Mysql+MybatisPlus+Vue实现基础增删改查CRUD

数据库

设计数据库

设计几个字段,主键id自动增长且不可为空

create table if not exists `user`
(
    `id`       bigint(20) primary key auto_increment comment '主键id',
    `username` varchar(255)   not null comment '用户名',
    `sex`      char(1)        not null comment '性别',
    `phone`    varchar(22)    not null comment '手机号',
    `city`     varchar(255)   not null comment '所在城市',
    `position` varchar(255)   not null comment '职位',
    `salary`   decimal(18, 2) not null comment '工资:长度18,保留2位小数'
) engine InnoDB comment '用户表';

插入数据

随机插入几条数据

INSERT INTO `user` (`username`, `sex`, `phone`, `city`, `position`, `salary`) VALUES
('张三', '男', '13912345678', '北京', '软件工程师', 10000.00),
('李四', '女', '13723456789', '上海', '数据分析师', 12000.00),
('王五', '男', '15034567890', '广州', '产品经理', 15000.00),
('赵六', '女', '15145678901', '深圳', '前端工程师', 11000.00),
('刘七', '男', '15856789012', '成都', '测试工程师', 9000.00),
('陈八', '女', '13967890123', '重庆', 'UI设计师', 8000.00),
('朱九', '男', '13778901234', '武汉', '运维工程师', 10000.00),
('杨十', '女', '15089012345', '南京', '数据工程师', 13000.00),
('孙十一', '男', '15190123456', '杭州', '后端工程师', 12000.00),
('周十二', '女', '15801234567', '天津', '产品设计师', 11000.00);
select * from user;

查询成功则建表以及插入数据都成功
在这里插入图片描述

后端

实体类

根据数据库进行实体类的书写,功能要求可以后期再加

package com.wedu.modules.my.entity;

import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * <p>
 * 用户表
 * </p>
 *
 * @author xw
 * @since 2024-01-26
 */
@Data
@TableName("user")
@ApiModel(value="User对象", description="用户表")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键id")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @ApiModelProperty(value = "用户名")
    private String username;

    @ApiModelProperty(value = "性别")
    private String sex;

    @ApiModelProperty(value = "手机号")
    private String phone;

    @ApiModelProperty(value = "所在城市")
    private String city;

    @ApiModelProperty(value = "职位")
    private String position;

    @ApiModelProperty(value = "工资:长度18位,保留2位小数")
    private BigDecimal salary;


}

dao层

使用mybatisplus的框架方法
继承BaseMapper使用其中基础的功能,进行增删改查的撰写

/**
 * 系统用户 增删改查
 * 要给mapper层添加@Mapper和@Repository注解
 */
@Mapper
@Repository
public interface UserMapper extends BaseMapper<User> {
}

service层

在当前层下写一个接口继承IService模板提供的基础功能

/**
 * IUserService继承IService模板提供的基础功能和方法
 */
public interface IUserService extends IService<User> {

}


再写一个实现类去实现,由于现在接口中没有方法需要实现,所以实现类中无需实现

/**
 * MyUserServiceImpl实现了IService,提供了IService中基础功能的实现
 * 若MyUserServiceImpl无法满足业务需求,则可以使用自定的MyUserService定义方法,并在实现类中实现
 * service的impl实现类的注释要加实现的是哪个接口
 */
