1、添加插件配置类
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.annotation.LogicDelete;
import tk.mybatis.mapper.annotation.Version;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
@Intercepts({@Signature(
type = Executor.class,
method = "update",
args = {MappedStatement.class, Object.class}
)})
public class MybatisInterception implements Interceptor {
public MybatisInterception() {
}
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();
} else {
Field[] declaredFields = this.getAllFields(parameter);
Date now = new Date();
String userId = ContextUtil.getUserId();
Integer dteptId = ContextUtil.getDteptId();
Field[] var9 = declaredFields;
int var10 = declaredFields.length;
for(int var11 = 0; var11 < var10; ++var11) {
Field field = var9[var11];
if (field.getAnnotation(NotAutoFill.class) == null) {
Class clazz;
if (SqlCommandType.INSERT.equals(sqlCommandType)) {
if (field.getAnnotation(CreateTime.class) != null || Objects.equals(field.getName(), "createTime")) {
field.setAccessible(true);
field.set(parameter, now);
}
if (field.getAnnotation(Version.class) != null || Objects.equals(field.getName(), "version")) {
field.setAccessible(true);
field.set(parameter, 1);
}
if (Objects.equals(field.getName(), "createBy")) {
field.setAccessible(true);
if (StringUtils.isNotEmpty(userId)) {
clazz = field.getType();
if (clazz == Integer.class) {
field.set(parameter, Integer.parseInt(userId));
} else {
field.set(parameter, userId);
}
}
}
if (Objects.equals(field.getName(), "createDeptId")) {
field.setAccessible(true);
field.set(parameter, dteptId);
}
}
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
if (field.getAnnotation(UpdateTime.class) != null || Objects.equals(field.getName(), "updateTime")) {
field.setAccessible(true);
field.set(parameter, now);
}
if (Objects.equals(field.getName(), "updateBy")) {
field.setAccessible(true);
clazz = field.getType();
if (StringUtils.isNotEmpty(userId)) {
if (clazz == Integer.class) {
field.set(parameter, Integer.parseInt(userId));
} else {
field.set(parameter, userId);
}
}
}
}
}
}
if (SqlCommandType.DELETE.equals(sqlCommandType)) {
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
//转换DELETE语句为逻辑删除语句
String logicDeleteSql = convertToLogicDelete(boundSql.getSql());
FieldUtils.writeField(boundSql, "sql", logicDeleteSql, true);
MappedStatement newMappedStatement = new MappedStatement.Builder(mappedStatement.getConfiguration(),
mappedStatement.getId(), new BoundSqlSqlSource(boundSql), mappedStatement.getSqlCommandType())
.build();
invocation.getArgs()[0] = newMappedStatement;
}
return invocation.proceed();
}
}
// 根据表名转换为类名
private String convertTableNameToClassName(String tableName) {
// 实现根据表名转换为类名的逻辑,将下划线分隔的单词转换为驼峰式命名
StringBuilder classNameBuilder = new StringBuilder();
String[] words = tableName.split("_");
for (String word : words) {
classNameBuilder.append(Character.toUpperCase(word.charAt(0))).append(word.substring(1).toLowerCase());
}
classNameBuilder.append("Domain");
return classNameBuilder.toString();
}
// 根据表名查找对应的Class对象
private Class<?> findClassByTableName(String tableName) {
String[] packagePrefixes = {"com.demo.service.entity.video"};
for (String prefix : packagePrefixes) {
try {
String fullClassName = prefix + "." + convertTableNameToClassName(tableName);
return Class.forName(fullClassName);
} catch (ClassNotFoundException e) {
// 如果在当前包下找不到对应的类,则继续下一个包的搜索
continue;
}
}
return null;
}
// 获取指定父包下的所有子包
// private List<String> getPackages(String parentPackage) {
// List<String> packages = new ArrayList<>();
// Reflections reflections = new Reflections(parentPackage, new SubTypesScanner(false));
// Set<String> allClasses = reflections.getAllTypes();
// for (String className : allClasses) {
// if (className.contains(".")) {
// String packageName = className.substring(0, className.lastIndexOf('.'));
// if (!packages.contains(packageName)) {
// packages.add(packageName);
// }
// }
// }
// return packages;
// }
private String convertToLogicDelete(String sql) throws NoSuchFieldException {
Pattern pattern = Pattern.compile("DELETE FROM (\\w+)\\s+WHERE\\s+(.*)", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(sql);
if (matcher.matches()) {
String tableName = matcher.group(1); //获取表名
Class<?> classByTableName = findClassByTableName(tableName);
if(classByTableName == null) {
return sql;
}
Field isDeletedField = null;
for (Field field : classByTableName.getDeclaredFields()) {
if(field.getName().equals("isDeleted")) {
isDeletedField = field;
}
}
isDeletedField = hasParentField(classByTableName, "isDeleted");
if(isDeletedField == null || isDeletedField.getAnnotation(LogicDelete.class) == null) {
return sql;
}
String whereClause = matcher.group(2).trim(); //获取WHERE子句并去除两端空白字符
// 构建逻辑删除的UPDATE语句
StringBuilder logicDeleteSql = new StringBuilder();
logicDeleteSql.append("UPDATE ").append(tableName).append(" SET ").append("is_deleted").append(" = ").append(1);
// 如果WHERE子句不为空或不全为空白字符,则加上WHERE子句
if (!whereClause.isEmpty()) {
logicDeleteSql.append(" WHERE ").append(whereClause);
}
return logicDeleteSql.toString();
} else {
// 如果SQL语句格式不匹配,则返回原始SQL或抛出异常,这里为了简单起见,直接返回原始 SQL
return sql;
}
}
// 判断类中是否包含父类的字段
private Field hasParentField(Class<?> clazz, String fieldName) {
Class<?> superClass = clazz.getSuperclass();
while (superClass != null) {
Field[] fields = superClass.getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals(fieldName)) {
return field;
}
}
superClass = superClass.getSuperclass();
}
return null;
}
public Object plugin(Object o) {
return Plugin.wrap(o, this);
}
public void setProperties(Properties properties) {
}
private Field[] getAllFields(Object object) {
Class<?> clazz = object.getClass();
ArrayList fieldList;
for(fieldList = new ArrayList(); clazz != null; clazz = clazz.getSuperclass()) {
fieldList.addAll(new ArrayList(Arrays.asList(clazz.getDeclaredFields())));
}
Field[] fields = new Field[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
public class BoundSqlSqlSource implements SqlSource {
private BoundSql boundSql;
public BoundSqlSqlSource(BoundSql boundSql) {
this.boundSql = boundSql;
}
@Override
public BoundSql getBoundSql(Object parameterObject) {
return boundSql;
}
}
}
2、修改mybatis-config.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 插件配置... -->
<plugins>
<plugin interceptor="xxx.xxx.MybatisInterceptor">
<!-- 插件可以配置属性,如果需要的话 -->
<!-- <property name="someProperty" value="someValue"/> -->
</plugin>
</plugins>
<!-- 其他配置... -->
</configura
3、目前批量操作还存在一些问题,基本思路如此,使用mybatis-plus不知道会不会有批量的问题