1.导入jar包(如果用的若依框架则不用,本身就存在该包)
<!--sql解析类-->
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>1.1</version>
</dependency>
2.mybatis-config.xml关键如下(完整的参考ruoyi-vue)
<plugins>
<plugin interceptor="com.ruoyi.system.in.SqlWhereInterceptor" />
</plugins>
3.注解如下
import java.lang.annotation.*;
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface KxsMybatis
{
/**
* 可以用这个条件,自己实现,注解哦都有了,能拿到这个where去拼接sql
*/
public String where() default "";
}
4.mapper接口如下
import com.ruoyi.common.annotation.KxsMybatis;
import com.ruoyi.common.core.domain.entity.SysUser;
import java.util.List;
/**
* 用户表 数据层
*
* @author ruoyi
*/
public interface SysUserMapper {
@KxsMybatis
List<SysUser> selectUserList(SysUser sysUser);
}
2.我这是在ruoyi-vue上修改的
import com.ruoyi.common.annotation.KxsMybatis;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Properties;
/**
* @author kxs
* @date 2024-06-05 9:20
*/
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class SqlWhereInterceptor implements Interceptor {
private static Logger log = LoggerFactory.getLogger(SqlWhereInterceptor.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler sh = (StatementHandler)invocation.getTarget();
Object params = sh.getBoundSql().getParameterObject();
String sql = sh.getBoundSql().getSql();
log.info("\nsql入参 ===========> " + params);
log.info("\nsql语句 ===========> " + sql);
String mapperMethod = getMapperMethod(sh);
log.info("\nmapperMethod ===========> " + mapperMethod);
//获取mapper 类
Class<?> classType = Class.forName(mapperMethod.substring(0, mapperMethod.lastIndexOf(".")));
//方法名字
boolean isAnnotation = false;
String mName = mapperMethod.substring(mapperMethod.lastIndexOf(".") + 1, mapperMethod.length());
for (Method method : classType.getDeclaredMethods()) {
if (mName.equals(method.getName()) && method.isAnnotationPresent(KxsMybatis.class)) {
isAnnotation = true;
log.info("\n" + mName+"======================存在注解==================================");
}
}
if(!isAnnotation){
//注解不存在 直接正常执行
return invocation.proceed();
}
CCJSqlParserManager parserManager = new CCJSqlParserManager();
Statement parse = parserManager.parse(new StringReader(sql));
if(parse instanceof Select) {
//是查询的情况下
Select select = (Select) parse;
PlainSelect plain = (PlainSelect) select.getSelectBody();
Expression expWhere = plain.getWhere();
String where = expWhere != null ? expWhere.toString() : null;
log.info("\nwhere条件=================" + where);
//不要直接where+"1=1"因为where如果是null会变成null 1=1
where = StringUtils.isEmpty(where) ? "1=1" : where+" and 1=1 ";
/**
* MetaObject paramsObject = SystemMetaObject.forObject(params);
* 可以用这个代码拿到入参某个值
*例如你入参是个 User对象 User里面有ids,那么你可以通过这个拿到ids
* Object ids = paramsObject.getValue("ids");
*/
log.info("\nnewwhere条件=================" + where);
Expression whereExpression = CCJSqlParserUtil
.parseCondExpression(where);
plain.setWhere(whereExpression);
log.info("\nwhere条件=================" + plain.getWhere());
//如果自己能处理sql的话,newSql就是你处理后的,如果自己麻烦,建议用上面的,帮你处理过的,可以直接拿到where重新set
String newSql = select.toString();
Field sf = ReflectionUtils.findField(sh.getBoundSql().getClass(), "sql");
sf.setAccessible(true);
ReflectionUtils.setField(sf, sh.getBoundSql(), newSql);
}
// 继续执行后续操作
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties properties) {
// 可以设置一些属性,但在这个示例中我们不需要
}
private String getMapperMethod(StatementHandler statementHandler) {
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
// 提取 Mapper 方法名,这通常涉及到解析 SQL 语句的 id 或者其他元数据
// 注意:以下代码只是示例,实际实现可能依赖于 MyBatis 的内部实现和版本
String mapperId = (String) metaStatementHandler.getValue("delegate.mappedStatement.id");
// 这里你可能需要进一步解析 mapperId 来获取方法名
// 或者使用其他方式来获取方法名,比如从参数对象中解析
// 此处代码需要根据实际情况进行编写
return mapperId; // 在这个例子中,我们简单地返回了 mapperId,实际中需要处理以得到方法名
}
}