Vue-admin-template+SpringBoot+MyBatisPlus实现图书的增删改查功能(前后端分离)
由于最近学完Vue、MyBatisPlus、Vue-admin-template模板的使用,为了方便在后面的开发过程中更好的复习。特此在这里写一篇博客来记录,也方便编程学习者来借鉴。由于是初学,可能写的不怎么好,还望大神指导指导。
一、所需资料官网
[1] Vue-element-admin官网
[2] Vue.js官网
[3] MyBatisPlus官网
二、开发工具
IntelliJ IDEA Ultimate 2021.1.3
SpringBoot 2.6.2
MyBatisPlus 3.5.1
Vue-admin-template 4.4.0
apache-maven 3.8.3
MySQL 8.0.27
JDK 1.8.0_311
三、下载并安装Vue-Admin-Template模板
1、下载运行
1、克隆这个项目
(1)从github上克隆:
git clone https://github.com/PanJiaChen/vue-admin-template.git
(2)从gitee上克隆:
git clone https://gitee.com/panjiachen/vue-admin-template.git
2、进入项目目录
cd vue-admin-template
3、安装依赖
npm install
4、安装淘宝镜像
npm install --registry=https://registry.npm.taobao.org
5、启动服务
npm run dev
浏览器访问:http://localhost:9528
2、启动成功后的效果图
3、项目结构的介绍
4、配合后端使用改造前端项目
4.1、注释掉main.js中的mock的引用
4.2、注释掉vue.config.js中关于lint的语法检查
4.3、关注开发环境配置文件中关于请求前缀部分
4.4、在vue.config.js中添加路由表配置解决跨域问题
4.5、注释掉vue.config.js中关于mock的配置项,不然添加或修改时出现超时问题
proxy: {
'/dev-api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/dev-api': ''
}
}
}
4.6、查看登录成功后的数据返回格式以及查看用户信息时返回的格式
4.7、修改router/index.js文件(根据自己需要)
4.8、在views目录下新建book/index.vue文件
<template>
<div class="app-container">
<el-button type="success" icon="el-icon-plus" @click="handleEdit">添加</el-button>
<el-table
:data="books"
:header-cell-style="{'text-align':'center'}"
:cell-style="{'text-align':'center'}"
style="width: 100%"
>
<el-table-column
label="书籍编号"
prop="bookId"
width="280"
/>
<el-table-column
label="书籍名称"
prop="bookName"
width="280"
/>
<el-table-column
label="书籍数量"
prop="bookCounts"
width="280"
/>
<el-table-column
label="书籍描述"
prop="detail"
width="280"
/>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleEdit(scope.row)"
>编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.row)"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:page-size="pageSize"
:current-page="page"
:page-sizes="[5, 10, 15, 20]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<el-dialog :title="title" :visible.sync="dialogFormVisible">
<el-form :model="book">
<el-form-item label="书籍名称" :label-width="formLabelWidth">
<el-input v-model="book.bookName" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="书籍数量" :label-width="formLabelWidth">
<el-input v-model="book.bookCounts" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="书籍描述" :label-width="formLabelWidth">
<el-input v-model="book.detail" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getList, edit, del } from '@/api/book'
export default {
data() {
return {
books: [],
book: {},
page: 1,
pageSize: 5,
total: 20,
dialogFormVisible: false,
title: '添加书籍',
formLabelWidth: '120'
}
},
created() {
this.findAll()
},
methods: {
// 分页查询全部书籍信息
findAll() {
getList(this.page, this.pageSize).then(res => {
this.books = res.data.records
this.total = res.data.total
})
},
// 编辑操作
handleEdit(row) {
// 判断是否是添加或修改
if (row.bookId) {
this.title = '修改书籍'
this.book = row
} else {
this.title = '添加书籍'
this.book = {}
}
// 打开对话框
this.dialogFormVisible = true
},
// 保存数据
async save() {
// 设置添加url
let url = '/book/addBook'
// 判断是否是修改
if (this.book.bookId) {
url = '/book/editBook'
}
// 保存到数据库中
const data = await edit(url, JSON.stringify(this.book))
console.log('编辑状态:' + data.code)
if (data.code === 20000) {
// 关闭对话框
this.dialogFormVisible = false
// 刷新数据
this.findAll()
} else {
this.$message.error({
showClose: true,
message: data.message
})
}
},
// 删除操作
handleDelete(row) {
console.log(row)
this.$confirm(`您真的要删除书籍${row.bookName}吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
const data = await del(row.bookId)
if (data.code === 20000) {
this.$message({
type: 'success',
message: '删除成功!',
duration: 1000,
onClose: () => {
// 页数跳转到第一页
this.handleCurrentChange(1)
// 总条数-1
this.total--
}
})
} else {
this.$message({
type: 'info',
message: '删除失败!'
})
}
})
},
// 处理页数的改变
handleCurrentChange(page) {
this.page = page
getList(page, this.pageSize).then(res => {
this.books = res.data.records
})
console.log(`当前${page}页`)
},
// 处理每页显示条数的改变
handleSizeChange(pageSize) {
this.pageSize = pageSize
console.log(`当前${pageSize}页`)
// 重新发请求查询数据
this.handleCurrentChange(this.page)
}
}
}
</script>
<style>
.el-pagination {
margin-top: 20px;
float: right;
}
</style>
4.9、在api目录下新建book.js
import request from '@/utils/request'
export function getList(current, pageSize) {
return request({
url: `/book/list/${current}/${pageSize}`,
method: 'get'
})
}
export function edit(url, book) {
return request({
url: url,
method: 'post',
data: book,
headers: {
'Content-type': 'application/json'
}
})
}
export function del(bookId) {
return request({
url: `/book/delBook/${bookId}`,
method: 'get'
})
}
四、使用SpringBoot搭建后台项目
1、后台项目结构
2、加载依赖
<dependencies>
<!--Web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MyBatisPlus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!--MySQL依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--Lombok依赖-->
<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>
</dependency>
</dependencies>
3、创建数据库
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for books
-- ----------------------------
DROP TABLE IF EXISTS `books`;
CREATE TABLE `books` (
`bookId` int(0) NOT NULL AUTO_INCREMENT COMMENT '书id',
`bookName` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '书名',
`bookCounts` int(0) NOT NULL COMMENT '数量',
`detail` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '描述',
PRIMARY KEY (`bookId`) USING BTREE,
INDEX `bookID`(`bookId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of books
-- ----------------------------
INSERT INTO `books` VALUES (1, 'Java', 1, '从入门到放弃');
INSERT INTO `books` VALUES (2, 'MySQL', 10, '从删库到跑路');
INSERT INTO `books` VALUES (3, 'Linux', 5, '从进门到进牢');
SET FOREIGN_KEY_CHECKS = 1;
4、修改项目resources目录下application.yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/ssmbuild?characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
mybatis-plus:
configuration:
map-underscore-to-camel-case: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
server:
port: 8080
5、编写pojo实体类
package com.example.pojo;
import lombok.Data;
@Data
public class User {
private String username;
private String password;
}
package com.example.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
public class Books {
@TableId(type = IdType.AUTO)
private Integer bookId;
private String bookName;
private Integer bookCounts;
private String detail;
}
6、编写dao持久层
package com.example.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.pojo.Books;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BooksMapper extends BaseMapper<Books> {
}
7、编写service服务层
package com.example.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.dao.BooksMapper;
import com.example.pojo.Books;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BooksService {
@Autowired
private BooksMapper booksMapper;
public Page<Books> findAll(Integer current,Integer size){
Page<Books> page = new Page<>(current,size);
return booksMapper.selectPage(page,null);
}
public int addBooks(Books books){
return booksMapper.insert(books);
}
public int updateBooksById(Books books){
return booksMapper.updateById(books);
}
public int deleteBooksById(Integer bookId){
return booksMapper.deleteById(bookId);
}
}
8、编写controller控制层
package com.example.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.pojo.Books;
import com.example.service.BooksService;
import com.example.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/book")
public class BooksController {
@Autowired
private BooksService booksService;
@GetMapping("/list/{current}/{pageSize}")
public R getAllBooks(@PathVariable int current, @PathVariable int pageSize) {
Page<Books> booksList = booksService.findAll(current, pageSize);
return new R(20000, "查询成功!", booksList);
}
@PostMapping("/addBook")
public R addBooks(@RequestBody Books books) {
int i = booksService.addBooks(books);
return i == 1 ? new R().renderSuccess("添加成功") : new R().renderError("添加失败");
}
@PostMapping("/editBook")
public R editBooks(@RequestBody Books books) {
int i = booksService.updateBooksById(books);
return i == 1 ? new R().renderSuccess("修改成功") : new R().renderError("修改失败");
}
@GetMapping("/delBook/{bookId}")
public R delBooks(@PathVariable Integer bookId) {
int i = booksService.deleteBooksById(bookId);
return i == 1 ? new R().renderSuccess("删除成功") : new R().renderError("删除失败");
}
}
package com.example.controller;
import com.example.pojo.User;
import com.example.utils.R;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
@RestController
public class UserController {
@PostMapping("/user/login")
public R userLogin(@RequestBody User user) {
HashMap<String, Object> map = new HashMap<>();
if (user.getUsername().equals("admin")&&user.getPassword().equals("111111")){
map.put("token", "admin-token");
}else {
map.put("token", "editor-token");
}
return new R(20000,"登录成功", map);
}
@GetMapping("/user/info")
public R userInfo(@RequestParam("token") String token) {
HashMap<String, Object> map = new HashMap<>();
if (token.equals("admin-token")){
map.put("roles", "admin");
map.put("name", "Super Admin");
}else {
map.put("roles", "editor");
map.put("name", "Normal Editor");
}
map.put("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
return new R(20000,"查看用户信息", map);
}
@PostMapping("/user/logout")
public R userLogout(){
return new R(20000,"退出成功!");
}
}
9、编写MyBatisPlusConfig配置类
package com.example.utils;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//添加分页插件
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}
10、编写json格式结果返回类
package com.example.utils;
import lombok.Data;
@Data
public class R {
private Integer code;
private String message;
private Object data;
public R(){}
public R(Integer code,String message){
this.code=code;
this.message=message;
}
public R(Integer code,Object data){
this.code=code;
this.data=data;
}
public R(Integer code,String message,Object data){
this.code=code;
this.message=message;
this.data=data;
}
public R renderSuccess(String message){
return new R(20000,message);
}
public R renderError(String message){
return new R(20001,message);
}
}