文章目录
1、后端方面
1.1 创建一个book表
1.2 创建实体类Book
在entity文件夹下创建实体类 Book,里面的内容与数据库对应。
package com.example.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
//表名记得改
@TableName("book")
// 自动进行生成getter setter 方法
@Data
public class Book {
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private BigDecimal price;
private String author;
//数据库中有下划线的,自动转换为驼峰写法
private Date createTime;
}
1.3 创建BookMapper类
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.Book;
public interface BookMapper extends BaseMapper<Book> {
}
1.4 创建 BookController类
package com.example.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.common.Result;
import com.example.entity.Book;
import com.example.mapper.BookMapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RequestMapping("/book")
@RestController
public class BookController {
// 引入mapper中的内容
@Resource
BookMapper bookMapper;
// 新增
@PostMapping
// Result<?>表示接收任何类型的数据
public Result<?> save(@RequestBody Book book){
// 插入数据库,在里面进行使用
bookMapper.insert(book);
return Result.success();
}
// 查询,使用的是分页查询
// 在进行网页查询的时候,需要必须传入三个参数pageNum pageSize search
@GetMapping
// 当前页pageNum 默认从 1 开始,,每页条数 pageSize 默认从 10 开始,,查询关键字 默认为空
public Result<?> findPage(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize,@RequestParam(defaultValue = "") String search){
// Page对象是由mybatisplus进行提供的
// Page<Object> page = new Page<>(pageNum,pageSize);
// 里面需要传入两个参数 一个是分页的对象,另一个wrappers对象,也是由mybatisplus提供的类
// eq含义是 = ,ne 含义是不等于, gt 是大于,like 模糊查询
// 根据用户昵称进行模糊搜索,Book::getName中间四个点的意思是直接进行访问Book的属性,
//当 Name 和search 类似的时候,就进行显示
/**
* 此时原先直接将Wrappers.<Book>lambdaQuery().like(Book::getNickName,search);写在 BookPage中,在进行查询数据库的时候,nickName为空的字段
* 是查询不到的,所以在like之前进行一下判断
* 使用的是 hutool工具,StrUtil.isNotBlank(search) 判断 search 不是空的时候执行,此时就能将 nickName为空的数据查询出来
*/
LambdaQueryWrapper<Book> wrapper = Wrappers.<Book>lambdaQuery();
if(StrUtil.isNotBlank(search)){
wrapper.like(Book::getName,search);
}
Page<Book> bookPage = bookMapper.selectPage(new Page<>(pageNum,pageSize),wrapper);
return Result.success(bookPage);
}
// 更新 使用PutMapping接口
@PutMapping
// Result<?>表示接收任何类型的数据
public Result<?> update(@RequestBody Book book){
// 根据id进行更新
bookMapper.updateById(book);
return Result.success();
}
// 删除 使用DeleteMapping接口
@DeleteMapping("/{id}")
// "/{id}" 占位符是方式 需要通过PathVariable注解进行获取参数
public Result<?> delete(@PathVariable Long id){
// 根据id进行删除
bookMapper.deleteById(id);
return Result.success();
}
}
2、前端方面
图书页面与用户管理页面几乎一致,稍微改动一下即可。
2.1 路由方面
首先将原来的Home.vue组件重命名为 User.vue组件,所以在路由中需要进行更新,同时在views文件夹下创建一个Book.vue组件,在文件夹router下的index.js修改如下:
const routes = [
// 默认路由页面,主体区域
{
// 头部加上侧边栏
path: '/',
name: 'Layout',
// 重定向功能,当访问 / 时,会自动的访问 /home 的页面
redirect: '/user',
component: Layout,
// 进行路由的嵌套 主体区域
children:[
{
path: '/user',
name: 'User',
component: ()=>import("@/views/User"),
},
{
path: '/person',
name: 'Person',
component: ()=>import("@/views/Person"),
},
{
path: '/book',
name: 'Book',
component: ()=>import("@/views/Book"),
}
]
},
{
path: '/login',
name: 'Login',
component: ()=>import("@/views/Login")
},
{
path: '/register',
name: 'Register',
component: ()=>import("@/views/Register")
},
]
2.2 页面设计
代码几乎没有改变,只是将发送请求的 /user改为 /book,以及与数据库内容相对应。
(1)html
<template>
<div style="flex: 1; padding: 10px">
<div class="content">
<!-- 功能区域———新增按钮 -->
<div style="margin: 10px 0" class="content_left">
<el-button type="primary" @click="add">增加</el-button>
<el-button type="primary">导入</el-button>
<el-button type="primary">导出</el-button>
</div>
<!-- 搜索区域 -->
<div style="margin: 10px 0" class="content_right">
<el-input
v-model="search"
placeholder="请输入关键字"
style="width: 200px"
clearable
/>
<el-button type="primary" style="margin-left: 5px" @click="load"
>查询</el-button
>
</div>
</div>
<el-table :data="tableData" border style="width: 100%" stripe>
<!-- 在进行数据显示的时候,给日期加上排序 -->
<el-table-column prop="id" label="ID" sortable />
<el-table-column prop="name" label="书名" />
<el-table-column prop="price" label="单价" />
<el-table-column prop="author" label="作者" />
<el-table-column prop="createTime" label="出版时间" />
<el-table-column fixed="right" label="操作" width="150">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.row)"
>编辑</el-button
>
<el-popconfirm
title="确认删除吗?"
@confirm="handleDelete(scope.row.id)"
>
<template #reference>
<el-button type="danger" size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<div style="margin: 10px 0">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[5, 10, 20]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<!-- 对话弹出框 -->
<el-dialog v-model="dialogVisible" title="提示" width="30%">
<!-- 定义一个表单,将要进行添加的信息显示在此位置 -->
<!-- <span>这是一段信息</span> -->
<!-- 此时需要进行绑定一个变量form -->
<el-form :model="form" label-width="120px">
<el-form-item label="书名" style="width: 80%">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="单价" style="width: 80%">
<el-input v-model="form.price" />
</el-form-item>
<el-form-item label="作者" style="width: 80%">
<el-input v-model="form.author" />
</el-form-item>
<el-form-item label="出版时间" style="width: 80%">
<el-date-picker
v-model="form.createTime"
type="date"
clearable
value-format="YYYY-MM-DD"
/>
</el-form-item>
<!-- <el-form-item label="出版时间" style="width: 80%">
<el-date-picker
v-model="form.createTime"
value-format="YYYY-MM-DD"
type="date"
clearable
></el-date-picker>
</el-form-item> -->
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<!-- 点击之后,将数据保存到后台,显示在页面上面 -->
<el-button type="primary" @click="save"> 确定 </el-button>
</span>
</template>
</el-dialog>
</div>
</div>
</template>
(2)js
<script>
import request from "@/utils/request";
export default {
name: "Book",
components: {},
data() {
return {
form: {},
dialogVisible: false,
currentPage: 1,
pageSize: 10,
total: 0,
search: "",
// 从后台进行获取数据
tableData: [],
flag: false,
};
},
created() {
this.load();
},
// updated() {
// this.load();
// },
methods: {
// 编辑操作
handleEdit(row) {
// console.log(row);
/** 此时可以拿到当前行的数据,然后将拿到的数据,传入到form中进行显示,为了避免v-model
* 的影响,当在表格中进行修改数据的时候,会导致form中的数据,当点击取消之后,会影响原先的数据
* 所以采用深拷贝的方式进行赋值
*/
this.form = JSON.parse(JSON.stringify(row));
// 打开弹窗
this.dialogVisible = true;
},
// 改变页面个数触发函数
handleSizeChange() {
this.load();
},
// 改变当前页码
handleCurrentChange() {
this.load();
},
// 当点击添加按钮之后,会显示一个弹窗
add() {
// 打开弹窗
this.dialogVisible = true;
// 同时要进行清空表单里面的内容
this.form = {};
},
//查询数据库中的数据,由于需要多次进行使用,所以先进行一下封装
// 此时的方法并没有进行调用,所以可以再页面一进行加载,就调用
load() {
// 在进行后端设计的时候,get代表查询
// get不能直接使用对象进行传参
request
.get("/book", {
params: {
// 需要进行传递参数
pageNum: this.currentPage,
pageSize: this.pageSize,
search: this.search,
},
})
.then((res) => {
// console.log(res);
this.tableData = res.data.records;
// 总条数
this.total = res.data.total;
});
},
// 将数据保存到后台
save() {
// 通过 form表单中id进行判断,如果有id,表示为更新,否则为新增
if (this.form.id) {
// 更新 put
request.put("/book", this.form).then((res) => {
// console.log(res);
if (res.code === "0") {
this.$message({
type: "success",
message: "更新成功",
});
} else {
this.$message({
type: "error",
message: "更新失败",
});
}
// 判断之后,需要进行弹窗的关闭和页面的重新渲染
this.load();
this.dialogVisible = false;
});
} else {
// 新增
// 此时路径不能使用/api/book,要不然会自动拼接
request.post("/book", this.form).then((res) => {
// console.log(res);
//成功之后的提示
if (res.code === "0") {
this.$message({
type: "success",
message: "新增成功",
});
} else {
this.$message({
type: "error",
message: "新增失败",
});
} // 判断之后,需要进行弹窗的关闭和页面的重新渲染
this.load();
this.dialogVisible = false;
});
}
},
// 删除当前数据
handleDelete(id) {
// console.log(id);
// 通过字符串拼接的方式,将id传给后端userMapper.deleteById(id);中进行删除
request.delete("/book/" + id).then((res) => {
if (res.code === "0") {
this.$message({
type: "success",
message: "删除成功",
});
} else {
this.$message({
type: "error",
message: "删除失败",
});
}
this.load(); //重新进行表格数据的渲染
});
},
},
};
</script>
页面效果如下:
2.3 在Aside组件中添加
<template>
<div>
<!-- el-menu 存在一个属性 router ,
功能是,当进行点击里面的内容时,会自动进行跳转
会根据index中的路由内容进行跳转
-->
<!-- default-active="user" 进行控制高亮 -->
<el-menu
default-active="user"
class="el-menu-vertical-demo"
router
style="width: 200px; min-height: calc(100vh - 50px)"
>
<el-sub-menu index="1">
<template #title>
<span>系统管理</span>
</template>
<el-menu-item index="user">用户管理</el-menu-item>
</el-sub-menu>
<!-- index 中的值与路由名称相对应 -->
<el-menu-item index="book">图书管理</el-menu-item>
<!-- <el-menu-item index="date" :route="{ path: '/' }">数据管理</el-menu-item> -->
</el-menu>
</div>
</template>
3 问题
3.1 出版时间的显示
(1)第一种方法:在entity文件夹下的Book类下进行代码修改,加个格式化注解,改完记得重启后台,具体代码如下:
//表名记得改
@TableName("book")
// 自动进行生成getter setter 方法
@Data
public class Book {
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private BigDecimal price;
private String author;
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
//数据库中有下划线的,自动准换为驼峰写法
private Date createTime;
}
(2)第二种方法: 在项目中统一进行设置。
在配置文件application.properties中,代码为
spring.jackson.date-format=yyyy-MM-dd
在配置文件application.yml中,代码为:
jackson:
date-format: yyyy-MM-dd
3.2 关于左侧高亮的显示问题
问题: 在用户管理页面进行**/book**,不能进行高亮的跳转
解决办法:
控制高亮是通过default-active属性进行控制的,所以让他动态的接收当前传来的数据,将获取到当前页面的路由赋值给当前的这个属性值,即可。具体代码如下:
<template>
<div>
<!-- el-menu 存在一个属性 router ,
功能是,当进行点击里面的内容时,会自动进行跳转
会根据index中的路由内容进行跳转
-->
<!-- default-active="user" 进行控制高亮 -->
<el-menu
:default-active="path"
class="el-menu-vertical-demo"
router
style="width: 200px; min-height: calc(100vh - 50px)"
>
<el-sub-menu index="1">
<template #title>
<span>系统管理</span>
</template>
<el-menu-item index="/user">用户管理</el-menu-item>
</el-sub-menu>
<!-- index 中的值与路由名称相对应 -->
<el-menu-item index="/book">图书管理</el-menu-item>
<!-- <el-menu-item index="date" :route="{ path: '/' }">数据管理</el-menu-item> -->
</el-menu>
</div>
</template>
<script>
export default {
name: "Aside",
data() {
return {
path: this.$route.path, //设置默认高亮的菜单
};
},
// created() {
// console.log(this.$route.path);
// // path: this.$route.path;
// },
};
</script>