前后端实现增删改查

紧接着上一次的博客,我们接下来实现增加、删除、批量删除、分页查询、模糊查询、编辑功能,页面样式效果如下:

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,函数如下:
javascript 复制代码
handlerCurrentChange(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);
    }
相关推荐
一个处女座的程序猿O(∩_∩)O3 分钟前
完成第一个 Vue3.2 项目后,这是我的技术总结
前端·vue.js
逆旅行天涯10 分钟前
【Threejs】从零开始(六)--GUI调试开发3D效果
前端·javascript·3d
长风清留扬1 小时前
小程序毕业设计-音乐播放器+源码(可播放)下载即用
javascript·小程序·毕业设计·课程设计·毕设·音乐播放器
m0_748247801 小时前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
ZJ_.2 小时前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营2 小时前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood2 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
joan_852 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui
还是大剑师兰特3 小时前
什么是尾调用,使用尾调用有什么好处?
javascript·大剑师·尾调用
Watermelo6173 小时前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript