自动填充公共字段类的实现如下:
/**
* @author Zoe
* @description 自定义元数据处理器,用于实现公共字段自动填充
* @description 实现步骤:
* @description 1.在实体类属于公共字段的属性上加上@TableField,指定自动填充策略
* @description 2.按照框架要求编写元数据处理器,该类需要实现MetaObjectHandler接口,在此类中统一为公共字段赋值
* @date 2025/1/12
*/
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("公共字段自动填充[insert]……");
log.info(metaObject.toString());
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("createUser", BaseContext.getCurrentId());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("公共字段自动填充[update]……");
log.info(metaObject.toString());
// log.info("当前线程id:(MyMetaObjectHandler){}",Thread.currentThread().getId());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
}
这是一个controller:
/**
* 设置默认地址
*/
@PutMapping("default")
public R<AddressBook> setDefault(@RequestBody AddressBook addressBook) {
log.info("addressBook:{}", addressBook);
LambdaUpdateWrapper<AddressBook> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId());
wrapper.set(AddressBook::getIsDefault, 0);
// SQL:update address_book set is_default = 0 where user_id = ?
// 此处不会自动更新公共字段
addressBookService.update(wrapper);
addressBook.setIsDefault(1);
// SQL:UPDATE address_book SET is_default=?, update_time=?, update_user=? WHERE id=?
// 此处会连公共字段一起更新
addressBookService.updateById(addressBook);
return R.success(addressBook);
}
在代码中,两次更新操作对公共字段的自动填充表现不同,核心原因在于MyBatis-Plus的自动填充机制只对实体对象的字段生效,而对条件构造器(Wrapper)的更新不生效。具体分析如下:
1. addressBookService.update(wrapper); 不自动填充公共字段
- 该操作通过 LambdaUpdateWrapper 直接构造更新条件和字段(set(AddressBook::getIsDefault, 0)),本质是生成一条
UPDATE address_book SET is_default = 0 WHERE user_id = ?的SQL - 这种方式没有通过实体对象(AddressBook)设置字段,而是直接通过条件构造器指定更新内容,因此不会触发
MyMetaObjectHandler的自动填充逻辑(自动填充依赖实体对象的字段赋值)。所以公共字段(如updateTime、updateUser)不会被自动更新。
2. addressBookService.updateById(addressBook); 会自动填充公共字段
- 该操作通过实体对象 addressBook 进行更新,updateById 方法会将实体对象中的非空字段纳入更新范围。
- 由于实体类中,公共字段必然添加了 @TableField(fill = FieldFill.UPDATE) 注解(这是自动填充的前提),因此MyBatis-Plus 会在执行更新前调用MyMetaObjectHandler的
updateFill方法,自动为这些字段赋值。 - 最终生成SQL:
UPDATE address_book SET is_default=?, update_time=?, update_user=? WHERE id=?