@Service("iUserService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}

controller层

新建一个UserController 继承AbstractController 中的方法,可以调用进行删除用户和后续修改根据id得到用户,@RequestMapping("/my/test")表示下面如果再加路径,比如@GetMapping("/select"),查询的路径则是/my/test/select,具有全局效应

@RestController
@RequestMapping("/my/test")
public class UserController extends AbstractController {

}

前端

test.vue

首先在modules文件夹下新建一个my文件夹,在my文件夹内新建一个userrr的vue文件,下载了帮助插件的小伙伴就可以打一个<v,选择第一行回车就能得到一个快速撰写vue界面的模板
在这里插入图片描述
出来的界面就像下面的代码片一样,可以在template标签中导入element 要显示的标签主键等,然后进行批量页面渲染,在script标签内写自己所创建的方法或者从外部的引入,style内放什么无需多讲,相信大家都学过css

<template>
  
</template>

<script>
export default {

}
</script>

<style>

</style>

此时我们数据库已经写好,后端和前端模板都已生成,下一步可以进行增删改查的书写

查询所有用户列表

我们需要查询数据库内所有数据,展示在前端页面中

1.新建表单

在template内新建表单,将表单设置为内联,使控件水平排列

<template>
  <div>
    <el-form :inline="true">
    
    </el-form>
  </div>
</template>

2.新建表单项

在新建的表单内新建表单项,在表单项内写一个查询按钮,触发点击即可查询事件

<template>
  <div>
    <el-form :inline="true">
      <!-- 按钮 -->
      <el-form-item>
        <!-- 查询按钮 -->
        <el-button @click="search()">查询</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

3.查询方法search

export default {}内的methods:{}中写一个查询方法search(),用这个方法获取当前数据列表getDataList

<script>
export default {
  methods: {
    // 查询
    search() {
      this.getDataList();
    },
  },
};
</script>

4.初始化数据集合

数据列表需要在data(){return{}}内进行初始化,当页的数据集合dataList初始化为空数组

<script>
export default {
  data() {
    return {
      dataList: [],
    };
  },
  methods: {
    // 查询
    search() {
      this.getDataList();
    },
  },
};
</script>

5.发送请求获取当前数据列表

获取当前数据列表的getDataList也是一个方法,在方法模块中和查询方法同级,获取数据列表需要向后端发送一个请求this.$http({}),使用ajax请求url地址,这里为了解决跨域问题用到了一个请求地址处理adornUrl(),写入请求路径/xx/xx/xx即可,请求方式根据restful url设计风格来,查询get,添加post,更新put,删除delete,这里查询到的参数还要进行get请求参数处理adornParams,根据后端传递的参数进行处理,有就写没有就忽略。发送请求之后要进行.then判断,如果data存在且data的code值恒等于(===)0则返回当页数据放入data初始化的集合内,不满足则还是为空。
需要code恒等于0是因为后端与前端交互是通过R返回数据,R构造器中默认code等于0的时候返回数据才会成功,恒等于代表着值相同且类型相同,避免了一些由于值相同但类型不同返回的错误数据

<script>
export default {
  data() {
    return {
      dataList: [],
    };
  },
  methods: {
    // 查询
    search() {
      this.getDataList();
    },
    // 获取数据列表
    getDataList() {
      this.$http({
        url: this.$http.adornUrl("/my/test/select"),
        method: "get",
        params: this.$http.adornParams({
        }),
      }).then(({ data }) => {
        if (data && data.code === 0) {
          this.dataList = data.dataList;
        } else {
          this.dataList = [];
        }
      });
    },
  },
};
</script>

6.activated生命周期钩子

在export default {}内可以使用生命周期钩子激活组件,这里就可以用activated生命周期钩子激活组件的时候执行getDataList方法获取数据列表,生命周期钩子与data、methods同级

<script>
export default {
  data() {
    return {
      dataList: [],
    };
  },
  activated() {
    this.getDataList();
  },
  methods: {
    // 查询
    search() {
      this.getDataList();
    },
    // 获取数据列表
    getDataList() {
      this.$http({
        url: this.$http.adornUrl("/my/test/select"),
        method: "get",
        params: this.$http.adornParams({
        }),
      }).then(({ data }) => {
        if (data && data.code === 0) {
          this.dataList = data.dataList;
        } else {
          this.dataList = [];
        }
      });
    },
  },
};
</script>

7.新建表格

和表单项同级,新建表格显示数据,表格双向绑定dataList,为每个元素生成一行数据,border边框,style属性设置宽度100%

<template>
  <div>
    <el-form :inline="true">
      <!-- 按钮 -->
      <el-form-item>
        <!-- 查询按钮 -->
        <el-button @click="search()">查询</el-button>
      </el-form-item>
    </el-form>
    <!-- 数据列表表格 -->
    <el-table :data="dataList" border style="width: 100%">
    </el-table>
  </div>
</template>

8.el-table-column

在新建的表格内写表格项el-table-column,内置属性prop写数据库对应列内容的字段名,header-align表头对齐方式和align对齐方式都可显示为居中center,label显示标题

<template>
  <div>
    <el-form :inline="true">
      <!-- 按钮 -->
      <el-form-item>
        <!-- 查询按钮 -->
        <el-button @click="search()">查询</el-button>
      </el-form-item>
    </el-form>
    <!-- 数据列表表格 -->
    <el-table :data="dataList" border style="width: 100%">
      <el-table-column
        prop="id"
        header-align="center"
        align="center"
        label="ID"
      ></el-table-column>
      <el-table-column
        prop="username"
        header-align="center"
        align="center"
        label="用户名"
      ></el-table-column>
      <el-table-column
        prop="sex"
        header-align="center"
        align="center"
        label="性别"
      ></el-table-column>
      <el-table-column
        prop="phone"
        header-align="center"
        align="center"
        label="手机号"
      ></el-table-column>
      <el-table-column
        prop="city"
        header-align="center"
        align="center"
        label="所在城市"
      ></el-table-column>
      <el-table-column
        prop="position"
        header-align="center"
        align="center"
        label="职位"
      ></el-table-column>
      <el-table-column
        prop="salary"
        header-align="center"
        align="center"
        label="工资"
      ></el-table-column>
    </el-table>
  </div>
</template>

9.在UserController内写查询方法

查询所有用户可以回忆一下之前mybatisplus是怎么查询的,仿照着写即可,不过有一些区别,上次写mybatisplus是纯后端,现在要和前端进行连接,所以要使用R这个对象,这是给前端返回的对象
LambdaQueryWrapper和QueryWrapper在这里都可以用作于简单的查询,LambdaQueryWrapper使用lambda表达式可以直接通过实体类get()属性,而QueryWrapper必须要与数据库的中表名一致

    
    //在controller层引用service层接口对象
    @Autowired
    private IUserService iUserService;

    /**
     * 查询所有用户列表
     */
    @GetMapping("/select")
    public R selectAll(){
        LambdaQueryWrapper<User> ulqw = new LambdaQueryWrapper<>();
        //查询出来的所有数据放入数据库表实体类对象的集合中
        List<User> dataList=iUserService.list(ulqw);
        
        //查询所有用户方法在mapper继承的baseMapper内有方法封装可直接调用,用多态的写法
		//List<User> dataList=iUserService.getBaseMapper().selectList(null);
		
		//通过R的ok方法put键值对返回给前端,这里返回的键就是获取数据列表发送请求成功后需要展示的数据集合
        return R.ok().put("dataList",dataList);
    }

10.前端接收查询并显示在页面上

在这里插入图片描述

分页查询

  • 1.在service接口内根据不同的key构建SQL查询条件,结合分页参数进行数据库查询,最后将查询结果封装成PageUtils对象返回给调用者
  • 2.在接口实现类里重写这个接口方法,先从map对象中获取键对应的值,再根据给定的参数查询实体类表中用户的信息,返回一个分页结果。定义一个泛型为SysUserEntity的分页对象,用于存储查询后的分页数据;创建一个新的Query对象,并调用getPage方法初始化一个分页对象;创建一个新的QueryWrapper对象,构建复杂条件查询SQL语句的对象;.like:如果username不为空或空白字符串isnotblank,则在生成的SQL查询中添加一个LIKE条件,匹配所有username字段与给定username值相匹配的记录;.eq:如果createUserId不为null,则在生成的SQL查询中添加一个等于(EQ)条件,匹配所有create_user_id字段与给定createUserId值相等的记录;返回新的分页对象PageUtils
  • 3.给service的接口传入params参数,返回一个分页page,返回一个成功的响应结果

IUserService

public interface IUserService extends IService<User> {

    /**
     * 在service接口内根据不同的key构建SQL查询条件,结合分页参数进行数据库查询,最后将查询结果封装成PageUtils对象返回给调用者
     */
    PageUtils queryPage(Map<String,Object> params);
}

UserServiceImpl

@Service("iUserService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
	@Override
    /*返回PageUtils工具类对象*/
    public PageUtils queryPage(Map<String, Object> params) {
        String username = (String) params.get("username");
        String phone = (String) params.get("phone");

        /*分页查询*/
        IPage<User> page=this.page(
                new Query<User>().getPage(params),
                new QueryWrapper<User>()
                        /*like-模糊查询*/
                .like(StringUtils.isNotBlank(username),"username",username)
                        /*eq-相等*/
                .eq(phone!=null,"phone",phone)
        );
        return new PageUtils(page);
    }
}

UserController

@RestController
@RequestMapping("/my/test")
public class UserController extends AbstractController {
    @Autowired
    private IUserService iUserService;

    //分页查询
    @GetMapping("/list")
    //@RequestParam 将前端发送的请求参数绑定到controller层的方法参数上
    public R list(@RequestParam Map<String,Object> params){
        PageUtils page = iUserService.queryPage(params);
        return R.ok().put("page",page);
    }

}

ttt.vue

<template>
  <div>
    <el-form :inline="true" :model="dataForm" @keyup.enter.native="search()">
        <el-form-item>
            <el-input v-model="dataForm.username" placeholder="请输入用户名" clearable></el-input>
        </el-form-item>
        <el-form-item>
            <el-button @click="search()">查询</el-button>
        </el-form-item>
    </el-form>
    <el-table :data="dataList" border style="width: 100%;">
        <el-table-column
        prop="id"
        header-align="center"
        align="center"
        width="80"
        label="ID"
      ></el-table-column>
      <el-table-column
        prop="username"
        header-align="center"
        align="center"
        label="用户名"
      ></el-table-column>
      <el-table-column
        prop="sex"
        header-align="center"
        align="center"
        label="性别"
      ></el-table-column>
      <el-table-column
        prop="phone"
        header-align="center"
        align="center"
        label="手机号"
      ></el-table-column>
      <el-table-column
        prop="city"
        header-align="center"
        align="center"
        label="所在城市"
      ></el-table-column>
      <el-table-column
        prop="position"
        header-align="center"
        align="center"
        label="职位"
      ></el-table-column>
      <el-table-column
        prop="salary"
        header-align="center"
        align="center"
        label="工资"
      ></el-table-column>
    </el-table>
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="pageIndex"
      :page-sizes="[10, 20, 50, 100]"
      :page-size="pageSize"
      layout="total, sizes, prev, pager, next, jumper"
      :total="totalPage"
    >
    </el-pagination>
  </div>
</template>

<script>
export default {
    data(){
        return{
            dataForm:{
                username:''
            },
            dataList:[],
            pageIndex:1,
            pageSize:10,
            totalPage:0
        }
    },
    activated(){
        this.getDataList()
    },
    methods:{
        search(){
            this.pageIndex = 1
            this.getDataList()
        },
        getDataList(){
            this.$http({
                url:this.$http.adornUrl("/my/test/list"),
                method:'get',
                params:this.$http.adornParams({
                    page:this.pageIndex,
                    limit:this.pageSize,
                    username:this.dataForm.username
                })
            }).then(({data})=>{
                if(data&&data.code===0){
                    this.dataList=data.page.list;
                    this.totalPage=data.page.totalCount;
                }else{
                    this.dataList=[];
                    this.totalPage=0
                }
            })
        },
        handleSizeChange(val){
            this.pageSize=val;
            this.pageIndex=1;
            this.getDataList();
        },
        handleCurrentChange(val){
            this.pageIndex=val;
            this.getDataList();
        }
    }
}
</script>

<style>

</style>

分页查询总结

默认查询数据库内全部信息,按照分页查询一页10条信息,左上角请输入用户名,可以输入完整的用户名,也可以模糊查询,写入按回车或者点查询都是可以查到想到的数据的,如果输错了可以点框框最右边的叉叉全删
在这里插入图片描述

删除(单个或批量)

  • 1.根据传入的一组用户id,一次性从数据库删除多个用户且无返回值
  • 2.将传入的用户id转换为一个ArrayList,再通过removeByIds方法一次性删除所有指定id对象
  • 3.删除用户前三个注释,系统日志注解SysLog、请求方式注解PostMapping、权限注解RequiresPermissions,其中权限注解暂时不写,在controller层的传入对象前加上请求体RequestBody;如果要删除的id里包含1就返回错误信息:它有系统管理员不能删除,调用service层的删除方法,传入ids进行删除,方法没有返回值,最后将结果返回给前端,让前端展现

方法一

IUserService

    /**
     * 根据传入的一组用户id,一次性从数据库删除多个用户且无返回值
     */
    void deleteBatch(Long[] ids);

UserServiceImpl

    @Override
    public void deleteBatch(Long[] ids) {
        this.removeByIds(Arrays.asList(ids));
    }

UserController

    //批量删除
    @SysLog("批量删除")
    @PostMapping("/delete")
    public R delete(@RequestBody Long[] ids){
        if (ArrayUtils.contains(ids,1l)){
            return R.error("有主键,不可删除");
        }

        iUserService.deleteBatch(ids);

        return R.ok();

    }

在这里插入图片描述
仿照写

ttt.vue

<template>
  <div>
    <el-form :inline="true" :model="dataForm" @keyup.enter.native="search()">
      <el-form-item>
        <el-input
          v-model="dataForm.username"
          placeholder="请输入用户名"
          clearable
        ></el-input>
      </el-form-item>
      <el-form-item>
        <el-button @click="search()">查询</el-button>
        <el-button
          type="danger"
          @click="deleteHandle()"
          :disabled="dataListSelections.length <= 0"
          >批量删除</el-button
        >
      </el-form-item>
    </el-form>
    <el-table
      :data="dataList"
      border
      @selection-change="selectionChangeHandle"
      style="width: 100%"
    >
      <el-table-column
        type="selection"
        header-align="center"
        align="center"
        width="50"
      >
      </el-table-column>
      <el-table-column
        prop="id"
        header-align="center"
        align="center"
        width="80"
        label="ID"
      ></el-table-column>
      <el-table-column
        prop="username"
        header-align="center"
        align="center"
        label="用户名"
      ></el-table-column>
      <el-table-column
        prop="sex"
        header-align="center"
        align="center"
        label="性别"
      ></el-table-column>
      <el-table-column
        prop="phone"
        header-align="center"
        align="center"
        label="手机号"
      ></el-table-column>
      <el-table-column
        prop="city"
        header-align="center"
        align="center"
        label="所在城市"
      ></el-table-column>
      <el-table-column
        prop="position"
        header-align="center"
        align="center"
        label="职位"
      ></el-table-column>
      <el-table-column
        prop="salary"
        header-align="center"
        align="center"
        label="工资"
      ></el-table-column>

      <el-table-column
        fixed="right"
        header-align="center"
        align="center"
        width="150"
        label="操作"
      >
        <template slot-scope="scope">
          <el-button
            type="text"
            size="medium"
            @click="deleteHandle(scope.row.id)"
            >删除</el-button
          >
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="pageIndex"
      :page-sizes="[10, 20, 50, 100]"
      :page-size="pageSize"
      layout="total, sizes, prev, pager, next, jumper"
      :total="totalPage"
    >
    </el-pagination>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dataForm: {
        username: "",
      },
      dataList: [],
      pageIndex: 1,
      pageSize: 10,
      totalPage: 0,
      dataListSelections: [],
    };
  },
  activated() {
    this.getDataList();
  },
  methods: {
    search() {
      this.pageIndex = 1;
      this.getDataList();
    },
    getDataList() {
      this.$http({
        url: this.$http.adornUrl("/my/test/list"),
        method: "get",
        params: this.$http.adornParams({
          page: this.pageIndex,
          limit: this.pageSize,
          username: this.dataForm.username,
        }),
      }).then(({ data }) => {
        if (data && data.code === 0) {
          this.dataList = data.page.list;
          this.totalPage = data.page.totalCount;
        } else {
          this.dataList = [];
          this.totalPage = 0;
        }
      });
    },
    handleSizeChange(val) {
      this.pageSize = val;
      this.pageIndex = 1;
      this.getDataList();
    },
    handleCurrentChange(val) {
      this.pageIndex = val;
      this.getDataList();
    },
    selectionChangeHandle(val) {
      this.dataListSelections = val;
    },
    deleteHandle(id) {
      var ids = id
        ? [id]
        : this.dataListSelections.map((item) => {
            return item.id;
          });
      this.$confirm(
        `确定对[id=${ids.join(",")}]进行[${id ? "删除" : "批量删除"}]操作?`,
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }
      ).then(() => {
        this.$http({
          url: this.$http.adornUrl("/my/test/delete"),
          method: "post",
          data: this.$http.adornData(ids, false),
        })
          .then(({ data }) => {
            if (data && data.code === 0) {
              this.$message({
                type: "success",
                message: "删除成功!",
                onClose: () => {
                  this.getDataList();
                },
              });
            } else {
              this.$message.error(data.msg);
            }
          })  
      }).catch(() => {
            this.$message({
              type: "info",
              message: "已取消删除",
            });
          });
    },
  },
};
</script>

