package jnpf.database.plugins; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; import com.baomidou.mybatisplus.core.toolkit.*; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import com.baomidou.mybatisplus.extension.toolkit.PropertyMapper; import jnpf.database.util.LogicDeleteHelper; import jnpf.util.StringUtil; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.*; import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.expression.operators.conditional.OrExpression; import net.sf.jsqlparser.expression.operators.relational.*; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.delete.Delete; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.select.*; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.update.UpdateSet; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.sql.Connection; import java.sql.SQLException; import java.util.*; import java.util.stream.Collectors; /** * 逻辑删除插件 * @author JNPF开发平台组 * @user N * @copyright 引迈信息技术有限公司 * @date 2022/10/14 10:29 */ @Data @Slf4j public class MyLogicDeleteInnerInterceptor extends TenantLineInnerInterceptor implements InnerInterceptor { private LogicDeleteHandler logicDeleteHandler; private static List tableName = new ArrayList<>(); public MyLogicDeleteInnerInterceptor() { MyLogicDeleteInnerInterceptor instance = this; super.setTenantLineHandler(new TenantLineHandler() { @Override public String getTenantIdColumn() { return logicDeleteHandler.getLogicDeleteColumn(); } @Override public Expression getTenantId() { return logicDeleteHandler.getNotDeletedValue(); } @Override public boolean ignoreTable(String tableName) { return instance.ignoreTable(tableName); } }); } private boolean isRemoveLogic(){ return LogicDeleteHelper.isIgnoreLogicDelete(); } @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { //MybatisPlus自带方法不处理, 兼容Plus、PlusJoin 见MyDefaultSqlInjector if (InterceptorIgnoreHelper.willIgnoreOthersByKey(ms.getId(), MyDefaultSqlInjector.ignoreLogicPrefix)) return; //方法名包含ignorelogic不过滤 if (ms.getId().endsWith(MyDefaultSqlInjector.ignoreLogicPrefix)) return; try { if(!isRemoveLogic()) { //添加逻辑删除 if(boundSql.getSql().toLowerCase().contains(logicDeleteHandler.getLogicDeleteColumn().toLowerCase())){ //包含逻辑删除字段不处理 return; } } PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); mpBs.sql(parserSingle(mpBs.sql(), null)); } catch (Exception e){ //特殊语句解析失败 if(log.isDebugEnabled()){ log.debug("语句解析失败", e); } } } @Override public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); MappedStatement ms = mpSh.mappedStatement(); //MybatisPlus自带方法不处理, 兼容Plus、PlusJoin 见MyDefaultSqlInjector if (InterceptorIgnoreHelper.willIgnoreOthersByKey(ms.getId(), MyDefaultSqlInjector.ignoreLogicPrefix)) { return; } //方法名包含ignorelogic不过滤 if (ms.getId().endsWith(MyDefaultSqlInjector.ignoreLogicPrefix)) return; SqlCommandType sct = ms.getSqlCommandType(); if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { if(!isRemoveLogic()) { //添加逻辑删除 if (mpSh.mPBoundSql().sql().toLowerCase().contains(logicDeleteHandler.getLogicDeleteColumn().toLowerCase())) { //包含逻辑删除字段不处理 return; } } try { PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); mpBs.sql(parserMulti(mpBs.sql(), null)); } catch (Exception e){ //特殊语句解析失败 if(log.isDebugEnabled()){ log.debug("语句解析失败", e); } } } } @Override protected String processParser(Statement statement, int index, String sql, Object obj) { if (logger.isDebugEnabled()) { logger.debug("SQL to parse, SQL: " + sql); } if (statement instanceof Insert) { this.processInsert((Insert) statement, index, sql, obj); } else if (statement instanceof Select) { this.processSelect((Select) statement, index, sql, obj); } else if (statement instanceof Update) { this.processUpdate((Update) statement, index, sql, obj); } else if (statement instanceof Delete) { if(isRemoveLogic()) { //忽略逻辑删除就直接执行删除 this.processDelete((Delete) statement, index, sql, obj); }else{ //把删除语句替换为修改语句 statement = this.processDeleteToLogicDelete((Delete) statement, index, sql, obj); } } sql = statement.toString(); if (logger.isDebugEnabled()) { logger.debug("parse the finished SQL: " + sql); } return sql; } /** * delete 语句处理 */ protected Statement processDeleteToLogicDelete(Delete delete, int index, String sql, Object obj) { if (super.getTenantLineHandler().ignoreTable(delete.getTable().getName())) { // 过滤退出执行 return delete; } Update updateStatement = null; try { updateStatement = (Update) CCJSqlParserUtil.parse(logicDeleteHandler.getDeleteSql()); } catch (JSQLParserException e) { throw new RuntimeException(e); } updateStatement.setTable(delete.getTable()); updateStatement.setWhere(delete.getWhere()); return updateStatement; } @Override public void setProperties(Properties properties) { PropertyMapper.newInstance(properties).whenNotBlank("logicDeleteHandler", ClassUtils::newInstance, this::setLogicDeleteHandler); } @Override public Expression buildTableExpression(Table table, Expression where, String whereSegment) { if(getTenantLineHandler().ignoreTable(table.getName())){ return null; } return getLogicExpression(this.getAliasColumn(table), logicDeleteHandler.getNotDeletedValue()); } /** * 逻辑字段别名设置 *

F_DELETEMARK 或 tableAlias.F_DELETEMARK

* * @param table 表对象 * @return 字段 */ @Override protected Column getAliasColumn(Table table) { StringBuilder column = new StringBuilder(); // 为了兼容隐式内连接,没有别名时条件就需要加上表名 if (table.getAlias() != null) { column.append(table.getAlias().getName()); } else { column.append(table.getName()); } column.append(StringPool.DOT).append(logicDeleteHandler.getLogicDeleteColumn()); return new Column(column.toString()); } protected Expression getLogicExpression(Expression column, Expression val){ if("null".equalsIgnoreCase(val.toString())){ IsNullExpression isNullExpression = new IsNullExpression(); isNullExpression.setLeftExpression(column); isNullExpression.setNot(false); return isNullExpression; }else { return new EqualsTo(column, val); } } private boolean ignoreTable(String table){ if(StringUtil.isEmpty(table) || logicDeleteHandler.ignoreTable(table)){ return true; } TableInfo tableInfo = TableInfoHelper.getTableInfo(table); //无实体暂不执行, 非逻辑删除表不执行 if(tableInfo != null){ return !tableInfo.isWithLogicDelete(); } return true; } // ------------ 移除逻辑删除, 操作全部数据 开始 ------------ // @Override protected Expression builderExpression(Expression currentExpression, List tables, String whereSegment) { if(isRemoveLogic()) { return removeCondition(currentExpression); } return super.builderExpression(currentExpression, tables, whereSegment); } @Override protected Expression andExpression(Table table, Expression where, String whereSegment) { if(isRemoveLogic()) { return removeCondition(where); } return super.andExpression(table, where, whereSegment); } /** * 移除SQL中的逻辑删除条件 * @param expression * @return */ private Expression removeCondition(Expression expression){ if (expression != null) { String sql = expression.toString(); if(sql.contains(logicDeleteHandler.getLogicDeleteColumn())){ if (expression instanceof AndExpression || expression instanceof OrExpression) { BinaryExpression expression1 = (BinaryExpression) expression; expression1.setLeftExpression(removeCondition(expression1.getLeftExpression())); expression1.setRightExpression(removeCondition(expression1.getRightExpression())); } if (expression instanceof EqualsTo || expression instanceof NotEqualsTo || expression instanceof IsNullExpression) { return new EqualsTo(new LongValue(1), new LongValue(1)); } } } return expression; } // ------------ 移除逻辑删除, 操作全部数据 结束 ------------ // }