二、从零开始-用户管理

二、从零开始-用户管理编写

导航

上一章地址:一、从零开始-初始化项目

下一章地址:三、从零开始-填坑

说明

  1. 贴代码时会贴整个类的全量代码,防止找不到我改的是哪个
  2. 创建的类在哪个包下不会单独说明,因为全量代码里有 package 直接看这个就可以了
  3. 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 来接收来自前端的传参,并且需要对参数进行校验,并且由于是前端传参接收,那么 分页也必须得有

也就是需要做三件事

  1. 新增的 dto 只保留允许添加的参数
  2. 对参数进行校验
  3. 分页参数

别问为什么不能直接拿 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

而他们的整体使用流程大概就是这个样子

  1. 前端传输,controller 层接收(DTO)
  2. controller 传输,service 接收(DTO)
  3. service 向 mapper 传输,mapper 接收(DO)(DTO 转 DO)
  4. mapper 返回,service 接收(DO)
  5. service 返回,controller 接收(VO)(DO 转VO)
  6. controller 返回,前端接收(VO)

大概就是这样的一个概念

2.3、留坑回顾

  1. 通用 vo 的转换需要改进

    主要问题有两个

    • 采用 BeanUtil 转换的效率不高(其实也可以不改进,这个性能差一丢丢)
    • 这个转换如果不抽取公共的话,就会每次写查询的时候都要写这些东西,代码冗余
  2. 查数据库的时候是全量数据,向外展示为少几个字段,浪费问题改进

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值