前言
后台开发中,一般的业务表都有创建人
,创建时间
,修改人
,修改时间
等业务字段,这些业务字段的值没有特别的逻辑,只是对当时的操作人和操作时间的一个记录。如果每个表格的增删改查,都去修改的这些值的话,难免会影响主业务逻辑的阅读。那么有没有一个统计的方法,自动地去赋予这些值,而不用在业务代码上进行干预呢?
JPA也提供了类似的审计功能。
拦截器
思路就是使用mybatis拦截器,每次和数据库通信前,在拦截器中自动赋予这些值。
使用注解标记字段
spring data中定义几个注解,来表明一个字段是需要审计的,它们是:
@CreatedDate
:创建时间@LastModifiedDate
:最后更新时间@CreatedBy
:创建人信息@LastModifiedBy
:最后更新人信息
拦截器的逻辑
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class AuditingInterceptor implements Interceptor {
private final String param1 = "param1"; //参数为map时,有param1这个键,具体原因不知道。
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
//找到数据表对应的PO
Object parameter = invocation.getArgs()[1];
Object po = null;
if (parameter instanceof Map) {
Map map = (Map) parameter;
if (map.containsKey(param1)) {
po = map.get(param1);
}
} else {
po = parameter;
}
if (po == null) {
return invocation.proceed();
}
//当前时间和操作人
LocalDateTime currentDate = LocalDateTime.now();
String currentUser = Optional.ofNullable(ShiroUtils.getSecurityUser()).map(SecurityUserPo::getUserName).orElse(null);
//遍历PO的字段,查找并修改其中被审计字段的值
Field[] fields = po.getClass().getDeclaredFields();
if (SqlCommandType.INSERT == sqlCommandType || SqlCommandType.UPDATE == sqlCommandType) {
for (Field field : fields) {
boolean accessible = field.isAccessible();
field.setAccessible(true);
if (AnnotationUtils.getAnnotation(field, CreatedBy.class) != null && SqlCommandType.INSERT == sqlCommandType && currentUser != null) {
field.set(po, currentUser);
}
if (AnnotationUtils.getAnnotation(field, CreatedDate.class) != null && SqlCommandType.INSERT == sqlCommandType) {
field.set(po, currentDate);
}
if (AnnotationUtils.getAnnotation(field, LastModifiedBy.class) != null && currentUser != null) {
field.set(po, currentUser);
}
if (AnnotationUtils.getAnnotation(field, LastModifiedDate.class) != null) {
field.set(po, currentDate);
}
field.setAccessible(accessible);
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
}
更多信息请参考mybatis插件。
总结
mybatis插件是个好用的功能,用得好的话可以达到意想不到的效果,大大减少编码量。