mybatis-3.5.0使用插件拦截sql以及通用字段赋值

发布于:2024-04-19 ⋅ 阅读:(176) ⋅ 点赞:(0)

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不知道会不会有批量的问题


网站公告

今日签到

点亮在社区的每一天
去签到