建议直接看原文MybatisPlus - updateFill (strictUpdateFill)更新时间 自动填充失败
之前写的文章@TableField(fill = FieldFill.INSERT)并没有细写MetaObjectHandler,这里补充一下(因为遇到bug了)
MP官方给出的自动填充插入和更新时间的方法
https://baomidou.com/pages/4c6bcf/
项目实际举例
第一:后端接收实体类,在继承的BaseEntity添加@TableField
package com.njry.sjzl.busi.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njry.base.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
@Data
@TableName("T_ATOM_TEMPLATE")
public class AtomTemplate extends BaseEntity implements Serializable {
@NotNull(groups = Update.class)
@TableId(value="template_id", type = IdType.INPUT)
@ApiModelProperty(value = "ID", hidden = true)
private Long id;
@ApiModelProperty(value = "模板id seq_t_atom_Template")
private String templateId;
@ApiModelProperty(value = "模板名称")
private String templateName;
@ApiModelProperty(value = "模板备注")
private String templateDesc;
@ApiModelProperty(value = "状态 1 有效 0 无效")
private Integer status;
@ApiModelProperty(value = "maxLevel")
private Integer maxLevel;
@ApiModelProperty(value = "排序")
private Long showOrder;
@ApiModelProperty(value = "路径")
private String path;
@ApiModelProperty(value = "组织表名称")
private String orgTable;
public void copy(AtomTemplate source){
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
}
}
package com.njry.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.LastModifiedBy;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.sql.Timestamp;
/**
* 通用字段, is_del 根据需求自行添加
* @author
* @Date 2024年05月11日
*/
@Getter
@Setter
public class BaseEntity implements Serializable {
@CreatedBy
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建人", hidden = true)
private String createBy;
@LastModifiedBy
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新人", hidden = true)
private String updateBy;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间", hidden = true)
private Timestamp createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间", hidden = true)
private Timestamp updateTime;
/* 分组校验 */
public @interface Create {}
/* 分组校验 */
public @interface Update {}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this)).append("\n");
}
} catch (Exception e) {
builder.append("toString builder encounter an error");
}
return builder.toString();
}
}
第二:自定义类继承MetaObjectHandler
package com.njry.config.mybatis;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.njry.utils.SecurityUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.sql.Timestamp;
/**
* @author wj
* @date 2024-05-11
**/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
/* 创建时间 */
this.strictInsertFill(metaObject, "createTime", Timestamp.class, DateTime.now().toTimestamp());
this.strictInsertFill(metaObject, "updateTime", Timestamp.class, DateTime.now().toTimestamp());
/* 任务管理加创建时间改个字段名称 */
this.strictInsertFill(metaObject, "createDate", Timestamp.class, DateTime.now().toTimestamp());
this.strictInsertFill(metaObject, "modifyDate", Timestamp.class, DateTime.now().toTimestamp());
/* 操作人 */
String username = "System";
try {username = SecurityUtils.getCurrentUsername();}catch (Exception ignored){}
this.strictInsertFill(metaObject, "createBy", String.class, username);
this.strictInsertFill(metaObject, "updateBy", String.class, username);
/* 任务管理加操作人改个字段名称 */
this.strictInsertFill(metaObject, "createOperator", String.class, username);
this.strictInsertFill(metaObject, "modifyOperator", String.class, username);
}
@Override
public void updateFill(MetaObject metaObject) {
/* 更新时间 */
this.strictUpdateFill(metaObject, "updateTime", Timestamp.class, DateTime.now().toTimestamp());
// this.setFieldValByName("updateTime", DateTime.now().toTimestamp(), metaObject);
/* 任务管理加更新时间改个字段名称 */
this.strictUpdateFill(metaObject, "modifyDate", Timestamp.class, DateTime.now().toTimestamp());
// this.setFieldValByName("modifyDate", DateTime.now().toTimestamp(), metaObject);
/* 操作人 */
String username = "System";
try {username = SecurityUtils.getCurrentUsername();}catch (Exception ignored){}
this.strictUpdateFill(metaObject, "updateBy", String.class, username);
// this.setFieldValByName("updateBy", username, metaObject);
/* 任务管理加操作人改个字段名称 */
this.strictUpdateFill(metaObject, "modifyOperator", String.class, username);
// this.setFieldValByName("modifyOperator", username, metaObject);
}
}
问题来了
插入数据时,插入时间和更新时间都发生了变化。
但是,在使用更新数据时,使用 this.strictUpdateFill(metaObject, “updateTime”, Timestamp.class, DateTime.now().toTimestamp()),数据库updata_time字段无法更新成功。
原因
官方文档给出注意事项:
MetaObjectHandler提供的默认方法的策略均为: 如果属性有值则不覆盖, 如果填充值为null则不填充。也就是说,MP的自动填充功能的前提是填充字段要求为null。
这确实是个大坑,而且是官方给的大坑,很烦。
解决办法
1、换方法,使用 this.setFieldValByName(“updateTime”, LocalDateTime.now(), metaObject);(最简单,使用老方法)
2、修改前设置数据库字段为null(麻烦)
3、自己重写源代码方法(有一定经验的小伙伴可以尝试,下面是断点找到在哪里修改)
debug更新
前段修改模版备注请求编辑
进入断点
这一步是过滤更新字段在不在当前实体类中,这就是可以在updateFill里面多次调用strictUpdateFill不用担心有的表数据有这个字段有的没有
我的是mybatis-plus3.5.3.1源码 MetaObjectHandler的处理(如下)
断点继续就执行下一个this.strictUpdateFill
我下一个更新字段是modifyDate,直接在第一步过滤就结束了,期许在罪魁祸首哪一步也结束了
结果就是bug
省事就用老方法setFieldValByName,修改源码改麻烦
interface MetaObjectHandler 的 setFieldValByName方法
default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) {
if (Objects.nonNull(fieldVal) && metaObject.hasSetter(fieldName)) {
metaObject.setValue(fieldName, fieldVal);
}
return this;
}