<style>
</style>

方法二

在实现层只有一行代码无具体实现逻辑时可直接在controller层写该行实现代码(简便写法)
不用写service层方法,直接调用继承接口中的方法

UserController

    //批量删除
    @SysLog("批量删除")
    @PostMapping("/delete")
    public R delete(@RequestBody Long[] ids){
        if (ArrayUtils.contains(ids,1l)){
            return R.error("有主键,不可删除");
        }

        iUserService.removeByIds(Arrays.asList(ids));

        return R.ok();

    }

新增

  • 1.形参为用户实体类,用到的方法是IService中的save保存
  • 2.先使用hibernate-validator校验工具类ValidatorUtils里的校验方法validateEntity,传入实体类和新增数据所需验证规则的注解组AddGroup(一些数据不能为空或者有特定的规则)
  • 3.调用iUserService类接口继承的save方法,传入新增用户保存
  • 4.返回一个成功的响应结果

方法一

IUserService

void saveUser(User user);

UserServiceImpl

    @Override
    public void saveUser(User user) {
        this.save(user);
    }

UserController

    //新增
    @SysLog("新增用户")
    @PostMapping("/save")
    public R save(@RequestBody User user){
        ValidatorUtils.validateEntity(user, AddGroup.class);
        iUserService.saveUser(user);
        return R.ok();
    }

