跟我学Springboot开发后端管理系统2:Mybatis-Plus实战2

2020/05/03

在上一篇文章讲述了如何使用Mybatis-plus自动生成代码,生成的代码具有单表操作数据库的能力,节约了开发时间。然后讲述了如何在Spring Boot中整合Mybatis-Plus。这篇文章讲述如何使用Mybatis-Plus的增强功能:自动填充功能和查询分页功能。

Mybatis-Plus自动填充功能

在Matrix-web项目中,数据库的所有表都有四个公共字段,即create_by、create_time、update_by、update_time ,即存储了表数据的创建人、创建时间、更新时间、更新人。在对表插入一条数据的时候,需要自动填充四个字段,对表数据更新操作,需要更新后2个字段。但是如果在每个插入和更新业务逻辑里面, 手动的填充这四个字段,增加了工作量。幸好mybatis-plus有一个自动更新的插件。

实现自动填充功能很简单,只需要实现MetaObjectHandler接口和实现填充逻辑,并把它注入到spring ioc容器中即可。其中下面的代码UserUtils.getCurrentUserWithDefault();即获取当前请求的用户,在权限那一篇文章有讲到过,在这里不再重复;然后加上注解@Component注入到Spring ioc容器里面去。

@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {



    @Override
    public void insertFill(MetaObject metaObject) {

        log.info("start insert fill ....");
        Object createBy = getFieldValByName("createBy", metaObject);
        Object updateBy = getFieldValByName("updateBy", metaObject);
        Object createTime = getFieldValByName("createTime", metaObject);
        Object updateTime = getFieldValByName("updateTime", metaObject);

        if (createBy == null) {
            this.setFieldValByName("createBy", UserUtils.getCurrentUserWithDefault(), metaObject);//版本号3.0.6以及之前的版本
        }
        if (updateBy == null) {
            this.setFieldValByName("updateBy", UserUtils.getCurrentUserWithDefault(), metaObject);
        }
        if (createTime == null) {
            this.setFieldValByName("createTime", new Date(), metaObject);
        }
        if (updateTime == null) {
            this.setFieldValByName("updateTime", new Date(), metaObject);
        }

    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        Object updateBy = getFieldValByName("updateBy", metaObject);
        Object updateTime = getFieldValByName("updateTime", metaObject);
        if (updateBy == null) {
            this.setFieldValByName("updateBy", UserUtils.getCurrentUserWithDefault(), metaObject);
        }
        if (updateTime == null) {
            this.setFieldValByName("updateTime", new Date(), metaObject);
        }
    }
}

  • 字段必须声明TableField注解,属性fill选择对应策略,该申明告知 Mybatis-Plus 需要预留注入 SQL 字段
  • 填充处理器MyMetaObjectHandler 在 Spring Boot 中需要声明@Component 注入
  • 必须使用父类的setFieldValByName()或者setInsertFieldValByName/setUpdateFieldValByName方法,否则不会根据注解FieldFill.xxx来区分。
public enum FieldFill {
    /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插入填充字段
     */
    INSERT,
    /**
     * 更新填充字段
     */
    UPDATE,
    /**
     * 插入和更新填充字段
     */
    INSERT_UPDATE
}

然后再表中映射的实体类,加上该上面的相应的注解即可,比如在Matrix-Web中所有数据库映射的实体类都继承BaseEntity。

@Data
public class BaseEntity {


    @JsonSerialize(using= ToStringSerializer.class)
    @TableId(value = "id", type = IdType.ID_WORKER)
    protected Long id;

    /**
     * 创建时间
     */
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    protected Date createTime;
    /**
     * 创建人id
     */
    @TableField(value = "create_by", fill = FieldFill.INSERT)
    protected String createBy;
    /**
     * 更新时间
     */
    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    protected Date updateTime;
    /**
     * 更新人
     */
    @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
    protected String updateBy;

}

比如SysUser实体类继承上面的BaseEntity。

@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class SysUser extends BaseEntity {
...
}

当调用SysUserMapper插入SysUser数据的时候,就会自动在数据库中插入create_by、create_time、update_by、update_time这四个数据。

分页插件

在Web开发中,经常用到分页插件。Mybatis-Plus提供了这样的能力。需要在spring ioc容器注入PaginationInterceptor,代码如下:

