介绍
在进行数据insert或update时,有些字段需要自动进行填充,比如创建时间、创建人、更新时间、更新人等字段。
实现思路
- 首先实现Interceptor接口,实现其intercept方法。 获取当前执行的SQL命令类型(SqlCommandType)和参数对象(parameter),用于判断是否需要填充数据。
- 过滤掉参数为空,用户未登录或无登录信息,直接跳过字段填充。
- 根据参数对象类型,如是Map,遍历出Object。
- 通过反射获取对象的所有字段,包括父类字段,再根据SQL类型,处理字段填充。
- 在字段填充过程中try catch。
- 返回代理对象与属性设置。
实现
ts
/**
* 填充createBy,createTime等公共字段的拦截器
*/
/**
* Intercepts注解需要一个Signature(拦截点)参数数组。通过Signature来指定拦截哪个对象里面的哪个方法
*/
@Component
@Slf4j
@Intercepts({@Signature(type = Executor.class, method = "update", args = {
MappedStatement.class, Object.class
})})
public class MybatisInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
Object parameter = invocation.getArgs()[1];
if (parameter == null) {
return invocation.proceed();
}
//获取当前登录用户的id
String loginId = LoginUtil.getLoginId();
if (StringUtils.isBlank(loginId)) {
return invocation.proceed();
}
if (sqlCommandType == SqlCommandType.INSERT || sqlCommandType == SqlCommandType.UPDATE) {
replaceEntityProperty(parameter, loginId, sqlCommandType);
}
return invocation.proceed();
}
private void replaceEntityProperty(Object parameter, String loginId, SqlCommandType sqlCommandType) {
if (parameter instanceof Map) {
replaceMap((Map) parameter, loginId, sqlCommandType);
} else {
replace(parameter, loginId, sqlCommandType);
}
}
private void replaceMap(Map parameter, String loginId, SqlCommandType sqlCommandType) {
for (Object val : parameter.values()) {
replace(val, loginId, sqlCommandType);
}
}
private void replace(Object parameter, String loginId, SqlCommandType sqlCommandType) {
if (sqlCommandType == SqlCommandType.INSERT) {
dealInsert(parameter, loginId);
} else {
dealUpdate(parameter, loginId);
}
}
private void dealUpdate(Object parameter, String loginId) {
Field[] fields = getAllFields(parameter);
for (Field field : fields) {
try {
field.setAccessible(true);
Object o = field.get(parameter);
if (Objects.nonNull(o)) {
field.setAccessible(false);
continue;
}
//填充数据
if ("updateBy".equals(field.getName())) {
field.set(parameter, loginId);
field.setAccessible(false);
} else if ("updateTime".equals(field.getName())) {
field.set(parameter, new Date());
field.setAccessible(false);
} else {
field.setAccessible(false);
}
} catch (Exception e) {
log.error("dealUpdate.error:{}", e.getMessage(), e);
}
}
}
private void dealInsert(Object parameter, String loginId) {
Field[] fields = getAllFields(parameter);
for (Field field : fields) {
try {
field.setAccessible(true);
Object o = field.get(parameter);
if (Objects.nonNull(o)) {
field.setAccessible(false);
continue;
}
//填充数据
if ("isDeleted".equals(field.getName())) {
field.set(parameter, 0);
field.setAccessible(false);
} else if ("createdBy".equals(field.getName())) {
field.set(parameter, loginId);
field.setAccessible(false);
} else if ("createdTime".equals(field.getName())) {
field.set(parameter, new Date());
field.setAccessible(false);
} else {
field.setAccessible(false);
}
} catch (Exception e) {
log.error("dealInsert.error:{}", e.getMessage(), e);
}
}
}
private Field[] getAllFields(Object object) {
Class<?> clazz = object.getClass();
List<Field> fieldList = new ArrayList<>();
while (clazz != null) {
fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
clazz = clazz.getSuperclass();
}
Field[] fields = new Field[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}