目录
1、拦截器代码(处理了子查询、关联查询等情况)
package com.yami.shop.common.filter;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.*;
import org.apache.commons.collections.CollectionUtils;
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.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;
import java.io.StringReader;
import java.sql.Connection;
import java.util.List;
import java.util.Properties;
/**
* 逻辑删除拦截器,全局处理xml
*
* @author mlj
* @date 2022/10/21 13:34
*/
@Slf4j
@AllArgsConstructor
@Component
@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();
String finalSql = this.handleSql(originalSql);
System.err.println("逻辑删除处理过后的SQL: \n" + finalSql);
log.info("逻辑删除处理过后的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
*/
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) {
this.processInsertSelect(plainSelect);
}
/**
* 生成拦截对象的代理
*
* @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) {
}
/**
* 处理 子查询
*
* @param plainSelect
*/
protected void processInsertSelect(PlainSelect plainSelect) throws JSQLParserException {
FromItem fromItem = plainSelect.getFromItem();
if (fromItem instanceof Table) {
Table table = (Table) fromItem;
Alias fromItemAlias = table.getAlias();
String originalTableName = table.getName();
String mainTableName = fromItemAlias == null ? originalTableName : fromItemAlias.getName();
// 判断是否需要逻辑删除,如果不需要直接过滤
// if (!MybatisPlusConfig.LOGIC_DELETE_TABLE.contains(originalTableName)) {
// return;
// }
// 主表的逻辑删除处理
String dataSql = mainTableName + ".del_flag = 0";
//关联子表的逻辑删除处理
final List<Join> joins = plainSelect.getJoins();
if (CollectionUtils.isNotEmpty(joins)) {
for (Join join : joins) {
final Table rightItem = (Table) join.getRightItem();
Alias rightItemAlias = rightItem.getAlias();
String rightItemOriginalTableName = rightItem.getName();
String rightItemMainTableName = rightItemAlias == null ? rightItemOriginalTableName : rightItemAlias.getName();
String subDataSql = rightItemMainTableName + ".del_flag = 0";
final Expression expression = join.getOnExpression();
final String s = expression.toString();
join.setOnExpression(CCJSqlParserUtil.parseCondExpression(s + " and " + subDataSql));
}
}
if (plainSelect.getWhere() == null) {
plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(dataSql));
} else {
plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), CCJSqlParserUtil.parseCondExpression(dataSql)));
}
}
//子查询处理
else if (fromItem instanceof SubSelect) {
SubSelect subSelect = (SubSelect) fromItem;
PlainSelect subSelectBody = (PlainSelect) subSelect.getSelectBody();
processInsertSelect(subSelectBody);
}
}
}
2、测试