方法二

不用写service层方法,直接调用继承接口中的方法

UserController

    //新增
    @SysLog("新增用户")
    @PostMapping("/save")
    public R save(@RequestBody User user){
        ValidatorUtils.validateEntity(user, AddGroup.class);
        iUserService.save(user);
        return R.ok();
    }

修改

  • 1.和新增用户类似,使用方法为updateById,也是继承接口中的方法
  • 2.注解组变为UpdateGroup,也需要验证

方法一

IUserService

void updateUser(User user);

UserServiceImpl

    @Override
    public void updateUser(User user) {
        this.updateById(user);
    }

UserController

    //修改
    @SysLog("修改用户")
    @PostMapping("/update")
    public R update(@RequestBody User user){
        ValidatorUtils.validateEntity(user, UpdateGroup.class);
        iUserService.updateUser(user);
        return R.ok();
    }

方法二

不用写service层方法,直接调用继承接口中的方法

UserController

    //修改
    @SysLog("修改用户")
    @PostMapping("/update")
    public R update(@RequestBody User user){
        ValidatorUtils.validateEntity(user, UpdateGroup.class);
        iUserService.updateById(user);
        return R.ok();
    }

新增和修改为相同的方法

二者区别在于是否传入id,可以根据是否传入id来进行新增或是修改

