SpringBoot 版本:2.6.4
MybatisPlus 版本:3.5.1
在真实的项目里,表结构中一般会存在一些公司内部约定的公共字段,比如:创建时间,创建人,修改时间,修改人等,记录这些数据一方面可以出现问题时进行溯源,也可以提供给大数据收集。
不管怎样,这是目前大部分公司选择的方案。
通常公司的框架会有一个上下文对象,存储了当前登录人信息,每次新增或者修改数据库记录,可以从上下文中获取当前登录人信息,填充创建时间,创建人这些信息。但如果每次都需要手动去写这些业务无关的内容,重复且繁琐,而且还容易出错。
假设增加 createTime、createUser、updateTime、updateUser 四个字段用来记录创建时间,创建人,修改时间,修改人信息。
数据库脚本
CREATE TABLE user (
`id` BIGINT(20) NOT NULL COMMENT '主键',
`name` VARCHAR(32) NOT NULL COMMENT '姓名',
`age` SMALLINT(4) NOT NULL DEFAULT '0' COMMENT '年龄',
`email` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '邮箱',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`create_user` VARCHAR(32) NOT NULL COMMENT '创建人',
`update_time` DATETIME NOT NULL COMMENT '最近更新时间',
`update_user` VARCHAR(32) NOT NULL COMMENT '最近更新人',
PRIMARY KEY (id)
)
第一步:设置 @TableField 注解的 FieldFill 属性
其实每个字段都默认设置了一个 @TableField,所以 MybatisPlus 实体类中的字段都必须与数据库表中的字段对应,可以少,但不能多,多出来的字段必须设置 @TableField(exist = false)。
@TableField 注解中还有一个属性 fill,就是用于支持自动填充功能,可选择的值有四个
根据本次的需求,为 createTime、createUser、updateTime、updateUser 四个字段分别添加自动填充策略
@Data
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT)
private String createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateUser;
}
第二步:实现 MetaObjectHandler 接口
通过第一步,设置好的填充的时机,但具体该填充什么值,则需要实现 MetaObjectHandler 接口(为了简化,这里处理人姓名写死了,正常可以通过上下文进行获取)。
这个类需要注册到 Spring 容器中
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
// 新增时填充
@Override
public void insertFill(MetaObject metaObject) {
LocalDateTime now = LocalDateTime.now();
this.strictInsertFill(metaObject, "createTime", () -> now, LocalDateTime.class);
this.strictInsertFill(metaObject, "createUser", () -> "haha", String.class);
this.strictInsertFill(metaObject, "updateTime", () -> now, LocalDateTime.class);
this.strictInsertFill(metaObject, "updateUser", () -> "haha", String.class);
}
// 修改时填充
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
this.strictUpdateFill(metaObject, "updateUser", () -> "haha", String.class);
}
}
MetaObjectHandler 中声明填充的字段,如果实体类中有,则会进行填充,如果没有,也可以正常运行,填充动作被忽略
编写测试用例
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class MybatisPlusTest {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert() {
User user = new User();
user.setId(10);
user.setUsername("test");
userMapper.insert(user);
}
}
查看日志输出如下,deleted 查询条件已自动加上
==> Preparing: INSERT INTO user (id, name, create_time, create_user, update_time, update_user) VALUES ( ?, ?, ?, ?, ?, ? )
==> Parameters: 10(Long), test(String), 2022-03-11T20:32:31.532(LocalDateTime), haha(String), 2022-03-11T20:32:31.532(LocalDateTime), haha(String)
<== Updates: 1
修改的测试用例请自行编写
自动填充主要用途还是将一些与业务无关的字段,使用公共代码进行填充,减少业务处理时还要兼顾非业务字段,让业务代码更纯粹。
MybatisPlus 支持的逻辑删除功能,新增时需要对逻辑删除标记字段填充一个默认值,也可以使用自动填充功能进行填充。