MyBatisPlus通过@TableField的fill属性和实现MetaObjectHandler完成自动填充字段,更新字段失败bug修复

mybatisPlus自动填充字段,例如创建日期

平时我在写代码的时候,我们系统的大部分表都是由createTime,createBy,updateTime,updateBy等通用字段,于是我写了一个通用的抽象类,将这几个属性放到抽象类里面,让有这几个字段的数据库实体类都来继承这个抽象类,但是后来我发现一个问题,就是我每次在新增数据或者更新数据的时候都要对这几个字段手动赋值,例如:

object.setCreateTime(new Date());
object.setCreateBy("cc");

以上代码基本上再我写的每一个模块都有,并且基本上是一模一样的,于是我在查看myBatisplus的@TableField注解有哪些属性的时候就发现了一个属性——fill,该属性的意思就是填充,填满,所以我上网搜索了一下该属性的用法,发现可以解决我上述的问题,下面介绍一下这个属性的用法。

fill的值为一个枚举类——FieldFill,源码如下:

public enum FieldFill {
    DEFAULT,
    INSERT,
    UPDATE,
    INSERT_UPDATE;

    private FieldFill() {
    }
}

字段含义如下:

枚举值含义
DEFAULT默认值,不对字段做自动填充
INSERT只在执行插入操作时进行字段填充
UPDATE只在执行更新操作时进行字段填充
INSERT_UPDATE在执行插入和更新操作时都进行字段填充

用法如下:

在需要进行自动填充的字段上添加@TableField注解,填充fill属性值,填充策略根据自己的业务决定。

@Data
public abstract class BaseEntity {
    /**
     * 创建者
     */
    @TableField(fill = FieldFill.INSERT)
    private String createBy;

    /**
     * 创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    /**
     * 更新者
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String updateBy;

    /**
     * 更新时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}

实现MetaObjectHandler接口,重写insertFill方法和updateFill方法。

@Component
public class MybatisPlusHandler implements MetaObjectHandler {
    private final static String CREATE_TIME = "createTime";
    private final static String CREATE_BY = "createBy";
    private final static String UPDATE_TIME = "updateTime";
    private final static String UPDATE_BY = "updateBy";
    private final static String ADMIN = "admin";
    
    @Override
    public void insertFill(MetaObject metaObject) {
        // 新增数据时若对应字段没有值(空串或null)时,以下代码会对该字段进行自动填充
        // 时间的自动填充,时间默认填充当前时区系统时间
        LocalDateTime localDateTime = LocalDateTime.now();
        Date now = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        this.strictInsertFill(metaObject, CREATE_TIME, Date.class, now);
        this.strictInsertFill(metaObject, UPDATE_TIME, Date.class, now);

        // 操作用户名填充
        this.strictInsertFill(metaObject, CREATE_BY, String.class, ADMIN);
        this.strictInsertFill(metaObject, UPDATE_BY, String.class, ADMIN);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 修改数据时无论字段是否有值,都会对该字段进行自动填充,时间默认填充当前时区系统时间
        // 时间的自动填充,时间默认填充当前时区系统时间
        LocalDateTime localDateTime = LocalDateTime.now();
        Date now = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        this.setFieldValByName(UPDATE_TIME, now, metaObject);

        // 操作用户名填充
        this.setFieldValByName(UPDATE_BY, adminName, metaObject);
	
        this.strictUpdateFill(metaObject, "updateBy", String.class, ADMIN);
    }
}

在上述示例中,@TableField 注解的 fill 属性分别使用了 FieldFill.INSERTFieldFill.INSERT_UPDATE 两种枚举值,表示在执行数据库的插入和更新操作时,分别针对 createTimeupdateTimecreateByupdateBy字段进行相应的自动填充操作。

需要注意的是,使用FieldFill.INSERT_UPDATE这种方式进行自动填充的时候需要在insertFill方法和updateFill方法中都对使用了该属性的字段做自动填充处理,例如上面代码中的updateTime和updateBy两个字段,如果只在insertFill方法中实现那么在新增一条数据的时候updateTime和updateBy这两个字段就没有值,这是我在自己实际应用中碰到的一个奇怪的问题。

相信读者在看到上述代码时可能会提出疑问,为什么实现insertFill()方法的时候,填充数据用的是this.strictInsertFill()方法,而实现udpateFill()方法的时候,填充数据用的却是this.setFieldValByName(),为什么不用this.strictupdateFill()方法呢,原因就是使用this.strictInsertFill()和this.strictupdateFill()方法的时候,当当前设置的字段有值的时候,不会对其进行数据的填充,这对于插入数据的逻辑是正确的,但是修改数据就不对了,我们希望的是无论字段是否有值,都对该字段进行填充,例如更新时间这种字段,所以this.strictupdateFill()方法就满足不了我们的需求,需要改为this.setFieldValByName()来进行更新数据类型的数据填充。

为什么this.strictInsertFill()和this.strictupdateFill()这两个方法只能对字段值为空的数据进行填充可以参见下面MyBatisPlus的源码,这两个方法最终都会调用到这个方法,这个方法里首先根据字段名去拿了该字段的值,如果字段值为空就直接返回该对象,不设置值,如果为空,并且传入的fieldVal不为空,那就将字段值设置为我们传进去的入参!

default MetaObjectHandler strictFillStrategy(MetaObject metaObject, String fieldName, Supplier<?> fieldVal) {
        if (metaObject.getValue(fieldName) == null) {
            Object obj = fieldVal.get();
            if (Objects.nonNull(obj)) {
                metaObject.setValue(fieldName, obj);
            }
        }

        return this;
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值