目录
![](https://img2020.cnblogs.com/blog/1719811/202009/1719811-20200914091605917-1368703362.png)
![](https://img2020.cnblogs.com/blog/1719811/202009/1719811-20200914092002614-256485043.png)
![](https://img2020.cnblogs.com/blog/1719811/202009/1719811-20200914092151352-692103869.png)
![](https://img2020.cnblogs.com/blog/1719811/202009/1719811-20200914092203550-1058246805.png)
- 前端:
- Vue.js
- Element
- Axios
- 后端:
- Spring Boot
- Mysql
- JPA
- Lombok
- 其他功能:
- 模态框
- Pageable分页
![](https://img2020.cnblogs.com/blog/1719811/202009/1719811-20200914120741179-1930780457.png)
![](https://img2020.cnblogs.com/blog/1719811/202009/1719811-20200914120702890-447756835.png)
![](https://img2020.cnblogs.com/blog/1719811/202009/1719811-20200914120944443-1354276747.png)
![](https://img2020.cnblogs.com/blog/1719811/202009/1719811-20200914121012016-836424455.png)
<template>
<el-container style="height: 100%; border: 1px solid #eee">
<!-- 左边部分 菜单 -->
<el-aside width="200px" style="background-color: rgb(238, 241, 246)">
<el-menu router :default-openeds="['0','1']">
<!-- 通过for循环遍历路由设置菜单 -->
<el-submenu
v-for="(item,index) in $router.options.routes"
:key="item.name"
:index="index+''"
>
<!-- 菜单标题 -->
<template slot="title">
<i class="el-icon-setting"></i>
{{item.name}}
</template>
<!-- 子菜单 :class 如果当前路由路径与子菜单路由路径相等,则激活该样式-->
<el-menu-item
v-for="(item1) in item.children"
:key="item1.name"
:index="item1.path"
:class="$route.path==item1.path?'is-active':''"
>{{item1.name}}</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<!-- main部分 路由 -->
<el-container>
<el-main>
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
name: "Index",
data() {
return {
msg: "Welcome to Your Vue.js App",
};
},
};
</script>
<style scoped>
</style>
<template>
<div>
<!-- table表格 绑定数据tableData-->
<el-table :data="tableData" border style="width: 100%">
<el-table-column fixed prop="id" label="id"></el-table-column>
<el-table-column prop="name" label="书名"></el-table-column>
<el-table-column prop="author" label="作者"></el-table-column>
<el-table-column fixed="right" label="操作">
<template slot-scope="scope">
<el-button @click="OpenModifyBookDialog(scope.row)" type="text" size="small">修改</el-button>
<!-- 删除气泡确认框 -->
<el-popconfirm title="确定删除吗?" style="margin-left:10px;" @onConfirm="delBook(scope.row)">
<el-button type="text" slot="reference">删除</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!--
分页导航 tatal是从axios请求中获取出来的resp.data.totalElements
@current-change="page",绑定跳页按键事件,当我们点了其他页码之后,就会触发这个事件,去请求数据-->
<el-pagination
background
layout="prev, pager, next"
:page-size="pageSize"
:total="total"
@current-change="page"></el-pagination>
<!-- 修改图书资料的模态框 -->
<el-dialog
:title="ModifyBookDialogTitle"
:visible.sync="dialogModifyBookVisible"
@close="closeDialogModifyBookVisible">
<el-form :model="modifyForm" :rules="rules" ref="modifyForm">
<el-form-item label="图书编号">
<el-input v-model="modifyForm.id" readonly></el-input>
</el-form-item>
<el-form-item label="图书名称" prop="name">
<el-input v-model="modifyForm.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="作者" prop="author">
<el-input v-model="modifyForm.author"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogModifyBookVisible = false">取 消</el-button>
<el-button type="primary" @click="saveModifyForm('modifyForm')">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
inject: ["reload"],
data() {
return {
total: null, //图书条目的总数,由请求返回的resp.data.totalElements获得
pageSize: null, //一页的大小,由分页请求的链接返回的resp.data.size获得
tableData: null,//图书表格数据
ModifyBookDialogTitle: null, //修改图书信息模态框标题
modifyForm: { //修改图书信息模态框数据
name: "",
author: "",
},
dialogModifyBookVisible: null, //模态框视图是否打开
//修改图书模态框信息表单验证规则
rules: {
name: [
{ required: true, message: "图书名称不能为空!", trigger: "blur" },
{
min: 2,
max: 10,
message: "长度在 2 到 10 个字符",
trigger: "blur",
},
],
author: [
{ required: true, message: "作者名称不能为空!", trigger: "blur" },
{ min: 2, max: 5, message: "长度在 2 到 5 个字符", trigger: "blur" },
],
},
};
},
created() {
const _this = this; //这里要定义一个_this指向该组件对象
//生命周期开始时,请求分页数据,参数/1/7的意思是查找第一页 7条数据
this.$axios
.get("http://localhost:8082/book/findAll/1/7")
.then(function (resp) {
_this.tableData = resp.data.content; //图书表数据
_this.total = resp.data.totalElements; //总数
_this.pageSize = resp.data.size; //页面大小
});
},
methods: {
// 页码点击事件,获取要去的页码currentPage,重新请求数据,
page(currentPage) {
const _this = this; //这里要定义一个_this指向该组件对象
this.$axios
.get("http://localhost:8082/book/findAll/" + currentPage + "/7")
.then(function (resp) {
_this.tableData = resp.data.content;
_this.total = resp.data.totalElements; //总数
_this.pageSize = resp.data.size; //一页的数据大小
});
},
//打开修改图书信息模态框
OpenModifyBookDialog(row) {
const _this = this;
this.dialogModifyBookVisible = true;
this.ModifyBookDialogTitle = "修改图书信息";
this.modifyForm.id = row.id;
this.$axios
.get("http://localhost:8082/book/findById/" + row.id)
.then(function (resp) {
_this.modifyForm.name = resp.data.name;
_this.modifyForm.author = resp.data.author;
});
},
//提交模态框的表单数据
saveModifyForm(formName) {
const _this = this;
this.$refs[formName].validate((valid) => {
//如果表单验证通过,则提交请求
if (valid) {
this.$axios
.put("http://localhost:8082/book/updateBook/", this.modifyForm)
.then(function (resp) {
if (resp.data == "success update") {
_this.$message({
message: "修改成功!",
type: "success",
});
_this.reload(); //数据修改成功后,自动刷新页面
} else if (resp.data == "false update") {
alert("添加失败!");
}
});
this.dialogModifyBookVisible = false;
} else {
console.log("error submit!!");
return false;
}
});
},
//关闭或取消模态框,清空值
closeDialogModifyBookVisible() {
this.$refs.modifyForm.resetFields(); //element封装的方法,清空模态框的值
this.ModifyBookDialogTitle = ""; //初始化title的值
this.dialogModifyBookVisible = false;
this.modifyForm = {
//初始化modifyForm中的值
name: "",
author: "",
};
},
//确定删除图书
delBook(row) {
const _this = this;
console.log(row.id);
this.$axios
.delete("http://localhost:8082/book/deleteById/" + row.id)
.then(function (resp) {
if (resp.status == "200") {
_this.$message({
message: "删除成功!",
type: "success",
});
}
_this.reload(); //数据修改成功后,自动刷新页面
});
},
},
};
</script>
<template>
<div>
<el-form
:model="ruleForm"
:rules="rules"
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
>
<el-form-item label="图书名称" prop="name">
<el-input style="width:20%" v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="作者" prop="author">
<el-input style="width:20%" 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>
</div>
</template>
<script>
export default {
data() {
return {
ruleForm: {
name: "",
author: "",
},
//表单验证规则
rules: {
name: [
{ required: true, message: "图书名称不能为空!", trigger: "blur" },
{
min: 2,
max: 10,
message: "长度在 2 到 10 个字符",
trigger: "blur",
},
],
author: [
{ required: true, message: "作者名称不能为空!", trigger: "blur" },
{ min: 2, max: 5, message: "长度在 2 到 5 个字符", trigger: "blur" },
],
},
};
},
methods: {
//提交表单
submitForm(formName) {
const _this = this;
this.$refs[formName].validate((valid) => {
//根据rules规则进行表单验证,如果验证成功,则提交请求
if (valid) {
this.$axios
.post("http://localhost:8082/book/saveBook/", this.ruleForm) //提交表单数据时只需要在post后面参数添加上就可以了
.then(function (resp) {
if (resp.data == "success save") {
_this.$message({
message: "添加成功!",
type: "success",
});
_this.$router.push("/PageOne"); //路由跳转
} else if (resp.data == "false save") {
alert("添加失败!");
}
});
} else {
console.log("error submit!!");
return false;
}
});
},
//重置表单
resetForm(formName) {
this.$refs[formName].resetFields();
},
},
};
</script>
import Vue from 'vue'
import Router from 'vue-router'
import PageOne from '@/components/PageOne'
import PageTwo from '@/components/PageTwo'
import Index from '@/components/Index'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: '图书管理',
component: Index,
redirect:"/PageOne",
show: true,
children:[
{
path: '/PageOne',
name: '查询图书',
component: PageOne
},
{
path: '/PageTwo',
name: '添加图书',
component: PageTwo
},
]
},
]
})
- App.vue(通过provide和inject实现了页面刷新的功能)
<template>
<div id="app">
<router-view v-if="isRouterAlive" />
</div>
</template>
<script>
export default {
name: "App",
provide() {
//父组件中通过provide来提供变量,在子组件中通过inject来注入变量。
return {
reload: this.reload,
};
},
data() {
return {
isRouterAlive: true, //控制视图是否显示的变量
};
},
methods: {
reload() {
this.isRouterAlive = false; //先关闭,
this.$nextTick(function () {
this.isRouterAlive = true; //再打开
});
},
},
};
</script>
<style>
</style>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
spring:
datasource:
url: jdbc:mysql://localhost:3306/mytest?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
username: root
password: loveu0222
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
server:
port: 8082
- CrosConfig.java(Vue与SpirngBoot跨域请求配置)
package com.example.demo.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) {
//解决Vue与SpringBoot通信跨域问题
registry.addMapping("/**") //设置允许跨域的路径
.allowedOrigins("*") //设置允许跨域请求的域名
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS") //设置允许的方法
.allowCredentials(true) //这里:是否允许证书 不再默认开启
.maxAge(3600) //跨域允许时间
.allowedHeaders("*");
}
}
package com.example.demo.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
@Data
public class Book {
/*
@Data注解是lombok的注解,它会帮我们生成各种set、get方法
@id是主键注解
lombok插件要在idea里自己添加下载
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String author;
}
- BookRepository.java (JPA)
package com.example.demo.repository;
import com.example.demo.entity.Book;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BookRepository extends JpaRepository<Book,Integer> {}
- BookHander.java(Controller请求处理)
package com.example.demo.controller;
import com.example.demo.entity.Book;
import com.example.demo.repository.BookRepository;
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.data.domain.Sort;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/book")
public class BookHander {
//自动注入BookRepository,该接口继承了JpaRepository<Book,Integer>
@Autowired
private BookRepository bookRepository;
//查询所有
@GetMapping("/findAll")
public List<Book> findAll(){
//参数添加了排序规则,按照id排序
return bookRepository.findAll(Sort.by(Sort.Direction.DESC, "id"));
//return bookRepository.findAll();
}
//分页查询
@GetMapping("/findAll/{page}/{size}")
public Page<Book> findAll(@PathVariable("page") Integer page, @PathVariable("size") Integer size){
//第三个参数为排序规则,按照id排序
Pageable pageable = PageRequest.of(page-1,size,Sort.by(Sort.Direction.ASC, "id"));
return bookRepository.findAll(pageable);
}
//保存图书信息
@PostMapping("/saveBook")
public String save(@RequestBody Book book){
Book result = bookRepository.save(book);
if(result != null){
return "success save";
}else {
return "false save";
}
}
//通过id查找,请求时带id参数
@GetMapping("/findById/{id}")
public Book findById(@PathVariable("id") Integer id){
return bookRepository.findById(id).get();
}
//更新图书信息,调用save方法保存即可
@PutMapping("/updateBook")
public String updateBook(@RequestBody Book book){
Book result = bookRepository.save(book);
if(result != null){
return "success update";
}else {
return "false update";
}
}
//通过id删除,请求时带id参数,没有返回值,前端通过判断http状态码200判断删除是成功
@DeleteMapping("/deleteById/{id}")
public void DeleteById(@PathVariable("id") Integer id){
bookRepository.deleteById(id);
}
}