ttt.vue最终版

  • 1.新增按钮:在查询和批量删除中间,类型为primary主要,点击触发addOrUpdateHandle事件
  • 2.修改按钮:和删除并列,写法也与删除类似
  • 3.在分页下写一个弹窗add-or-update:和addOrUpdateVisible双向绑定,默认false不弹出,需要在data内初始化,注册组件引用addOrUpdate,刷新数据集合refreshDataList,和getDataList双向绑定
  • 4.import...from...:从xx导入AddOrUpdate模块->对新增和修改的具体写法放在另一个界面内
  • 5.注册组件:components内写组件的名字
  • 6.addOrUpdateHandle方法:传入一个id,有id值的则为修改,没有传入的则为新增;此时需要弹出新增/修改弹窗,所以要把addOrUpdateVisible写为true弹出;弹出之后才会有下一步$nextTick指向当前访问的$refs对象,在访问的对象中查找addOrUpdate的子组件,调用子组件的init方法并传入一个id
  • 此时主页面已写完,需要自行写addOrUpdate子组件
<template>
  <div>
    <el-form :inline="true" :model="dataForm" @keyup.enter.native="search()">
      <el-form-item>
        <el-input
          v-model="dataForm.username"
          placeholder="请输入用户名"
          clearable
        ></el-input>
      </el-form-item>
      <el-form-item>
        <el-button @click="search()">查询</el-button>
        <el-button type="primary" @click="addOrUpdateHandle()">新增</el-button>
        <el-button
          type="danger"
          @click="deleteHandle()"
          :disabled="dataListSelections.length <= 0"
          >批量删除</el-button
        >
      </el-form-item>
    </el-form>
    <el-table
      :data="dataList"
      border
      @selection-change="selectionChangeHandle"
      style="width: 100%"
    >
      <el-table-column
        type="selection"
        header-align="center"
        align="center"
        width="50"
      ></el-table-column>
      <el-table-column
        prop="id"
        header-align="center"
        align="center"
        width="80"
        label="ID"
      ></el-table-column>
      <el-table-column
        prop="username"
        header-align="center"
        align="center"
        label="用户名"
      ></el-table-column>
      <el-table-column
        prop="sex"
        header-align="center"
        align="center"
        label="性别"
      ></el-table-column>
      <el-table-column
        prop="phone"
        header-align="center"
        align="center"
        label="手机号"
      ></el-table-column>
      <el-table-column
        prop="city"
        header-align="center"
        align="center"
        label="所在城市"
      ></el-table-column>
      <el-table-column
        prop="position"
        header-align="center"
        align="center"
        label="职位"
      ></el-table-column>
      <el-table-column
        prop="salary"
        header-align="center"
        align="center"
        label="工资"
      ></el-table-column>
      <el-table-column
        fixed="right"
        header-align="center"
        align="center"
        width="150"
        label="操作"
      >
        <template slot-scope="scope">
          <el-button
            type="text"
            size="medium"
            @click="deleteHandle(scope.row.id)"
            >删除</el-button
          >
          <el-button
            type="text"
            size="medium"
            @click="addOrUpdateHandle(scope.row.id)"
            >修改</el-button
          >
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="pageIndex"
      :page-sizes="[10, 20, 50, 100]"
      :page-size="pageSize"
      layout="total, sizes, prev, pager, next, jumper"
      :total="totalPage"
    >
    </el-pagination>
    <add-or-update
      v-if="addOrUpdateVisible"
      ref="addOrUpdate"
      @refreshDataList="getDataList"
    ></add-or-update>
  </div>
