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) {
    
    }

}

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

public static Set<String> LOGIC_DELETE_TABLE = new HashSet<>();

static {
    
    
    LOGIC_DELETE_TABLE.add("t_demo");
}

3、启用插件

@Bean
@ConditionalOnMissingBean
public LogicDeleteInterceptor logicDeleteInterceptor() {
    
    
    return new LogicDeleteInterceptor();
}

4、测试

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

三、本文案例demo源码

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


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

猜你喜欢

转载自blog.csdn.net/qq_38225558/article/details/126387438