Java自定义mybatis拦截器实现创建人等相关信息自动填充
·
在实际项目开发中,我们可能需要在mapper层插入相应的数据,而这些数据在各个表基本都有,比如
创建时间,更新时间,创建人,更新人这些,但是又不想在每个业务中都去设置这些值,那么我们就可以使用mybatis拦截器实现数据自动填充。
一、如何实现?
1.首先添加mybatis相关依赖。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
2.自定义mybatis拦截器。
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.defaults.DefaultSqlSession.StrictMap;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.*;
@Slf4j
@Component
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class MybatisInterceptor implements Interceptor {
private static final String DATETYPE="java.util.Date";
private static final String STRINGTYPE="java.lang.String";
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
// 获取sql执行类型:insert、update、select、delete
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
Object parameter = invocation.getArgs()[1];
if (parameter == null) {
return invocation.proceed();
}
//获取当前登录用户id
String userId = TokenUtil.getConcurrentUserId();
log.debug(" userId is {}....",userId);
// 当sql为新增或更新类型时,自动填充操作人相关信息
if (SqlCommandType.INSERT == sqlCommandType || SqlCommandType.UPDATE == sqlCommandType) {
replaceEntityProperty(parameter,userId,sqlCommandType);
}
return invocation.proceed();
}
private void replaceEntityProperty(Object parameter,String userId, SqlCommandType sqlCommandType ) {
// StrictMap
if (parameter instanceof StrictMap) {
replaceStrictMap((StrictMap) parameter,userId,sqlCommandType);
} else if (parameter instanceof Map) {
replaceMap((Map) parameter,userId,sqlCommandType);
} else {
replace(parameter,userId,sqlCommandType);
}
}
private void replace(Object parameter,String userId,SqlCommandType sqlCommandType ) {
if(SqlCommandType.INSERT == sqlCommandType){
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 ("deleted".equals(field.getName())) {
field.set(parameter, Integer.valueOf("0"));
field.setAccessible(false);
}else if ("createdBy".equals(field.getName())) {
field.set(parameter, userId);
field.setAccessible(false);
}else if ("createdTime".equals(field.getName())) {
String type = field.getType().getName();
if(DATETYPE.equals(type)){
field.set(parameter, new Date());
}else if(STRINGTYPE.equals(type)) {
field.set(parameter, DateUtil.formatDateTime(new Date()));
}
field.setAccessible(false);
}else {
updateProperty(parameter, field, userId);
}
} catch (Exception e) {
log.error("failed to insert data, exception = ", e);
}
}
}else if(SqlCommandType.UPDATE == sqlCommandType){
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;
}
//更新时只判断是否更新的属性
updateProperty(parameter, field, userId);
}catch (Exception e){
log.error("failed to update data, exception = ", e);
}
}
}
}
private void replaceStrictMap(StrictMap map, String userId, SqlCommandType sqlCommandType ) {
if (map.containsKey("collection")) {
Object collection = map.get("collection");
for (Object t : (Collection) collection) {
replace(t,userId,sqlCommandType);
}
} else if (map.containsKey("array")) {
Object collection = map.get("array");
for (Object t : (Object[]) collection) {
replace(t,userId,sqlCommandType);
}
}
}
private void replaceMap(Map map,String userId, SqlCommandType sqlCommandType) {
for (Object value : map.values()) {
replace(value,userId,sqlCommandType);
}
}
private void updateProperty(Object parameter, Field field, String userId) throws IllegalAccessException {
if ("updatedBy".equals(field.getName())) {
field.set(parameter, userId);
field.setAccessible(false);
}else if ("updatedTime".equals(field.getName())) {
String type = field.getType().getName();
if (DATETYPE.equals(type)) {
field.set(parameter, new Date());
} else if (STRINGTYPE.equals(type)) {
field.set(parameter, DateUtil.formatDateTime(new Date()));
}
field.setAccessible(false);
}else {
//其他属性什么也不做
field.setAccessible(false);
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
/**
* 获取类的所有属性,包括父类
*/
private 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;
}
}
下面是TokenUtil类,用于获取当前登录用户id。
@Slf4j
public class TokenUtil {
public static String getConcurrentUserId() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (Objects.isNull(requestAttributes)) {
return "";
} else {
HttpServletRequest request = requestAttributes.getRequest();
String userId = request.getHeader("x-userId");
if (!StringUtils.isBlank(userId)) {
return userId;
} else {
Object attribute = request.getAttribute("x-userId");
return Objects.nonNull(attribute) ? attribute.toString() : "";
}
}
}
}
这样就实现了在DAO层 创建人等相关信息自动填充。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)