紧接着上一次的博客,我们接下来实现增加、删除、批量删除、分页查询、模糊查询、编辑功能,页面样式效果如下:
1.分页查询和模糊查询
分页器样式代码如下:
html
<div class="block" style="margin: 20px 0px;">
<el-pagination
@current-change="handlerCurrentChange"
:current-page="pageNum"
:page-size="pageSize"
layout="total, prev, pager, next"
:total="total">
</el-pagination>
</div>
我们来分析下上面的代码:
@current-change="handlerCurrentChange" @current-change表示当前页码数改变之后就会触发绑定的函数handlerCurrentChange,函数如下:
javascripthandlerCurrentChange(pageNum){ this.pageNum = pageNum this.load() },
load()函数里封装的是分页查询的请求,如下,这个代码我们等会介绍
javascript//分页查询的请求 load(pageNum){ if (pageNum){ this.pageNum = pageNum } request.get('/user/selectByPage',{ params:{ pageNum:this.pageNum, pageSize:this.pageSize, name:this.name, } }).then(res =>{ this.users = res.data.records this.total = res.data.total }) },
:current-page="pageNum" 表示当前页码数,pageNum是我们自定义的变量,他的初始值我们给他赋成1,表示从第一页开始,至于为什么他会改变呢?答案在上面的那部分代码,通过handlerCurrentChange函数,我们获取到了前端页码数,然后再将这个值传给自定义的pageNum,然后再将这个pageNum与:current-page属性进行双向绑定,这样就能动态改变页码数
:page-size="pageSize" 表示每页显示的数据个数,pageSize是我们自定义的变量,我在这给他定义的是7,表示每页展示7条数据
layout="total, prev, pager, next"表示分页页面的布局
- total表示总页数
- prev表示上一页的按钮或者链接
- pager表示页码列表,用户可以根据列表来切换页面
- next表示下一页的按钮或者链接
:total="total表示总页数,total是我们自定义的变量,初始值赋为0,之后在分页请求的回调函数中将后端返回来的总数据量赋值给total
讲完了这些属性的作用之后,我们再来重点看下load()这个发送分页请求的函数,其实触发这个函数的入口有两个,第一个 是在create钩子函数中触发 ,当页面在加载的时候就发送分页查询的请求,第二个 是在进行模糊查询的时候,当用户点击查询按钮之后触发,一般在网页功能里,模糊查询和分页查询是不分开的,当进行完模糊查询之后,还得要进行分页查询才能将搜索的数据渲染出来,模糊查询样式如下:
html
<div>
<el-input placeholder="查询用户名" style="width: 250px" size="small" v-model="name"></el-input>
<el-button type="primary" size="small" style="margin-left: 10px" @click="load(1)">查 询</el-button>
<el-button type="danger" size="small" style="margin-left: 10px" @click="reset">重 置</el-button>
</div>
接下来着重讲一下load()函数
reset()函数,具有重置功能
接下来看下后端是怎么实现的,首先是引入mybatisplus的依赖
XML
<!--MybatisPlus-SpringBoot-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version>
</dependency>
然后引入官方提供的分页查询的插件
java
package com.kuang.common;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.kuang.mapper")
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}
改造mapper层和service层,这里就略了,可以看看往期的博客,里面有讲到,下面是分页查询的controller层
java
@GetMapping("/selectByPage")
public Result selectByPage(@RequestParam("pageNum") Integer pageNum,@RequestParam("pageSize") Integer pageSize,@RequestParam("name") String name){
//构造分页查询器
Page<User> pageInfo = new Page<>(pageNum,pageSize);
//构造条件查询器
QueryWrapper<User> wrapper = new QueryWrapper<>();
//添加一个排序条件
wrapper.orderByAsc("id");
//添加模糊查询
wrapper.like(StringUtils.isNotBlank(name),"name",name);
//执行查询
userService.page(pageInfo, wrapper);
//返回数据
return Result.success(pageInfo);
}
2.新增和编辑
为什么要把这两个功能放在一起讲呢?因为这两个功能,在前端中用的是同一个函数来向后端来传递数据,编辑按钮和新增按钮如下:
html
<template v-slot="scope">
<el-button @click="handleEdit(scope.row)" type="primary" size="small" plain >编辑</el-button>
</template>
html
<div style="margin: 10px 0px">
<el-button @click="handleAddPatient" size="small" type="primary" plain>新 增</el-button>
</div>
下面是这两个按钮绑定的click函数,这两个函数都是用来打开编辑和新增用户的弹窗
javascript
//编辑用户(打开弹窗)
handleEdit(row){
this.title = '编辑用户'
//将信息深拷贝到addPatientInfo中(用于回显数据)
this.addPatientInfo = JSON.parse(JSON.stringify(row))
//打开弹窗
this.addPatient = true
},
//新增用户(打开弹窗)
handleAddPatient(){
this.title = '新增用户'
//初始化,并设置性别为男
this.addPatientInfo = {gender:'男'}
//让表单显现
this.addPatient = true
},
弹窗样式如下:
html
<div>
<el-dialog :title="title" :visible.sync="addPatient" style="width: 100%">
<el-form :model="addPatientInfo" label-width="80px" ref="patientRef">
<el-form-item label="姓名" prop="name">
<el-input v-model="addPatientInfo.name" autocomplete="off" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="用户名" prop="username">
<el-input v-model="addPatientInfo.username" autocomplete="off" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="病房" prop="address">
<el-input v-model="addPatientInfo.address" autocomplete="off" placeholder="请输入病房"></el-input>
</el-form-item>
<el-form-item label="症状" prop="symptom">
<el-input type="textarea" v-model="addPatientInfo.symptom" autocomplete="off" placeholder="请输入症状"></el-input>
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="addPatientInfo.gender">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<!-- 09-->
<div slot="footer" class="dialog-footer">
<el-button @click="addPatient = false">取 消</el-button>
<el-button type="primary" @click="submitInfo">确 定</el-button>
</div>
</el-dialog>
</div>
:visible.sync="addPatient" 用来控制弹窗的可见性,addPatient是自定义的变量,一开始赋值为false表示这个弹窗不显示,当点击编辑或者新增按钮后,再将这个值改成true
autocomplete="off" 用来控制浏览器自动填充功能,off表示关闭这个功能
当点击弹窗里的确定按钮后,就会触发点击函数submitInfo,注意,编辑和新增功能用的弹窗是同一个,所以这个点击函数也是同一个,那么我们重点来看看,在同一个函数中是怎么区分这两个功能从而发送不同的请求的
javascript
//新增用户和编辑用户请求发送
submitInfo(){
//提交请求
this.$refs["patientRef"].validate((valid) => {
if (valid){
console.log(this.addPatientInfo)
this.request({
//有id就是更新,没有就是新增
method:this.addPatientInfo.id ? 'PUT' : 'POST',
url:this.addPatientInfo.id ? '/user/update' : '/user/add',
data: this.addPatientInfo,
}).then(res => {
if (res.code === '200'){
this.$message.success("保存成功")
//增加用户之后,再次调用分页查询,并将页数置为1
this.load(1)
//关闭弹窗
this.addPatient = false
}else {
this.$message.error(res.msg)
}
})
}
})
},
答案是用id来区分,当addPatientInfo中携带的有id,那么就是编辑功能,没有id就是新增功能,在点击编辑按钮后的点击函数会获取当前行对象的数据,并且赋值给了addPatientInfo,这样这个变量里就有了id,而点击新增按钮后,并没有这个过程
后端添加用户的controller接口如下
java
/**
* 新增用户
* @param user
* @return
*/
@PostMapping("/add")
public Result addUser(@RequestBody User user){
userService.save(user);
return Result.success();
}
在service实现类中重写了一下save方法,如下
重写sava方法里主要完成了如果有重名的情况,那么就要给前端返回信息,并且还要给用户添加一个初始密码
java
/**
* 重写save方法
* @param entity
* @return
*/
@Override
public boolean save(User entity) {
//先拿这个name去查数据库,如果有重名的话就抛异常
//添加条件查询器
QueryWrapper<User> wrapper = new QueryWrapper<>();
//添加条件(select * from patient where username = #{username})
wrapper.eq("username",entity.getUsername());
List<User> users = userMapper.selectList(wrapper);
if (!users.isEmpty()){
System.out.println(users);
throw new ServiceException("用户名重复");
}
//如果添加的用户password为空,则手动添加初始密码
if (StringUtils.isBlank(entity.getPassword())){
System.out.println("密码为空");
entity.setPassword("123456789");
}
return super.save(entity);
}