SpringBoot-Vue前后端分离

SpringBoot-Vue 前后端分离开发

安装Vue.js

  • vue安装最新版本 npm install -g @vue/cli 或 yarn global add @vue/cli
  • Win + R 输入vue -V 或者vue -version , 出现版本号即Vue可安装完成。
  • 继续输入vue ui(vue要3.0以上版本才行) ,启动项目,会自动跳转http://localhost:8080/页面。
  • 然后可创建项目vue项目进行开发啦。

IEDA导入前端工程

IDEA启动项目

  • 打开Terminal 输入npm run serve即可。

编写代码

vuetest结构

新建Book.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<template>
<div>
<table>
<tr>
<td>编号</td>
<td>图书名称</td>
<td>作者</td>
</tr>
<tr v-for="item in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.author}}</td>
</tr>
</table>
{{msg}}
</div>
</template>
<script>
export default {
name:"Book",
data(){
return{
msg:"Hello Vue",
books:[{
id: 1 ,
name: '千羽',
author: '千羽的编程之路'
},{
id: 2 ,
name: '千寻',
author: 'SpringBoot-Vue 前后端分离开发'
},{
id: 3 ,
name: '小明',
author: 'SpringBoot入门到精通'
}
]
}
},
created() {
const _this = this
axios.get('http://localhost:8181/book/findAll').then(function(resp){
_this.books = resp.data
})
}
}

</script><style scoped=""></style>

配置路由
配置路由

在terminal添加axios库:vue add axios

新建数据库

1
2
create databases library;
use databases;

导入数据

创建SpringBootTest工程

添加lombok,Spring Web,SpringData Jpa,MySQL Driver

配置yml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
datasource:
url: jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
server:
port: 8181

创建实体类Book.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.southwind.springboottest.entity;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity //类名与表名绑定
@Data
public class Book { //编写实体类
@Id
private Integer id;
private String name;
private String author;

}

创建BookHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.southwind.springboottest.controller;

import com.southwind.springboottest.entity.Book;
import com.southwind.springboottest.reporesity.BookReposity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.Mapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/book")
public class BookHandler {

@Autowired
private BookReposity bookReposity;

@GetMapping("/findAll")
public List<Book> findAll(){
return bookReposity.findAll();
}

}

解决跨域问题CrosConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.southwind.springboottest.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CrosConfig implements WebMvcConfigurer {

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}


创建BookReposity接口

1
2
3
4
5
6
7
8
9
10
package com.southwind.springboottest.reporesity;

import com.southwind.springboottest.entity.Book;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BookReposity extends JpaRepository<Book,Integer>{


}

debug测试

启动SpringboottestApplication

实现前后端数据交互啦!

实现技术
Spring Boot + Vue
使⽤ Spring Boot 进⾏后端应⽤开发,使⽤ Vue 进⾏前端应⽤开发。

Vue + Element UI

先了解了一下Element(饿了么) UI,Element-Ul是饿了么前端团队推出的一款基于Vue.js 2.0 的桌面端UI框架。小编感觉它太强大了,主要你会查找和Ctrl + C,会前端开发基本上问题不大。

Vue 集成 Element UI

前提是要安装好Element插件,

Element UI 后台管理系统主要的标签:

  • el-container:构建整个⻚⾯框架。
  • el-aside:构建左侧菜单。
  • el-menu:左侧菜单内容,常⽤属性:
    • :default-openeds:默认展开的菜单,通过菜单的 index 值来关联。
    • :default-active:默认选中的菜单,通过菜单的 index 值来关联。
  • el-submenu:可展开的菜单,常⽤属性:
  • index:菜单的下标,⽂本类型,不能是数值类型。
  • template:对应 el-submenu 的菜单名。
  • i:设置菜单图标,通过 class 属性实则。
    • el-icon-messae
    • el-icon-menu
    • el-icon-setting
  • el-menu-item:菜单的⼦节点,不可再展开,常⽤属性:
  • index:菜单的下标,⽂本类型,不能是数值类型。

