添加拦截器修改mybatis-plus SQL实现查询出被逻辑删除的数据
出现的问题
第一次使用springboot+mybatis-plus开发项目,先通过逆向工程生成了所有的文件,但发现查询的时候mybatis默认把被逻辑删除的数据排除掉,这让我很苦恼,因为我想通过逻辑删除来实现用户的状态。这样导致我无法实现我想要的效果
思考
我上网搜了很多帖子,发现网友提供了两种方法
1.在表中再添加一个状态的字段来实现用户状态的判断
2.手写sql语句,根据自己的需求来编写。
这两种方法对于我来说都不适用,因为我有几十张表,如果都修改,那我得掉多少根头发 /(ㄒoㄒ)/~~
于是我继续搜索,发现mybatis-plus提供了一个拦截器接口,可以通过这个接口实现对sql语句的拦截,这样就可以将delId条件进行删除或者修改了
废话不多说了,直接上代码
代码
package com.jcy.stuhelp.common.handler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;
/**
* mybatis拦截器
* 对所有sql语句进行监视,修改
*/
@Slf4j
@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class SqlModifyInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("====SqlModifyInterceptor======");
System.out.println("====SqlModifyInterceptor======");
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
//通过MetaObject优雅访问对象的属性,这里是访问statementHandler的属性;:MetaObject是Mybatis提供的一个用于方便、
//优雅访问对象属性的对象,通过它可以简化代码、不需要try/catch各种reflect异常,同时它支持对JavaBean、Collection、Map三种类型对象的操作。
MetaObject metaObject = MetaObject
.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
new DefaultReflectorFactory());
//先拦截到RoutingStatementHandler,里面有个StatementHandler类型的delegate变量,其实现类是BaseStatementHandler,然后就到BaseStatementHandler的成员变量mappedStatement
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
//id为执行的mapper方法的全路径名,如com.uv.dao.UserMapper.insertUser
String id = mappedStatement.getId();
log.info("id为执行的mapper方法的全路径名:" + id);
//sql语句类型 select、delete、insert、update
String sqlCommandType = mappedStatement.getSqlCommandType().toString();
log.info("sql语句类型:" + sqlCommandType);
BoundSql boundSql = statementHandler.getBoundSql();
/**
这些代码是我在网上复制别人的,然后进行了一些小的修改,
其中log.info()是我为了监控sql的运行情况而添加的代码,不需要可以删除,
上面部分我不知道是不是必须的,所以我也没有删,下面是我主要修改的地方
**/
//获取到原始sql语句
String sql = boundSql.getSql();
log.info("拦截的sql语句:" + sql);
//可以先打印出原始的sql语句,然后根据实际情况修改,我个人建议是下面这样修改
//只在原sql上添加条件而不是删除条件
sql=sql.replace("DEL_ID=0 ","DEL_ID=0 OR DEL_ID=1 ");
log.info("修改之后的sql:" + sql);
//通过反射修改sql语句
//下面类似于替换sql
Field field = boundSql.getClass().getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, sql);
return invocation.proceed();
}
/**
下面这两个咱也不知道有没有用,就直接复制粘贴上来了
**/
@Override
public Object plugin(Object target) {
System.out.println("-----------------------------plugin-------------------------");
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
System.out.println("====setProperties======");
}
}
结语
目前是跑通的,并且得到了我想要的数据。
如果大家有什么看法可以留言我们一起探讨。
纯属小白操作,如果有大佬看见了,也希望可以指出一些错误的地方。
最后,如果对你有帮助,请点个赞再走吧😀