</template>
  
  <script>
import AddOrUpdate from "./ttt-add-or-update";
export default {
  data() {
    return {
      dataForm: {
        username: "",
      },
      dataList: [],
      pageIndex: 1,
      pageSize: 10,
      totalPage: 0,
      dataListSelections: [],
      addOrUpdateVisible: false,
    };
  },
  components: {
    AddOrUpdate,
  },
  activated() {
    this.getDataList();
  },
  methods: {
    search() {
      this.pageIndex = 1;
      this.getDataList();
    },
    getDataList() {
      this.$http({
        url: this.$http.adornUrl("/my/test/list"),
        method: "get",
        params: this.$http.adornParams({
          page: this.pageIndex,
          limit: this.pageSize,
          username: this.dataForm.username,
        }),
      }).then(({ data }) => {
        if (data && data.code === 0) {
          this.dataList = data.page.list;
          this.totalPage = data.page.totalCount;
        } else {
          this.dataList = [];
          this.totalPage = 0;
        }
      });
    },
    handleSizeChange(val) {
      this.pageSize = val;
      this.pageIndex = 1;
      this.getDataList();
    },
    handleCurrentChange(val) {
      this.pageIndex = val;
      this.getDataList();
    },
    selectionChangeHandle(val) {
      this.dataListSelections = val;
    },
    deleteHandle(id) {
      var ids = id
        ? [id]
        : this.dataListSelections.map((item) => {
            return item.id;
          });
      this.$confirm(
        `确定对[id=${ids.join(",")}]进行[${id ? "删除" : "批量删除"}]操作?`,
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }
      )
        .then(() => {
          this.$http({
            url: this.$http.adornUrl("/my/test/delete"),
            method: "post",
            data: this.$http.adornData(ids, false),
          }).then(({ data }) => {
            if (data & (data.code === 0)) {
              this.$message({
                type: "success",
                message: "删除成功!",
                onClose: () => {
                  this.getDataList();
                },
              });
            } else {
              this.$message.error(data.msg);
            }
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除",
          });
        });
    },
    addOrUpdateHandle(id) {
      this.addOrUpdateVisible = true;
      this.$nextTick(() => {
        this.$refs.addOrUpdate.init(id);
      });
    },
  },
};
</script>
  
  <style>
</style>

ttt-add-or-update.vue

  • 1.根据对话框组件dialog写弹窗内容,动态设置标题内容,属性都需要双向绑定,无id传入就新增,有id传入就修改,将close-on-click-modal设置为false
  • 2.在对话框内写表单,和dataForm双向绑定,dataForm内有数据库全部字段;和dataRule双向绑定,用户名等不为空,手机号有特殊验证格式,通过ref直接访问dataForm dom元素,绑定回车即提交表单事件
  • 3.表单项:username、sex、phone、city、position、salary,均有label、prop属性
  • 4.表单项内username输入框,双向绑定dataForm的username,占位文本placeholder
  • 5.性别男女保密单选
  • 6.最后复制底部插槽 修改确定的点击事件为提交表单事件
  • 可以去element官网找寻自己需要的组件 点击进入element官网
    在这里插入图片描述
<template>
  <el-dialog
    :title="!dataForm.id ? '新增' : '修改'"
    :visible.sync="dialogVisible"
    :before-close="handleClose"
    :close-on-click-modal="false"
  >
    <el-form
      :model="dataForm"
      :rules="dataRule"
      ref="dataForm"
      @keyup.enter.native="dataFormSubmit()"
    >
      <el-form-item label="用户名" prop="username">
        <el-input
          v-model="dataForm.username"
          placeholder="请输入用户名"
        ></el-input>
      </el-form-item>
      <el-form-item label="性别" prop="sex">
        <el-radio-group v-model="dataForm.sex">
           <el-radio label=""></el-radio> 
          <el-radio label=""></el-radio> 
          <el-radio label="保密"></el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="手机号" prop="phone">
        <el-input
          v-model="dataForm.phone"
          placeholder="请输入手机号"
        ></el-input>
      </el-form-item>
      <el-form-item label="所在城市" prop="city">
        <el-input
          v-model="dataForm.city"
          placeholder="请输入所在城市"
        ></el-input>
      </el-form-item>
      <el-form-item label="职位" prop="position">
        <el-input
          v-model="dataForm.position"
          placeholder="请输入职位"
        ></el-input>
      </el-form-item>
      <el-form-item label="工资" prop="salary">
        <el-input v-model="dataForm.salary" placeholder="请输入工资"></el-input>
      </el-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
      <el-button @click="dialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="dataFormSubmit()">确 定</el-button>
    </span>
  </el-dialog>
</template>
    
    <script>
export default {
  data() {
    return {
      dialogVisible: false,
      dataForm: {
        id: 0,
        username: "",
        sex: "",
        phone: "",
        city: "",
        position: "",
        salary: "",
      },
      dataRule: {},
    };
  },
  methods: {
      handleClose(done) {
        this.$confirm('确认关闭?')
          .then(_ => {
            done();
          })
          .catch(_ => {});
      },
    }
};
</script>
    
    <style>
</style>
    
    

init方法

