MybatisPlus 统一管理创建人、更新人、创建时间、更新时间等公共字段

 开发过程中的问题

       1. 在设计数据库模型的时候,我们通常会在表中创建创建人、创建时间、更新人、更新时间等通用的字段来记录每行数据的创建和变动信息。比如在 inset 和 update 过程方法中要不停的set的创建时间字段或更新时间字段等公共信息。

       2.  并且,如果有大量的表,每个表都有这些公共字段,不论是在创建或者更新的时候都是重复繁琐的操作,让人难受。

针对问题1,我们可以通过代码自动生成创建人、更新人、创建时间、更新时间等公共字段的信息,来减少开发者的工作量(大量使用set方法)。

针对问题2,我们可以将大量表中的重复的公共字段抽取出来,做一个通用字段的bean类型,在java中让它成为父类,让其他表继承。

实现:

1. 抽取公共字段创建父类基础模型

例如,有 im_base_entity 表,表中有些字段与其他表中字段一致(主要根据实际业务区分):创建人、更新人、创建时间、更新时间、逻辑删除

CREATE TABLE `im_base_entity`  (
  `id` int(11) NOT NULL COMMENT '主键',
  `username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `password` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  `creator` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者',
  `updater` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新者',
  `deleted` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '逻辑删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;

将重复字段抽取,并创建java的父类基础模型

package org.example.bean;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 数据库模型设计时抽出所有通用字段,抽象为父类
 */
@Data
public abstract class BaseEntity implements Serializable {

    /**
     * 创建时间
     * 意思是新建的时候插入
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    /**
     * 最后更新时间
     * 意思是新建和修改的时候插入
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    /**
     * 创建者,目前使用 SysUser 的 id 编号
     * 意思是新建的时候插入
     * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
     */
    @TableField(fill = FieldFill.INSERT)
    private String creator;
    /**
     * 更新者,目前使用 SysUser 的 id 编号
     * 意思是新建和修改的时候插入
     * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String updater;
    /**
     * 是否删除
     * 框架提供的逻辑删除注解。如果使用delete关键字,会报错
     * 如果进行查询,会过滤被逻辑删除的字段!
     *  0 未删除
     *  1 已删除
     */
    @TableLogic
    private Boolean deleted;

}

2. java中所有业务实体继承该父类基础模型

注意:这里继承了父类 BaseEntity,所以可以不用在创建公共字段的声明了。但是在数据库表中公共字段还是要有的。

package org.example.bean;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;

/**
 * autoResultMap = true
 *  如果数据库是json类型的字段,同时autoResultMap=true,
 *      那么在select的时候,数据库json字段对应的实体类字段可以直接映射,
 *          该字段类型可以是某个类,也可以是List。
 *
 * @EqualsAndHashCode(callSuper = true)
 *      该注解用于子类对象之间进行比较的时候,如果不加这个注解,当创建俩个 MyTableEntity 对象时,
 *          这俩个对象比较是相等的,即使给这俩个对象设置了不同的值。
 *
 *  @Builder
 *      为你的类生成相对略微复杂的构建器API。
 *          可以让你以下面显示的那样调用你的代码,来初始化你的实例对象:
 *             MyTableEntity.builder()
 *                    .id( "001" )
 *                    .password( "110" )
 *                    .build();
 */
@TableName(value = "im_base_entity", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MyTableEntity extends BaseEntity {

    /**
     * 用户ID
     */
    @TableId
    private Long id;
    /**
     * 用户账号
     */
    private String username;
    /**
     * 加密后的密码
     */
    private String password;

}

3. 实现 MetaObjectHandler 接口,(元对象字段填充控制器抽象类),实现公共字段自动写入功能

package org.example.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.log4j.Log4j;
import org.apache.ibatis.reflection.MetaObject;
import org.example.bean.LoginUser;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Objects;

/**
 * 如果没有显式的对通用参数进行赋值,这里会对通用参数进行填充、赋值
 */
@Log4j
@Component
public class DefaultDBFieldHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        // 可以通过 getFieldValByName()方法判断
       // Object modifyTime = getFieldValByName("updateTime", metaObject);
        log.info("进入创建");
        // 获取当前用户信息
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("creator",loginUser.getUser().getUserName(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
        this.setFieldValByName("updater",loginUser.getUser().getUserName(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 更新时间为空,则以当前时间为更新时间
        Object modifyTime = getFieldValByName("updateTime", metaObject);
        if (Objects.isNull(modifyTime)) {
            setFieldValByName("updateTime", new Date(), metaObject);
        }
        // 当前登录用户不为空,更新人为空,则当前登录用户为更新人
        Object modifier = getFieldValByName("updater", metaObject);
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String userId = loginUser.getUser().getUserName();
        if (Objects.nonNull(userId) && Objects.isNull(modifier)) {
            setFieldValByName("updater", userId.toString(), metaObject);
        }
    }
}

注意:

使用 @TableLogic 注解后,如果使用delete关键字,会报错 ,如果进行查询,会过滤被逻辑删除的字段。但是需要在yml中配置

mybatis-plus:
  configuration:
    #开启驼峰命名
    map-underscore-to-camel-case: true
  mapper-locations: classpath*:/mapper/*.xml
  global-config:
    db-config:
      logic-delete-field: flag  #全局逻辑删除字段值 3.3.0开始支持,详情看下面。
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

配置完成后,添加业务,创建和更新 im_base_entity 表,进行测试,自动添加了。

至此完毕。 

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在实体类中,我们可以使用注解和AOP等方式来实现自动给公共字段赋值的功能。下面是一个示例: ```java import java.util.Date; public class BaseEntity { private Long id; private String createBy; private Date createTime; private String updateBy; private Date updateTime; // 在实体类持久化之前,自动设置createBy、createTime、updateBy、updateTime @PrePersist public void prePersist() { createTime = updateTime = new Date(); createBy = updateBy = "system"; } // 在实体类更新之前,自动设置updateBy、updateTime @PreUpdate public void preUpdate() { updateTime = new Date(); updateBy = "system"; } // 省略getter和setter方法 } ``` 上述代码中,使用了JPA提供的注解 `@PrePersist` 和 `@PreUpdate` 标注了 `prePersist()` 和 `preUpdate()` 方法,这两个方法在实体类被持久化前和更新前自动调用。在这两个方法中,我们可以编写代码来实现自动给公共字段赋值的功能。 在 `prePersist()` 方法中,我们使用 `new Date()` 方法来获取当前时间,并将其赋值给 `createTime` 和 `updateTime` 字段。同时,我们将 `createBy` 和 `updateBy` 字段赋值为 "system",表示是系统自动创建更新的。 在 `preUpdate()` 方法中,我们同样使用 `new Date()` 方法来获取当前时间,并将其赋值给 `updateTime` 字段。同时,我们将 `updateBy` 字段赋值为 "system",表示是系统自动更新的。 需要注意的是,上述代码中的字段和默认值都是示例,具体情况需要根据实际需求进行调整。同时,如果需要自动获取当前登录用户信息,可以使用AOP等方式来实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值