Vue router 来动态构建左侧菜单

  • 导航1

    • ⻚⾯1
    • ⻚⾯2
  • 导航2

    • ⻚⾯3
    • ⻚⾯4
  1. 标签添加 router 属性。
  2. 在⻚⾯中添加 标签,它是⼀个容器,动态渲染你选择的 router。
  3. 标签的 index 值就是要跳转的 router。

Element UI 表单数据校验

定义 rules 对象,在 rules 对象中设置表单各个选项的校验规则

  • required: true, 是否为必填项
  • message: ‘error’, 提示信息
  • trigger: ‘blur’,触发事件

vuetest结构层次

AddBook.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<template>
<el-form style="width: 60%" :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">

<el-form-item label="图书名称" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>

<el-form-item label="作者" prop="author">
<el-input v-model="ruleForm.author"></el-input>
</el-form-item>


<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
<el-button @click="test()">test</el-button>
</el-form-item>

</el-form>
</template>

<script>
export default {
data() {
return {
ruleForm: {
name: '',
author: ''
},
rules: {
name: [
{ required: true, message: '图书名称不能为空', trigger: 'blur' }
],
author:[
{ required: true, message: '作者不能为空', trigger: 'blur' }
]
}
};
},
methods: {
test(){
console.log(this.ruleForm)
},
submitForm(formName) {
const _this = this
this.$refs[formName].validate((valid) => {
if (valid) {
axios.post('http://localhost:8181/book/save',this.ruleForm).then(function(resp){
if(resp.data == 'success'){
_this.$alert('《'+_this.ruleForm.name+'》添加成功!', '消息', {
confirmButtonText: '确定',
callback: action => {
_this.$router.push('/BookManage')
}
})
}
})
} else {
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>

BookManage.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<template>
<div>
<el-table
:data="tableData"
border
style="width: 70%">
<el-table-column
fixed
prop="id"
label="编号"
width="150">
</el-table-column>
<el-table-column
prop="name"
label="图书名"
width="120">
</el-table-column>
<el-table-column
prop="author"
label="作者"
width="120">
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="100">
<template slot-scope="scope">
<el-button @click="edit(scope.row)" type="text" size="small">修改</el-button>
<el-button @click="deleteBook(scope.row)" type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>

<el-pagination
background
layout="prev, pager, next"
:page-size="pageSize"
:total="total"
@current-change="page">
</el-pagination>
</div>
</template>

<script>
export default {
methods: {
deleteBook(row){
const _this = this
axios.delete('http://localhost:8181/book/deleteById/'+row.id).then(function(resp){
_this.$alert('《'+row.name+'》删除成功!', '消息', {
confirmButtonText: '确定',
callback: action => {
// 动态刷新
window.location.reload()
}
})
})
},
edit(row) {
this.$router.push({
path: '/update',
query:{
id:row.id
}
})
},
page(currentPage){
const _this = this
axios.get('http://localhost:8181/book/findAll/'+currentPage+'/6').then(function(resp){
console.log(resp)
_this.tableData = resp.data.content
_this.pageSize = resp.data.size
_this.total = resp.data.totalElements
})
}
},

data() {
return {
pageSize:'1',
total:'11',
tableData: null
}
},

created() {
const _this = this
axios.get('http://localhost:8181/book/findAll/1/6').then(function(resp){
console.log(resp)
_this.tableData = resp.data.content
_this.pageSize = resp.data.size
_this.total = resp.data.totalElements
})
}
}
</script>

BookUpdate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<template>
<el-form style="width: 60%" :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">

<el-form-item label="图书编号">
<el-input v-model="ruleForm.id" readOnly></el-input>
</el-form-item>

<el-form-item label="图书名称" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>

<el-form-item label="作者" prop="author">
<el-input v-model="ruleForm.author"></el-input>
</el-form-item>

<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">修改</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>

</el-form>
</template>

<script>
export default {
data() {
return {
ruleForm: {
id: '',
name: '',
author: ''
},
rules: {
name: [
{ required: true, message: '图书名称不能为空', trigger: 'blur' }
],
author:[
{ required: true, message: '作者不能为空', trigger: 'blur' }
]
}
};
},
methods: {
submitForm(formName) {
const _this = this
this.$refs[formName].validate((valid) => {
if (valid) {
axios.put('http://localhost:8181/book/update',this.ruleForm).then(function(resp){
if(resp.data == 'success'){
_this.$alert('《'+_this.ruleForm.name+'》修改成功!', '消息', {
confirmButtonText: '确定',
callback: action => {
_this.$router.push('/BookManage')
}
})
}
})
} else {
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
},
created() {

const _this = this
axios.get('http://localhost:8181/book/findById/'+this.$route.query.id).then(function(resp){
_this.ruleForm = resp.data
})
}
}
</script>

配置路由/router/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import Vue from 'vue'
import VueRouter from 'vue-router'
import BookManage from '../views/BookManage'
import AddBook from '../views/AddBook'
import Index from '../views/Index'
import BookUpdate from '../views/BookUpdate'

Vue.use(VueRouter)

const routes = [
{
path:"/",
name:"图书管理",
component:Index,
show:true,
redirect:"/BookManage",
children:[
{
path:"/BookManage",
name:"查询图书",
component:BookManage
},
{
path:"/AddBook",
name:"添加图书",
component:AddBook
}
]
},
{
path:'/update',
component:BookUpdate,
show:false
}
]

const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})

export default router

后端springbootTest代码实现BookHandler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.southwind.springboottest.controller;

import com.southwind.springboottest.entity.Book;
import com.southwind.springboottest.reporesity.BookReposity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/book")
public class BookHandler {

@Autowired
private BookReposity bookReposity;

@GetMapping("/findAll/{page}/{size}")
public Page<Book> findAll(@PathVariable("page") Integer page, @PathVariable("size") Integer size){
Pageable pageable = PageRequest.of(page-1,size);
return bookReposity.findAll(pageable);
}

@PostMapping("/save")
public String save(@RequestBody Book book ){

Book result = bookReposity.save(book);
if(result != null){
return "success";
}else {
return "error";
}

}
@GetMapping("/findById/{id}")
public Book findById(@PathVariable("id") Integer id){
return bookReposity.findById(id).get();
}

@PutMapping("/update")
public String update(@RequestBody Book book ) {
Book result = bookReposity.save(book);
if (result != null) {
return "success";
} else {
return "error";
}
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id){
bookReposity.deleteById(id);

}

}

当然,在测试每一个功能时,建议在BookReposity接口上创建一个测试类BookReposityTest,测试看看是否成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.southwind.springboottest.reporesity;

import com.southwind.springboottest.entity.Book;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class BookReposityTest {

@Autowired
private BookReposity bookReposity;

//测试查找所有数据
@Test
void findAll(){
System.out.println(bookReposity.findAll());
}

//添加测试
@Test
void save(){
Book book = new Book();
book.setName("张三");
book.setAuthor("李四");
Book save = bookReposity.save(book);
System.out.println(save);

}

@Test
void findById(){
Book book = bookReposity.findById(1).get();
System.out.println(book);

}

//测试修改
@Test
void update(){
Book book = new Book();
book.setId(12);
book.setName("测试测试");
Book save = bookReposity.save(book);
System.out.println(save);
}
//测试删除
@Test
void delete(){
bookReposity.deleteById(12);
}
}

功能展示


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1210331079@qq.com

💰

Title:SpringBoot-Vue前后端分离

Count:3k

Author:千 羽

Created At:2020-05-16, 21:25:17

Updated At:2020-08-23, 13:06:32

Url:https://nateshao.github.io/2020/05/16/SpringBoot-Vue%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB/

Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.

×

donation.headline

// 底部音乐
//右上角Github图标