1.init(id)根据传入的id值,真则修改,假则为0新增,左上角的标题随之动态改变
2.判断完了设置弹出弹窗为true
3.弹出了再进行下一步操作$nextTick用resetFields把表单内的数据都置空
4.如果有id,则修改单条数据,先根据id查询单条数据,请求方式以及参数处理,then对把data数据放入表单,如果data存在且code恒等于0则进行修改this.dataForm.xxx=data.user.xxx
这里涉及到一个根据id查找返回用户信息的方法

  methods: {
      handleClose(done) {
        this.$confirm('确认关闭?')
          .then(_ => {
            done();
          })
          .catch(_ => {});
      },
      init(id){
        this.dataForm.id=id||0;
        this.dialogVisible = true;
        this.$nextTick(()=>{
            this.$refs['dataForm'].resetFields();
        })
        if(this.dataForm.id){
            this.$http({
                url:this.$http.adornUrl(`/my/test/info/${this.dataForm.id}`),
                method:'get',
            }).then(({data})=>{
                if(data&&data.code===0){
                    this.dataForm.username=data.user.username;
                    this.dataForm.sex=data.user.sex;
                    this.dataForm.phone=data.user.phone;
                    this.dataForm.city=data.user.city;
                    this.dataForm.position=data.user.position;
                    this.dataForm.salary=data.user.salary;
                }
            })
        }
      }
    }

涉及到的info方法

    //根据id拿出用户信息
    @GetMapping("/info/{id}")
    public R info(@PathVariable Long id){
        User user = iUserService.getById(id);
        return R.ok().put("user",user);
    }

dataRule

1.不能为空:字段:[{required:true,message:“”,trigger:“blur”}]
2.手机号有特殊认证,再加一个{},在里面写验证函数validator: validateMobile
3.自定义函数validateMobile,验证规则对象rule,待验证的值value,回调函数用于通知验证结果callback
4.如果这个待验证的值不符合手机号格式(从另一个格式页面导入)就用回调函数返回一个错误消息,否则就通过验证,回调函数内什么也不写

<template>
  <el-dialog
    :title="!dataForm.id ? '新增' : '修改'"
    :visible.sync="dialogVisible"
    :before-close="handleClose"
    :close-on-click-modal="false"
  >
    <el-form
      :model="dataForm"
      :rules="dataRule"
      ref="dataForm"
      @keyup.enter.native="dataFormSubmit()"
    >
      <el-form-item label="用户名" prop="username">
        <el-input
          v-model="dataForm.username"
          placeholder="请输入用户名"
        ></el-input>
      </el-form-item>
      <el-form-item label="性别" prop="sex">
        <el-radio-group v-model="dataForm.sex">
           <el-radio label=""></el-radio> 
          <el-radio label=""></el-radio> 
          <el-radio label="保密"></el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="手机号" prop="phone">
        <el-input
          v-model="dataForm.phone"
          placeholder="请输入手机号"
        ></el-input>
      </el-form-item>
      <el-form-item label="所在城市" prop="city">
        <el-input
          v-model="dataForm.city"
          placeholder="请输入所在城市"
        ></el-input>
      </el-form-item>
      <el-form-item label="职位" prop="position">
        <el-input
          v-model="dataForm.position"
          placeholder="请输入职位"
        ></el-input>
      </el-form-item>
      <el-form-item label="工资" prop="salary">
        <el-input v-model="dataForm.salary" placeholder="请输入工资"></el-input>
      </el-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
      <el-button @click="dialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="dataFormSubmit()">确 定</el-button>
    </span>
  </el-dialog>
</template>
    
    <script>
    import { isMobile } from "@/utils/validate";
export default {
  data() {
    var valicatePhone=(rule,value,callback)=>{
        if(!isMobile(value)){
            callback(new Error('手机号格式错误,请重新输入'))
        }else{
            callback()
        }
    }
    return {
      dialogVisible: false,
      dataForm: {
        id: 0,
        username: "",
        sex: "",
        phone: "",
        city: "",
        position: "",
        salary: "",
      },
      dataRule: {
        username:[{required: true,message:'用户名不为空',trigger:'blur'}],
        phone:[{required: true,message:'手机号不为空',trigger:'blur'},{valivate:valicatePhone,trigger:'blur'}],
        city:[{required: true,message:'所在城市不为空',trigger:'blur'}],
        position:[{required: true,message:'职位不为空',trigger:'blur'}],
        salary:[{required: true,message:'薪水不为空',trigger:'blur'}],
      },
    };
  },
  methods: {
      handleClose(done) {
        this.$confirm('确认关闭?')
          .then(_ => {
            done();
          })
          .catch(_ => {});
      },
      init(id){
        this.dataForm.id=id||0;
        this.dialogVisible = true;
        this.$nextTick(()=>{
            this.$refs['dataForm'].resetFields();
        })
        if(this.dataForm.id){
            this.$http({
                url:this.$http.adornUrl(`/my/test/info/${this.dataForm.id}`),
                method:'get',
            }).then(({data})=>{
                if(data&&data.code===0){
                    this.dataForm.username=data.user.username;
                    this.dataForm.sex=data.user.sex;
                    this.dataForm.phone=data.user.phone;
                    this.dataForm.city=data.user.city;
                    this.dataForm.position=data.user.position;
                    this.dataForm.salary=data.user.salary;
                }
            })
        }
      }
    }
};
</script>
    
    <style>
</style>
    
    

dataFormSubmit

