一、前言
在項目中,我們有一些公共的字段需要做修改。如:
- gmt_create:創建時間
- creator_id:創建人
- gmt_modified:修改時間
- modifier_id:修改人
這時候我們可以採用 MyBatis-Plus 中的字段自動填充功能去實現
思路:抽取公用字段封裝到BaseEntity類中,再將使用到此公共字段的類繼承基類,最後由 MyBatis-Plus 幫我們實現自動填充,這樣我們便可以在service服務類中減少一定代碼重複量!
二、實現
@Data
@TableName("t_user")
public class User extends BaseEntity<User> {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField("username")
private String username;
@Override
protected Serializable pkVal() {
return this.id;
}
}
2. 公用字段 - 使用註解填充字段,如:@TableField(fill = FieldFill.INSERT)
@Getter
@Setter
public abstract class BaseEntity<T extends Model> extends Model {
/**
* 創建日期 - 現在時表示主動創建
*/
@TableField(value = "gmt_create", fill = FieldFill.INSERT)
private Date gmtCreate;
/**
* 修改時間 - 過去分詞表示被動更新
*/
@TableField(value = "gmt_modified", fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
}
Ctrl 選中FieldFill
進入源碼可查看相應字段填充策略枚舉類,如下:
public enum FieldFill {
DEFAULT(0, "默認不處理"),
INSERT(1, "插入填充字段"),
UPDATE(2, "更新填充字段"),
INSERT_UPDATE(3, "插入和更新填充字段");
/**
* 主鍵
*/
private final int key;
/**
* 描述
*/
private final String desc;
FieldFill(final int key, final String desc) {
this.key = key;
this.desc = desc;
}
public static FieldFill getIgnore(int key) {
FieldFill[] fis = FieldFill.values();
for (FieldFill fi : fis) {
if (fi.getKey() == key) {
return fi;
}
}
return FieldFill.DEFAULT;
}
public int getKey() {
return this.key;
}
public String getDesc() {
return this.desc;
}
}
3. 自定義MyMetaObjectHandler
字段自動填充處理類繼承MetaObjectHandler
- 注:在 Spring Boot 中需要聲明 @Component 注入
/**
* <p> MyBatisPlus自定義字段自動填充處理類 - 實體類中使用 @TableField註解 </p>
*
* @description: 注意前端傳值時要爲null
* @author: zhengqing
* @date: 2019/8/18 0018 1:46
*/
@Component
public class MyMetaObjectHandler extends MetaObjectHandler {
private static final Logger LOG = LoggerFactory.getLogger(MyMetaObjectHandler.class);
/**
* 創建時間
*/
@Override
public void insertFill(MetaObject metaObject) {
LOG.info(" -------------------- start insert fill ... --------------------");
if (metaObject.hasGetter("gmtCreate") && metaObject.hasGetter("gmtModified")) {
setFieldValByName("gmtCreate", new Date(), metaObject);
setFieldValByName("gmtModified", new Date(), metaObject);
}
}
/**
* 最後一次更新時間
*/
@Override
public void updateFill(MetaObject metaObject) {
LOG.info(" -------------------- start update fill ... --------------------");
if (metaObject.hasGetter("et.gmtModified")) {
setFieldValByName("gmtModified", new Date(), metaObject);
}
}
}
溫馨小提示
我們在更新字段的時候要使用 et.字段名
或者 param1.字段
纔會生效!
原因:我們可以debug模式查看metaObject
中的屬性發現多了et
或者查看繼承的BaseMapper類源碼,我們也可以發現更新的方法中都有et
而插入的方法並沒有et
另外一個注意點就是,自動填充是在執行完插入或更新方法之後,也就是說,MyBatis-Plus會在方法之後判斷@TableField
註解的字段有沒有被手動更新,如果沒有才會走自定義的實現類MyMetaObjectHandler
!
補充(不同實體類“表名_createTime”)
自動判斷解決方案
package com.chinadaas.platform.common.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* @author Lux Sun
* @date 2020/6/16
*/
@Component
public class DspMetaObjectHandler implements MetaObjectHandler {
private String getClassLikeFieldName(MetaObject metaObject, String likeStr) {
Field[] fields;
if (metaObject.hasSetter("et") && metaObject.hasSetter("param1")) { // update case
fields = ((MapperMethod.ParamMap)metaObject.getOriginalObject()).get("et").getClass().getDeclaredFields();
}
else { // insert case
fields = metaObject.getOriginalObject().getClass().getDeclaredFields();
}
for (int i=0; i<fields.length; i++) {
if (fields[i].getName().endsWith(likeStr)) {
return fields[i].getName();
}
}
return null;
}
@Override
public void insertFill(MetaObject metaObject) {
String key = "Del";
key = getClassLikeFieldName(metaObject, key);
if (Objects.nonNull(key) && metaObject.hasSetter(key)) {
Object del = getFieldValByName(key, metaObject);
if (Objects.nonNull(del)) {
setInsertFieldValByName(key, del, metaObject);
}
else {
setInsertFieldValByName(key, Byte.valueOf("0"), metaObject);
}
}
key = "Createtime";
key = getClassLikeFieldName(metaObject, key);
if (Objects.nonNull(key) && metaObject.hasSetter(key)) {
Object createTime = getFieldValByName(key, metaObject);
if (Objects.nonNull(createTime)) {
setInsertFieldValByName(key, createTime, metaObject);
}
else {
setInsertFieldValByName(key, LocalDateTime.now(), metaObject);
}
}
key = "Updatetime";
key = getClassLikeFieldName(metaObject, key);
if (Objects.nonNull(key) && metaObject.hasSetter(key)) {
Object updateTime = getFieldValByName(key, metaObject);
if (Objects.nonNull(updateTime)) {
setInsertFieldValByName(key, updateTime, metaObject);
}
else {
setInsertFieldValByName(key, LocalDateTime.now(), metaObject);
}
}
}
@Override
public void updateFill(MetaObject metaObject) {
String key = "Updatetime";
key = getClassLikeFieldName(metaObject, key);
if (Objects.nonNull(key) && metaObject.hasSetter(key)) {
Object updateTime = getFieldValByName(key, metaObject);
if (Objects.nonNull(updateTime)) {
setUpdateFieldValByName(key, updateTime, metaObject);
}
else {
setUpdateFieldValByName(key, LocalDateTime.now(), metaObject);
}
}
}
}