用户自定义的拦截器也被称为 MyBatis 插件。
有些公司对数据表的表结构有一些规范,要求数据表必须包含某些字段,如创建人姓名(create_by)、创建时间(create_time)、编辑人姓名(update_by)、最后编辑时间(update_time)等。
怎样设置这些公共字段的属性值呢?
最无脑的做法是在每次新增或者编辑数据时手动设置这些字段的属性值。这样做确实可以实现功能,但是重复代码太多,不够优雅。
有没有比较简便、稍微优雅点的方式呢?
当然是有的。
因为我们数据库持久层框架使用的是 MyBatis,我们可以使用 MyBatis 的 拦截器(Interceptor)来实现此功能。
拦截器代码实现
我们定义了一个实体类BaseEntity,所有实体继承该实体。
BaseEntity.java —— Entity基类
/**
* Entity基类
* @author wanggc
*/
@Data
public class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
/** 创建者 */
private String createBy;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/** 更新者 */
private String updateBy;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
BaseEntityInterceptor.java —— 自定义 Mybatis 拦截器
@Slf4j
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class BaseEntityInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object parameter = invocation.getArgs()[1];
if (parameter instanceof BaseEntity) {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String currentUsername = null;
if (principal instanceof UserDetailsImpl) {
UserDetailsImpl userDetails = (UserDetailsImpl) principal;
currentUsername = userDetails.getUsername();
}
// if (Objects.nonNull(userDetails)) {
// log.info("current user info: {}", new Gson().toJson(userDetails));
// }
BaseEntity baseEntity = (BaseEntity) parameter;
if (Objects.equals(SqlCommandType.INSERT, mappedStatement.getSqlCommandType())) {
baseEntity.setCreateBy(currentUsername);
baseEntity.setCreateTime(new Date());
} else if (Objects.equals(SqlCommandType.UPDATE, mappedStatement.getSqlCommandType())) {
baseEntity.setUpdateBy(currentUsername);
baseEntity.setUpdateTime(new Date());
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// Interceptor.super.setProperties(properties);
}
}
拦截器配置
在 MyBatis 的配置文件里配置自定义拦截器:
<plugins>
<plugin interceptor="com.jasmine.plugin.BaseEntityInterceptor" />
</plugins>
这样,我们在新增或者修改数据的时候,公共字段就自动赋值了。