1.访问特定ref属性的dom元素dataForm并进行表单验证validate接收参数
2.如果验证成功,则发送请求,url内写一个三元表达式/xx/xx/${},和title的三元一样,没有id就save,有id就update,要用着重符号处理特殊字符,确保能发送请求,请求方式post要调用adornData传入数据对象,id要写一个逻辑或,是真的就取前面的值,假的就为undefined,其他全this.dataForm.xxx
3.then再处理data,如果存在且code恒等于0就发出提示信息,操作成功,关闭窗口的时候触发关闭事件,把标题重新设置为false,再用$emit方法触发刷新列表数据事件refreshDataList,否则显示data的错误信息

      dataFormSubmit() {
        this.$refs["dataForm"].validate((val) => {
          if (val) {
            this.$http({
              url: this.$http.adornUrl(
                `/my/test/${!this.dataForm.id ? "save" : "update"}`
              ),
              method: "post",
              data: this.$http.adornData({
                id: this.dataForm.id || undefined,
                username: this.dataForm.username,
                sex: this.dataForm.sex,
                phone: this.dataForm.phone,
                city: this.dataForm.city,
                position: this.dataForm.position,
                salary: this.dataForm.salary,
              }),
            }).then(({ data }) => {
              if (data && data.code === 0) {
                this.$message({
                  message: "操作成功",
                  type: "success",
                  onClose: () => {
                    this.dialogVisible = false;
                    this.$emit("refreshDataList");
                  },
                });
              } else {
                this.$message.Error(data.msg);
              }
            });
          }
        });
      },

ttt-add-or-update.vue最终版

<template>
  <el-dialog
    :title="!dataForm.id ? '新增' : '修改'"
    :visible.sync="dialogVisible"
    :close-on-click-modal="false"
    :before-close="handleClose"
  >
    <el-form
      :model="dataForm"
      :rules="dataRule"
      ref="dataForm"
      @keyup.enter.native="dataFormSubmit()"
    >
      <el-form-item label="用户名" prop="username">
        <el-input
          v-model="dataForm.username"
          placeholder="请输入用户名"
        ></el-input>
      </el-form-item>
      <el-form-item label="性别" prop="sex">
        <el-radio-group v-model="dataForm.sex">
          <el-radio label=""></el-radio>
          <el-radio label=""></el-radio>
          <el-radio label="保密"></el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="手机号" prop="phone">
        <el-input
          v-model="dataForm.phone"
          placeholder="请输入手机号"
        ></el-input>
      </el-form-item>
      <el-form-item label="所在城市" prop="city">
        <el-input
          v-model="dataForm.city"
          placeholder="请输入所在城市"
        ></el-input>
      </el-form-item>
      <el-form-item label="职位" prop="position">
        <el-input
          v-model="dataForm.position"
          placeholder="请输入职位"
        ></el-input>
      </el-form-item>
      <el-form-item label="工资" prop="salary">
        <el-input v-model="dataForm.salary" placeholder="请输入工资"></el-input>
      </el-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
      <el-button @click="dialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="dataFormSubmit()">确 定</el-button>
    </span>
  </el-dialog>
</template>

<script>
import { isMobile } from "@/utils/validate";
export default {
  data() {
    var validatePhone = (rule, value, callback) => {
      if (!isMobile(value)) {
        callback(new Error("手机号格式错误,请重新输入"));
      } else {
        callback();
      }
    };
    return {
      dataForm: {
        id: 0,
        username: "",
        sex: "",
        phone: "",
        city: "",
        position: "",
        salary: "",
      },
      dialogVisible: false,
      dataRule: {
        username: [
          { required: true, message: "用户名不为空", trigger: "blur" },
        ],
        phone: [
          { required: true, message: "手机号不为空", trigger: "blur" },
          { validator: validatePhone, trigger: "blur" },
        ],
        city: [{ required: true, message: "所在城市不为空", trigger: "blur" }],
        position: [{ required: true, message: "职位不为空", trigger: "blur" }],
        salary: [{ required: true, message: "工资不为空", trigger: "blur" }],
      },
    };
  },
  methods: {
    handleClose(done) {
      this.$confirm("确认关闭?")
        .then((_) => {
          done();
        })
        .catch((_) => {});
    },
    init(id) {
      this.dataForm.id = id || 0;
      this.dialogVisible = true;
      this.$nextTick(() => {
        this.$refs["dataForm"].resetFields();
      });
      if (this.dataForm.id) {
        this.$http({
          url: this.$http.adornUrl(`/my/test/info/${this.dataForm.id}`),
          method: "get",
        }).then(({ data }) => {
          if (data && data.code === 0) {
            (this.dataForm.username = data.user.username),
              (this.dataForm.sex = data.user.sex),
              (this.dataForm.phone = data.user.phone),
              (this.dataForm.city = data.user.city),
              (this.dataForm.position = data.user.position),
              (this.dataForm.salary = data.user.salary);
          } 
        });
      }
    },
    dataFormSubmit() {
      this.$refs["dataForm"].validate((val) => {
        if (val) {
          this.$http({
            url: this.$http.adornUrl(
              `/my/test/${!this.dataForm.id ? "save" : "update"}`
            ),
            method: "post",
            data: this.$http.adornData({
              id: this.dataForm.id || undefined,
              username: this.dataForm.username,
              sex: this.dataForm.sex,
              phone: this.dataForm.phone,
              city: this.dataForm.city,
              position: this.dataForm.position,
              salary: this.dataForm.salary,
            }),
          }).then(({ data }) => {
            if (data && data.code === 0) {
              this.$message({
                message: "操作成功",
                type: "success",
                onClose: () => {
                  this.dialogVisible = false;
                  this.$emit("refreshDataList");
                },
              });
            } else {
              this.$message.Error(data.msg);
            }
          });
        }
      });
    },
  },
};
</script>

<style>
</style>

至此Mysql+MybatisPlus+Vue实现基础增删改查CRUD已基本完善

  • 40
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今年不养猪只除草

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值