@Configuration
public class MybatisPlusConfig {
    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

现在以一个具体的案例来讲述如何分页。比如查询SysUser的分页。在Controller层:

@GetMapping("/pagelist")
public RespDTO searchUsers(@RequestParam int page, @RequestParam int pageSize, @RequestParam(required = false) String userId, @RequestParam(required = false) String realname) {
        PageUtils.check(page, pageSize);
        PageResultsDTO sysUsers = sysUserService.searchUsers(page, pageSize, userId, realname);
        return RespDTO.onSuc(sysUsers);
    }

在上面的代码中需要必传2个参数,page和pageSize,即页数和每页的数量。PageUtils.check(page, pageSize)是检查page和pageSize是否合理。RespDTO是返回给前端的DTO类。具体代码如下:

public class RespDTO<T> implements Serializable {
    public int code = 0;
    public String message = "";
    public T data;
    public String requestId;
}

PageResultsDTO是存放分页的数据和分页的元数据,代码如下:

public class PageResultsDTO<T> {
    public List<T> list = new ArrayList<>();
    public int page;
    public int pageSize;
    public long totalCount;
    public int offset;
    public int totalPage;
    
}

Sevice层代码,需要将sysUserMapper查询的数据包装到PageResultsDTO中代码如下:

  public PageResultsDTO searchUsers(int page, int pageSize, String userId, String realname) {
        Page<SysUser> sysLogPage = new Page<>(page, pageSize);
        IPage<SysUser> sysUserIPage = sysUserMapper.searchUsers(sysLogPage, userId, realname);
        PageResultsDTO result = new PageResultsDTO(page, pageSize);
        result.setTotalCount(sysUserIPage.getTotal());
        result.setTotalPage((int) sysUserIPage.getTotal(), pageSize);
        List<SysUser> records = sysUserIPage.getRecords();
        result.setList(transformSysUserDTO(records));
        return result;

    }

SysUserMapper的searchUsers方法会查询数据库,获取数据:

@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {


    IPage<SysUser> searchUsers(Page page, @Param("userId") String userId,
                               @Param("realname") String realname);
}

SysUserMapper的查询数据库的sql语句,需要自己写,在SysUserMapper.xml中,

    <select id="searchUsers" resultMap="BaseResultMap">
        SELECT a.id as id ,a.create_time as create_time, a.create_by as create_by,a.update_time as update_time,a.update_by as update_by
        ,a.user_id as user_id,a.password as password,a.realname as realname,a.type as type,a.mobile as mobile
        ,a.email as email,a.remarks as remarks ,a.status as status,a.avatar as avatar,a.sex as sex
        ,c.name as role_name,c.role_id as role_role_id ,e.org_id as org_id,e.simple_name as simple_name,g.code as code,g.url as url
        from sys_user a
        LEFT JOIN  sys_user_role b on a.user_id=b.user_id
        LEFT JOIN  sys_role c on b.role_id=c.role_id
        LEFT JOIN sys_user_org d on a.user_id=d.user_id
        left JOIN sys_org e on d.org_id =e.org_id
        left join sys_role_menu f on f.role_id=c.role_id
        left join sys_menu g on g.code=f.menu_code
        <where>
            <if test="userId != null and userId!='' ">
                a.user_id = #{userId}
            </if>

            <if test="realname != null and realname!='' ">
                AND a.realname = #{realname}
            </if>
        </where>
    </select>

这是完整的使用Mybatis-Plus插件分页的案例。前端代码就不在这里讲解了,在前端界面展示的分页效果如下:

总结

这篇文章讲述了如何使用Mybatis-Plus的增强功能,自动填充和分页。下篇文章将讲述如何使用Durid连接池和Sharding-JDBC实现数据库读写分离。

参加资料:

https://mp.baomidou.com/guide/#%E7%89%B9%E6%80%A7

源码下载

https://github.com/forezp/matrix-web

本文为原创文章,转载请标明出处。
本文链接:https://www.fangzhipeng.com/springboot/2020/05/03/mw-mybatis-plus2.html
本文出自方志朋的博客


(转载本站文章请注明作者和出处 方志朋-forezp

宝剑锋从磨砺出,梅花香自苦寒来,用心分享,一起成长,做有温度的攻城狮!

Post Directory