二、从零开始-用户管理编写
导航
上一章地址:一、从零开始-初始化项目
下一章地址:三、从零开始-填坑
说明
- 贴代码时会贴整个类的全量代码,防止找不到我改的是哪个
- 创建的类在哪个包下不会单独说明,因为全量代码里有 package 直接看这个就可以了
- gitee 代码存放地址 https://gitee.com/mxw13579/study-scaffold 可以直接下下来看更加清晰
文章目录
二、从零开始-用户管理
我们先编写一个初始的用户管理模块开始
2.1、初始化架子
先把一些简单的功能先写出来
2.1.1、entity
package com.lzl.study.scaffold.studyscaffold.user.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.lzl.study.scaffold.studyscaffold.common.entity.BaseEntity;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @ClassName SysUser
* @Author lizelin
* @Description 用户管理 entity
* @Date 2023-10-09 19:45
* @Version 1.0
*/
@TableName("t_sys_user")
@Data
public class SysUserEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableField(fill = FieldFill.INSERT)
private Long id;
/**
* 姓名
*/
private String name;
/**
* 密码
*/
private String password;
/**
* 手机号
*/
private String phone;
/**
* 登录账号
*/
private String account;
/**
* 性别,0女1男2未知
*/
private Integer sex;
/**
* 身份证号码
*/
private String idCard;
/**
* 邮箱
*/
private String email;
/**
* 部门ID,不允许多部门
*/
private Long deptId;
/**
* 岗位ID集合,允许多岗位
*/
private String userPostIds;
/**
* 角色ID集合,允许多角色
*/
private String roleIds;
/**
* 用户状态 0为启用1为禁用
*/
private Integer userStatus;
/**
* 父部门ID
*/
private Long parentId;
/**
* 最后密码修改时间
*/
private LocalDateTime passwordUpdateData;
/**
* 最后登录时间
*/
private LocalDateTime loginDate;
/**
* 最后登录IP
*/
private String loginIp;
/**
* 备注
*/
private String remark;
/**
* 租户号
*/
private Integer tenantId;
/**
* 乐观锁
*/
private Integer revision;
/**
* 创建人
*/
@TableField(fill = FieldFill.INSERT)
private Long createdBy;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createdTime;
/**
* 更新人
*/
@TableField(fill = FieldFill.UPDATE)
private Long updatedBy;
/**
* 更新时间
*/
@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updatedTime;
}
2.1.2、controller
package com.lzl.study.scaffold.studyscaffold.user.controller;
import com.lzl.study.scaffold.studyscaffold.user.service.SysUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
/**
* @ClassName SysUserController
* @Author lizelin
* @Description 用户管理 controller 层
* @Date 2023-10-09 20:00
* @Version 1.0
*/
@Slf4j
@RestController
@RequestMapping("sysUser")
@AllArgsConstructor
public class SysUserController {
private final SysUserService sysUserService;
/**
* @param dto
* @return com.baomidou.mybatisplus.extension.plugins.pagination.Page
* @Description 分页查询
* @author lizelin
* @date 2023-10-10 16:35
**/
@GetMapping("/page")
public Page page(Page page) {
return sysUserService.page(page);
}
/**
* @param sysUserSaveDto
* @return com.lzl.study.scaffold.studyscaffold.common.entity.R
* @Description 新增
* @author lizelin
* @date 2023-10-10 16:35
**/
@PostMapping
public Boolean add(@RequestBody SysUserEntity entity) {
return sysUserService.save(entity);
}
}
2.1.3、service
package com.lzl.study.scaffold.studyscaffold.user.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lzl.study.scaffold.studyscaffold.user.entity.SysUserEntity;
/**
* @ClassName UserService
* @Author lizelin
* @Description 用户管理 service
* @Date 2023-10-09 19:52
* @Version 1.0
*/
public interface SysUserService extends IService<SysUserEntity> {
}
2.1.4、serviceImpl
package com.lzl.study.scaffold.studyscaffold.user.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lzl.study.scaffold.studyscaffold.user.entity.SysUserEntity;
import com.lzl.study.scaffold.studyscaffold.user.mapper.SysUserMapper;
import com.lzl.study.scaffold.studyscaffold.user.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @ClassName SysUserServiceImpl
* @Author lizelin
* @Description 用户管理 serviceImpl
* @Date 2023-10-09 19:58
* @Version 1.0
*/
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity> implements SysUserService {
}
2.1.5、mapper
package com.lzl.study.scaffold.studyscaffold.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lzl.study.scaffold.studyscaffold.user.entity.SysUserEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* @ClassName SysUserMapper
* @Author lizelin
* @Description 用户管理 mapper
* @Date 2023-10-09 19:55
* @Version 1.0
*/
@Mapper
public interface SysUserMapper extends BaseMapper<SysUserEntity> {
}
2.1.6、分页插件
然后将分页插件注入进去
package com.lzl.study.scaffold.studyscaffold.common.config;
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;
/**
* @ClassName MybatisConfig
* @Author lizelin
* @Description mybatisPlus 配置
* @Date 2023-10-09 20:09
* @Version 1.0
*/
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//1 创建MybatisPlusInterceptor拦截器对象
MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
//2 添加分页拦截器
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mpInterceptor;
}
}
到这里的话项目也就可以正常运行了,通过 controller 层就可以对接口进行测试看是否正常
2.2、通用类
到上面初始化架子完成之后,项目虽然能正常运行,但是很显然不符合企业级的要求
我们看 controller 层返回的两个接口,返回两种不同的对象,很明显你想累死前端
所以我们首先需要做一个公共返回类
2.2.1、通用返回类
package com.lzl.study.scaffold.studyscaffold.common.entity;
import lombok.Data;
/**
* @ClassName R
* @Author lizelin
* @Description Result 封装类
* @Date 2023-10-09 23:38
* @Version 1.0
*/
@Data
public class R {
/**
* 编码:1 成功,0和其他数字失败
*/
private Integer code;
/**
* 错误信息
*/
private String msg;
/**
* 数据
*/
private Object data;
/**
* @param obj 数据
* @return com.study.study.common.R<T>
* @Description 成功返回
* @author lizelin
* @date 2023-09-25 20:20
**/
public static R success(Object obj) {
R r = new R();
r.data = obj;
r.code = 1;
return r;
}
/**
* @param msg 错误信息
* @return com.study.study.common.R<T>
* @Description 失败返回
* @author lizelin
* @date 2023-09-25 20:20
**/
public static R error(String msg) {
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}
}
然后我们改造一下 controller 层的返回
package com.lzl.study.scaffold.studyscaffold.user.controller;
import com.lzl.study.scaffold.studyscaffold.common.entity.R;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserPageDto;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserSaveDto;
import com.lzl.study.scaffold.studyscaffold.user.service.SysUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @ClassName SysUserController
* @Author lizelin
* @Description 用户管理 controller 层
* @Date 2023-10-09 20:00
* @Version 1.0
*/
@Slf4j
@RestController
@RequestMapping("sysUser")
@AllArgsConstructor
public class SysUserController {
private final SysUserService sysUserService;
/**
* @param dto
* @return com.baomidou.mybatisplus.extension.plugins.pagination.Page
* @Description 分页查询
* @author lizelin
* @date 2023-10-10 16:35
**/
@GetMapping("/page")
public R page(Page page) {
return R.success(sysUserService.page(page));
}
/**
* @param sysUserSaveDto
* @return com.lzl.study.scaffold.studyscaffold.common.entity.R
* @Description 新增
* @author lizelin
* @date 2023-10-10 16:35
**/
@PostMapping
public R add(@RequestBody SysUserEntity entity) {
return R.success(sysUserService.save(entity));
}
}
这个改造完了我们在看看还有没有什么别的问题
分析一下,首先数据库表肯定要有 ID 的,什么 createdBy、updatedBy、createdTime、updatedTime 这些肯定都是公有的,这些参数我们就可以抽离出来用一个父类去存放,而不需要每个类都写一个
2.2.2、通用 Entity 父类
package com.lzl.study.scaffold.studyscaffold.common.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @ClassName BaseEntity
* @Author lizelin
* @Description entity 父类
* @Date 2023-10-09 19:47
* @Version 1.0
*/
@Data
public class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableField(fill = FieldFill.INSERT)
private Long id;
/**
* 租户号
*/
private Integer tenantId;
/**
* 乐观锁
*/
private Integer revision;
/**
* 创建人
*/
@TableField(fill = FieldFill.INSERT)
private Long createdBy;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createdTime;
/**
* 更新人
*/
@TableField(fill = FieldFill.UPDATE)
private Long updatedBy;
/**
* 更新时间
*/
@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updatedTime;
}
然后改造一下 entity
package com.lzl.study.scaffold.studyscaffold.user.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.lzl.study.scaffold.studyscaffold.common.entity.BaseEntity;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @ClassName SysUser
* @Author lizelin
* @Description 用户管理 entity
* @Date 2023-10-09 19:45
* @Version 1.0
*/
@TableName("t_sys_user")
@Data
public class SysUserEntity extends BaseEntity {
/**
* 姓名
*/
private String name;
/**
* 密码
*/
private String password;
/**
* 手机号
*/
private String phone;
/**
* 登录账号
*/
private String account;
/**
* 性别,0女1男2未知
*/
private Integer sex;
/**
* 身份证号码
*/
private String idCard;
/**
* 邮箱
*/
private String email;
/**
* 部门ID,不允许多部门
*/
private Long deptId;
/**
* 岗位ID集合,允许多岗位
*/
private String userPostIds;
/**
* 角色ID集合,允许多角色
*/
private String roleIds;
/**
* 用户状态 0为启用1为禁用
*/
private Integer userStatus;
/**
* 父部门ID
*/
private Long parentId;
/**
* 最后密码修改时间
*/
private LocalDateTime passwordUpdateData;
/**
* 最后登录时间
*/
private LocalDateTime loginDate;
/**
* 最后登录IP
*/
private String loginIp;
/**
* 备注
*/
private String remark;
}
我们将其抽离出来,这样实体里面存的就是无冗余的字段了
继续分析
我们在新增的时候,用的是实体类接收的
/**
* @param sysUserSaveDto
* @return com.lzl.study.scaffold.studyscaffold.common.entity.R
* @Description 新增
* @author lizelin
* @date 2023-10-10 16:35
**/
@PostMapping
public Boolean add(@RequestBody SysUserEntity entity) {
return sysUserService.save(entity);
}
这样可能会导致前端传参的时候,恶意的传一个 ID 过来,或者是 createdBy 这些参数过来,这样肯定是不行的,这不纯纯被攻击了么
所以我们需要一个专门的 DTO 来接收来自前端的传参,并且需要对参数进行校验,并且由于是前端传参接收,那么 分页也必须得有
也就是需要做三件事
- 新增的 dto 只保留允许添加的参数
- 对参数进行校验
- 分页参数
别问为什么不能直接拿 Page 来接收分页参数,问就是 Page 是泛型,如果直接使用按规范来讲应该要指定类型的
2.2.3、通用 DTO 父类
首先来完成第一和第二件事,只保留允许添加的参数,并且对参数进行校验
2.2.3.1、新增处理
新建一个DTO 类
@Data
public class SysUserSaveDtoimplements Serializable {
private static final long serialVersionUID = 1L;
/**
* 姓名
*/
@NotBlank(message = "姓名不能为空")
@Size(min = 0, max = 32, message = "参数名称不能超过 32 个字符")
private String name;
/**
* 密码
*/
@NotBlank(message = "密码不能为空")
@Size(min = 0, max = 64, message = "密码长度不能超过 64 个字符")
private String password;
/**
* 手机号
*/
@NotBlank(message = "手机号不能为空")
@Size(min = 0, max = 32, message = "手机号长度不能超过 32 个字符")
@Pattern(regexp = StringCommonConstant.PHONE_REGEXP, message = "手机号格式不正确")
private String phone;
/**
* 登录账号
*/
@NotBlank(message = "登录账号不能为空")
@Size(min = 0, max = 32, message = "登录账号不能超过 64 个字符")
private String account;
/**
* 性别,0女1男2未知
*/
@Min(value = 0, message = "用户状态 传参不正确")
@Max(value = 2, message = "用户状态 传参不正确")
@NotNull
private Integer sex;
/**
* 身份证号码
*/
@NotBlank(message = "身份证号码不能为空")
@Size(min = 0, max = 32, message = "身份证号码不能超过 32 个字符")
@Pattern(regexp = StringCommonConstant.ID_CARD_REGEXP , message = "身份证号码格式不正确")
private String idCard;
/**
* 邮箱
*/
@Pattern(regexp = StringCommonConstant.EMAIL_REGEXP, message = "邮箱格式不正确")
private String email;
/**
* 部门ID,不允许多部门
*/
private Long deptId;
/**
* 岗位ID集合,允许多岗位,传值为 1,2,3
*/
private String userPostIds;
/**
* 角色ID集合,允许多角色,传值为 1,2,3
*/
private String roleIds;
/**
* 用户状态 0为启用1为禁用
*/
@Min(value = 0, message = "用户状态 传参不正确")
@Max(value = 1, message = "用户状态 传参不正确")
private Integer userStatus;
/**
* 父部门ID
*/
private Long parentId;
/**
* 备注
*/
@Size(min = 0, max = 255, message = "备注不能超过 255 个字符")
private String remark;
}
然后写一个常量类来存储常量
package com.lzl.study.scaffold.studyscaffold.common.constant;
/**
* @ClassName ConmmonEnum
* @Author lizelin
* @Description String 类型常用 常量
* @Date 2023-10-10 16:46
* @Version 1.0
*/
public class StringCommonConstant {
private StringCommonConstant() {
throw new IllegalStateException("工具类不允许实例化");
}
public static final String PHONE_REGEXP = "^((13[0-9])|(14[579])|(15([0-3]|[5-9]))|(16[56])|(17[0-8])|(18[0-9])|(19[1589]))\\d{8}$";
public static final String ID_CARD_REGEXP = "^[1-9]\\d{5}(18|19|20)\\d{2}(0\\d|10|11|12)([0-2]\\d|30|31)\\d{3}[0-9Xx]$";
public static final String EMAIL_REGEXP = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
}
然后在去改造一下 service 层,因为你拿 DTO 直接去 save 的话,是无法 save 进去的
package com.lzl.study.scaffold.studyscaffold.user.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lzl.study.scaffold.studyscaffold.user.entity.SysUserEntity;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserPageDto;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserSaveDto;
/**
* @ClassName UserService
* @Author lizelin
* @Description 用户管理 service
* @Date 2023-10-09 19:52
* @Version 1.0
*/
public interface SysUserService extends IService<SysUserEntity> {
/**
* @param sysUserSaveDto
* @return java.lang.Boolean
* @Description dto 新增
* @author lizelin
* @date 2023-10-10 0:07
**/
Boolean dtoSave(SysUserSaveDto sysUserSaveDto);
}
实现一下方法
package com.lzl.study.scaffold.studyscaffold.user.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lzl.study.scaffold.studyscaffold.common.util.QueryWrapperBuild;
import com.lzl.study.scaffold.studyscaffold.user.entity.SysUserEntity;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserPageDto;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserSaveDto;
import com.lzl.study.scaffold.studyscaffold.user.mapper.SysUserMapper;
import com.lzl.study.scaffold.studyscaffold.user.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @ClassName SysUserServiceImpl
* @Author lizelin
* @Description 用户管理 serviceImpl
* @Date 2023-10-09 19:58
* @Version 1.0
*/
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity> implements SysUserService {
/**
* @param sysUserSaveDto
* @return java.lang.Boolean
* @Description 通过 dto 新增
* @author lizelin
* @date 2023-10-10 0:08
**/
@Override
public Boolean dtoSave(SysUserSaveDto sysUserSaveDto) {
SysUserEntity entity = BeanUtil.copyProperties(sysUserSaveDto, SysUserEntity.class);
return save(entity);
}
}
我们将 DTO 转换生成一个 entity,就可以 save 了
然后在去改造一下 controller 层
package com.lzl.study.scaffold.studyscaffold.user.controller;
import com.lzl.study.scaffold.studyscaffold.common.entity.R;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserPageDto;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserSaveDto;
import com.lzl.study.scaffold.studyscaffold.user.service.SysUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @ClassName SysUserController
* @Author lizelin
* @Description 用户管理 controller 层
* @Date 2023-10-09 20:00
* @Version 1.0
*/
@Slf4j
@RestController
@RequestMapping("sysUser")
@AllArgsConstructor
public class SysUserController {
private final SysUserService sysUserService;
/**
* @param dto
* @return com.baomidou.mybatisplus.extension.plugins.pagination.Page
* @Description 分页查询
* @author lizelin
* @date 2023-10-10 16:35
**/
@GetMapping("/page")
public R page(Page page) {
return R.success(sysUserService.page(page));
}
/**
* @param sysUserSaveDto
* @return com.lzl.study.scaffold.studyscaffold.common.entity.R
* @Description 新增
* @author lizelin
* @date 2023-10-10 16:35
**/
@PostMapping
public R add(@Validated @RequestBody SysUserSaveDto sysUserSaveDto) {
return R.success(sysUserService.dtoSave(sysUserSaveDto));
}
}
ok 这下新增就搞定了
2.2.3.2、查询处理
而第三个问题的分页,这个就和 2.2.2 的通用父类去存 ID 这些字段一样,由于你是一个前端传输后端接收的类,所以分页实际上是常用的,这样也可以抽取出一个父类来存储这些
package com.lzl.study.scaffold.studyscaffold.common.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @ClassName BaseVo
* @Author lizelin
* @Description vo 父类
* @Date 2023-10-09 23:42
* @Version 1.0
*/
@Data
public class BaseDto implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 每页显示条数,默认 10
*/
private long size = 10;
/**
* 当前页
*/
private long current = 1;
}
这里的话由于查询的时候条件肯定和新增不一样,所以我们还需要一个 page 的 DTO
package com.lzl.study.scaffold.studyscaffold.user.entity.dto;
import com.lzl.study.scaffold.studyscaffold.common.entity.BaseDto;
import lombok.Data;
/**
* @ClassName SysUserVo
* @Author lizelin
* @Description 用户管理 分页 DTO
* @Date 2023-10-09 23:40
* @Version 1.0
*/
@Data
public class SysUserPageDto extends BaseDto {
/**
* 姓名
*/
private String name;
/**
* 手机号
*/
private String phone;
/**
* 登录账号
*/
private String account;
/**
* 性别,0女1男2未知
*/
private Integer sex;
/**
* 身份证号码
*/
private String idCard;
/**
* 邮箱
*/
private String email;
/**
* 部门ID,不允许多部门
*/
private Long deptId;
/**
* 岗位ID集合,允许多岗位,传值为 1,2,3
*/
private String userPostIds;
/**
* 角色ID集合,允许多角色,传值为 1,2,3
*/
private String roleIds;
/**
* 用户状态 0为启用1为禁用
*/
private Integer userStatus;
/**
* 父部门ID
*/
private Long parentId;
}
然后我们去改造 service
package com.lzl.study.scaffold.studyscaffold.user.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lzl.study.scaffold.studyscaffold.user.entity.SysUserEntity;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserPageDto;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserSaveDto;
/**
* @ClassName UserService
* @Author lizelin
* @Description 用户管理 service
* @Date 2023-10-09 19:52
* @Version 1.0
*/
public interface SysUserService extends IService<SysUserEntity> {
/**
* @param sysUserSaveDto
* @return java.lang.Boolean
* @Description dto 新增
* @author lizelin
* @date 2023-10-10 0:07
**/
Boolean dtoSave(SysUserSaveDto sysUserSaveDto);
/**
* @param dto
* @return com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.lzl.study.scaffold.studyscaffold.user.entity.SysUserEntity>
* @Description dto 分页
* @author lizelin
* @date 2023-10-10 21:40
**/
Page<SysUserEntity> dtoPage(SysUserPageDto dto);
}
实现一下方法
package com.lzl.study.scaffold.studyscaffold.user.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lzl.study.scaffold.studyscaffold.common.util.QueryWrapperBuild;
import com.lzl.study.scaffold.studyscaffold.user.entity.SysUserEntity;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserPageDto;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserSaveDto;
import com.lzl.study.scaffold.studyscaffold.user.mapper.SysUserMapper;
import com.lzl.study.scaffold.studyscaffold.user.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @ClassName SysUserServiceImpl
* @Author lizelin
* @Description 用户管理 serviceImpl
* @Date 2023-10-09 19:58
* @Version 1.0
*/
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity> implements SysUserService {
/**
* @param sysUserSaveDto
* @return java.lang.Boolean
* @Description 通过 dto 新增
* @author lizelin
* @date 2023-10-10 0:08
**/
@Override
public Boolean dtoSave(SysUserSaveDto sysUserSaveDto) {
SysUserEntity entity = BeanUtil.copyProperties(sysUserSaveDto, SysUserEntity.class);
return save(entity);
}
/**
* @param dto
* @return com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.lzl.study.scaffold.studyscaffold.user.entity.vo.SysUserPageVo>
* @Description 分页查询
* @author lizelin
* @date 2023-10-10 17:44
**/
@Override
public Page<SysUserEntity> dtoPage(SysUserPageDto dto) {
SysUserEntity entity = BeanUtil.copyProperties(dto, SysUserEntity.class);
Page<SysUserEntity> page = BeanUtil.copyProperties(dto, Page.class);
return page(page, Wrappers.lambdaQuery(entity));
}
}
然后再去改造一下 controller
package com.lzl.study.scaffold.studyscaffold.user.controller;
import com.lzl.study.scaffold.studyscaffold.common.entity.R;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserPageDto;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserSaveDto;
import com.lzl.study.scaffold.studyscaffold.user.service.SysUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @ClassName SysUserController
* @Author lizelin
* @Description 用户管理 controller 层
* @Date 2023-10-09 20:00
* @Version 1.0
*/
@Slf4j
@RestController
@RequestMapping("sysUser")
@AllArgsConstructor
public class SysUserController {
private final SysUserService sysUserService;
/**
* @param dto
* @return com.baomidou.mybatisplus.extension.plugins.pagination.Page
* @Description 分页查询
* @author lizelin
* @date 2023-10-10 16:35
**/
@GetMapping("/page")
public R page(SysUserPageDto dto) {
return R.success(sysUserService.dtoPage(dto));
}
/**
* @param sysUserSaveDto
* @return com.lzl.study.scaffold.studyscaffold.common.entity.R
* @Description 新增
* @author lizelin
* @date 2023-10-10 16:35
**/
@PostMapping
public R add(@Validated @RequestBody SysUserSaveDto sysUserSaveDto) {
return R.success(sysUserService.dtoSave(sysUserSaveDto));
}
}
到这里查询也就没了问题
继续分析
新增我们有一些参数不希望前端传输,那么同理,后端传输给前端的时候,有些数据实际上我们也不希望前端获取到,或者是说分页的时候列表只需要展示这么多数据,而在 getById 的时候在把全部的数据读取出来,这个时候我们就需要 VO 来对前端展示的数据进行包装
而在 service 中我们是直接返回的 entity 实体
@Override
public Page<SysUserEntity> dtoPage(SysUserPageDto dto) {
SysUserEntity entity = BeanUtil.copyProperties(dto, SysUserEntity.class);
Page<SysUserEntity> page = BeanUtil.copyProperties(dto, Page.class);
return page(page, Wrappers.lambdaQuery(entity));
}
所以得将他改造为 vo 去返回
2.2.4、通用 VO 父类
首先还是老规矩,先新建一个父类
package com.lzl.study.scaffold.studyscaffold.common.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @ClassName BaseVo
* @Author lizelin
* @Description vo 父类
* @Date 2023-10-09 23:42
* @Version 1.0
*/
@Data
public class BaseVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
}
然后做一个分页列表的 vo 将需要展示在列表的字段进行存放
package com.lzl.study.scaffold.studyscaffold.user.entity.vo;
import com.lzl.study.scaffold.studyscaffold.common.entity.BaseVo;
import lombok.Data;
/**
* @ClassName SysUserVo
* @Author lizelin
* @Description 用户管理 vo
* @Date 2023-10-09 23:40
* @Version 1.0
*/
@Data
public class SysUserPageHomeVo extends BaseVo {
/**
* 姓名
*/
private String name;
/**
* 手机号
*/
private String phone;
/**
* 登录账号
*/
private String account;
/**
* 性别,0女1男2未知
*/
private Integer sex;
/**
* 部门ID,不允许多部门
*/
private Long deptId;
/**
* 岗位ID集合,允许多岗位,传值为 1,2,3
*/
private String userPostIds;
/**
* 角色ID集合,允许多角色,传值为 1,2,3
*/
private String roleIds;
/**
* 用户状态 0为启用1为禁用
*/
private Integer userStatus;
}
我们先做一个简单的转换,后面再改进
修改一下 service 的返回类型,这里就不贴代码了
然后修改一下实现
package com.lzl.study.scaffold.studyscaffold.user.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lzl.study.scaffold.studyscaffold.common.util.QueryWrapperBuild;
import com.lzl.study.scaffold.studyscaffold.user.entity.SysUserEntity;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserPageDto;
import com.lzl.study.scaffold.studyscaffold.user.entity.dto.SysUserSaveDto;
import com.lzl.study.scaffold.studyscaffold.user.entity.vo.SysUserPageHomeVo;
import com.lzl.study.scaffold.studyscaffold.user.mapper.SysUserMapper;
import com.lzl.study.scaffold.studyscaffold.user.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* @ClassName SysUserServiceImpl
* @Author lizelin
* @Description 用户管理 serviceImpl
* @Date 2023-10-09 19:58
* @Version 1.0
*/
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity> implements SysUserService {
/**
* @param sysUserSaveDto
* @return java.lang.Boolean
* @Description 通过 dto 新增
* @author lizelin
* @date 2023-10-10 0:08
**/
@Override
public Boolean dtoSave(SysUserSaveDto sysUserSaveDto) {
SysUserEntity entity = BeanUtil.copyProperties(sysUserSaveDto, SysUserEntity.class);
return save(entity);
}
/**
* @param dto
* @return com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.lzl.study.scaffold.studyscaffold.user.entity.vo.SysUserPageVo>
* @Description 分页查询
* @author lizelin
* @date 2023-10-10 17:44
**/
@Override
public Page<SysUserPageHomeVo> dtoPage(SysUserPageDto dto) {
SysUserEntity entity = BeanUtil.copyProperties(dto, SysUserEntity.class);
Page<SysUserEntity> page = BeanUtil.copyProperties(dto, Page.class);
page(page, Wrappers.lambdaQuery(entity));
List<SysUserEntity> records = page.getRecords();
//在这里做转换
Page<SysUserPageHomeVo> voPage = new Page<>();
BeanUtil.copyProperties(page,voPage);
voPage.setRecords(records.stream().map(item -> BeanUtil.copyProperties(item, SysUserPageHomeVo.class)).collect(Collectors.toList()));
return voPage;
}
}
这样转换就完成了
但是这里很明显还有一个问题,实际上我们数据库查出来的是全量的数据,只是向前端返回的时候少几个字段向外返回了而已,但是这玩意不纯纯浪费了么,你查都查出来的,所以这个地方下一章在改进
2.2.5、总结
首先讲一下 dto、entity、vo 之间的关系
所谓 entity 实际上就是 DO 也就是和数据库表一一对应的,只是我自己习惯了叫 entity 仅此而已
- 前端传参 后端接收参数为 DTO
- 操作数据库的参数为 DO
- 后端传输前端接收的参数为 VO
而他们的整体使用流程大概就是这个样子
- 前端传输,controller 层接收(DTO)
- controller 传输,service 接收(DTO)
- service 向 mapper 传输,mapper 接收(DO)(DTO 转 DO)
- mapper 返回,service 接收(DO)
- service 返回,controller 接收(VO)(DO 转VO)
- controller 返回,前端接收(VO)
大概就是这样的一个概念
2.3、留坑回顾
-
通用 vo 的转换需要改进
主要问题有两个
- 采用 BeanUtil 转换的效率不高(其实也可以不改进,这个性能差一丢丢)
- 这个转换如果不抽取公共的话,就会每次写查询的时候都要写这些东西,代码冗余
-
查数据库的时候是全量数据,向外展示为少几个字段,浪费问题改进