需求
如题,用Mybatis拦截器做公共字段的自动注入,这是我第一次使用Mybatis拦截器。之前做过一次自动注入,是用的自定义注解,然后用AOP拦截注入的。
- 注意:这一版是我写的第一版。都是写死的字段,很废物,下一遍会写一个注解版,稍微能通用一点…
- 需要注入的字段:
字段 | 备注 |
---|---|
created_by | 创建人 |
created_time | 创建时间 |
updated_by | 修改人 |
updated_time | 修改时间 |
思路
- 因为是公共字段,所以抽一个基类,将这些公共字段放到基类中
- 在拦截器中,通过反射机制递归获取对象及其基类的所有字段,遍历获取到的字段数组,判断字段名,如果跟我们的字段一致则注入。
- 前端提交请求时传一个updatedBy。新增时拦截器将updatedBy注入到createdBy中
实现
- 反射工具类
public class ReflectUtil {
public static Field[] getAllFields(Object object){
Class clazz = object.getClass();
List<Field> fieldList = new ArrayList<>();
while (clazz != null){
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
clazz = clazz.getSuperclass();
}
Field[] fields = new Field[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
public static Field[] getAllFields(Class clazz){
List<Field> fieldList = new ArrayList<>();
while (clazz != null){
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
clazz = clazz.getSuperclass();
}
Field[] fields = new Field[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
}
- 拦截器
@Intercepts({@Signature(type = Executor.class, method = "update"
, args = {MappedStatement.class, Object.class})})
public class StuffInterceptorFirst implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
if (invocation.getTarget() instanceof Executor && invocation.getArgs().length == 2) {
final Executor executor = (Executor) invocation.getTarget();
// 获取第一个参数
final MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
final Object paramObj = invocation.getArgs()[1];
if (ms.getSqlCommandType() == SqlCommandType.INSERT) {
return this.executeInsert(executor, ms, paramObj);
} else if (ms.getSqlCommandType() == SqlCommandType.UPDATE) {
return this.executeUpdate(executor, ms, paramObj);
}
}
return invocation.proceed();
}
@Override
public Object plugin(final Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
/**
* 新增操作
*
* @param executor executor
* @param ms ms
* @param paramObj 参数
* @return 返回执行结果
*/
private Object executeInsert(final Executor executor, final MappedStatement ms, final Object paramObj) throws Exception {
final BaseEntity baseEntity = (BaseEntity)paramObj;
// 获取对象的所有字段
final Field[] fields = ReflectUtil.getAllFields(paramObj);
// 遍历获取到的字段,根据字段名判断注入
for (final Field field : fields) {
field.setAccessible(true);
final String fieldName = field.getName();
switch (fieldName) {
case "createdBy":
field.set(paramObj, baseEntity.getUpdatedBy());
break;
case "createdTime":
field.set(paramObj, new Date());
break;
case "updatedBy":
field.set(paramObj, baseEntity.getUpdatedBy());
break;
case "updatedTime":
field.set(paramObj, new Date());
break;
default:
break;
}
}
return executor.update(ms, paramObj);
}
/**
* 修改操作
*
* @param executor executor
* @param ms ms
* @param paramObj 参数
* @return 返回执行结果
*/
private Object executeUpdate(final Executor executor, final MappedStatement ms, final Object paramObj) throws Exception {
final BaseEntity baseEntity = (BaseEntity)paramObj;
final Field[] fields = ReflectUtil.getAllFields(paramObj);
for (final Field field : fields) {
field.setAccessible(true);
final String fieldName = field.getName();
switch (fieldName) {
case "updatedBy":
field.set(paramObj, baseEntity.getUpdatedBy());
break;
case "updatedTime":
field.set(paramObj, new Date());
break;
default:
break;
}
}
return executor.update(ms, paramObj);
}
}
- 配置类
@Configuration
public class InterceptorConfig {
@Bean
public Interceptor interceptor() {
return new StuffInterceptor();
}
}
缺点
- 字段名都写死了,换一个项目或者项目修改一下就要跟着修改了。
- 要注入的内容还得让前端传,老奇怪了…
收获
主要是稍微了解了一下mybatis拦截器的使用吧