• MyBatis-Plus(3) 自定义逻辑删除插件 -- 全局处理xml中的SQL


    一、前言

    MyBatis-Plus原本是提供了逻辑删除的功能。
    在这里插入图片描述

    但如果在xml中直接写sql,它的逻辑删除是未生效的。
    网上看了下,未找到这一解决方案…
    下面我们来自定义一个简单的逻辑删除插件来实现这一功能^_^

    二、自定义逻辑删除插件

    1、编写插件LogicDeleteInterceptor

    @Slf4j
    @AllArgsConstructor
    @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
    public class LogicDeleteInterceptor implements Interceptor {
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
            MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
            // 判断是不是SELECT操作 不是直接过滤
            MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
            if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
                return invocation.proceed();
            }
            BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
            // 执行的SQL语句
            String originalSql = boundSql.getSql();
            // SQL语句的参数
            Object parameterObject = boundSql.getParameterObject();
    
            String finalSql = this.handleSql(originalSql);
    //        System.err.println("逻辑删除处理过后的SQL: \n" + finalSql);
    
            metaObject.setValue("delegate.boundSql.sql", finalSql);
            return invocation.proceed();
        }
    
        /**
         * 改写SQL
         * {@link com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor}
         *
         * @param originalSql 执行的SQL语句
         * @return 处理后的SQL
         * @author zhengqingya
         * @date 2022/1/13 10:43
         */
        private String handleSql(String originalSql) throws JSQLParserException {
            CCJSqlParserManager parserManager = new CCJSqlParserManager();
            Select select = (Select) parserManager.parse(new StringReader(originalSql));
            SelectBody selectBody = select.getSelectBody();
            if (selectBody instanceof PlainSelect) {
                this.setWhere((PlainSelect) selectBody);
            } else if (selectBody instanceof SetOperationList) {
                SetOperationList setOperationList = (SetOperationList) selectBody;
                List<SelectBody> selectBodyList = setOperationList.getSelects();
                selectBodyList.forEach(s -> this.setWhere((PlainSelect) s));
            }
            return select.toString();
        }
    
        /**
         * 设置 where 条件  --  使用CCJSqlParser将原SQL进行解析并改写
         * @param plainSelect 查询对象
         */
        @SneakyThrows(Exception.class)
        protected void setWhere(PlainSelect plainSelect) {
            Table fromItem = (Table) plainSelect.getFromItem();
            // 有别名用别名,无别名用表名,防止字段冲突报错
            Alias fromItemAlias = fromItem.getAlias();
            String originalTableName = fromItem.getName();
            String mainTableName = fromItemAlias == null ? originalTableName : fromItemAlias.getName();
    
            // 判断是否需要逻辑删除,如果不需要直接过滤
            if (!MybatisPlusConfig.LOGIC_DELETE_TABLE.contains(originalTableName)) {
                return;
            }
    
            // 构建子查询 -- 逻辑删除
            String dataSql = mainTableName + ".is_deleted = 0";
            if (plainSelect.getWhere() == null) {
                plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(dataSql));
            } else {
                plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), CCJSqlParserUtil.parseCondExpression(dataSql)));
            }
        }
    
        /**
         * 生成拦截对象的代理
         * @param target 目标对象
         * @return 代理对象
         */
        @Override
        public Object plugin(Object target) {
            if (target instanceof StatementHandler) {
                return Plugin.wrap(target, this);
            }
            return target;
        }
    
        /**
         * mybatis配置的属性
         * @param properties mybatis配置的属性
         */
        @Override
        public void setProperties(Properties properties) {}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

    2、配置需要逻辑删除的表

    public static Set<String> LOGIC_DELETE_TABLE = new HashSet<>();
    
    static {
        LOGIC_DELETE_TABLE.add("t_demo");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、启用插件

    @Bean
    @ConditionalOnMissingBean
    public LogicDeleteInterceptor logicDeleteInterceptor() {
        return new LogicDeleteInterceptor();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4、测试

    可以看见已经自动加上了is_deleted = 0
    在这里插入图片描述

    三、本文案例demo源码

    https://gitee.com/zhengqingya/small-tools


    今日分享语句:
    坚定自己想要的。

  • 相关阅读:
    java I/O流使用导航
    MySQL基础操作
    单数据改多数据导致,LinkedHashMap读取视图数据出错
    Spring Cloud OpenFeign - 日志配置
    JAVA:实现二个数字的通用根算法(附完整源码)
    ELK + kafka 日志方案
    C++之保存编译全部中间文件(二百一十五)
    Jmeter入门
    8.CF446C DZY Loves Fibonacci Numbers 线段树Lazy标记
    面试结束前被问「你有哪些要问我的?」该怎么办?这样回答你就凉了
  • 原文地址:https://blog.csdn.net/qq_38225558/article/details/126387438