需求:

在执行某个动态sql时,where 子句,希望通过用户进行自定义查询条件,比如用户可以传入 “id > 100011 and name = '张三'” 的多条件表达式进行查询 (注意:这里的条件查询,为了安全性的考虑,是经过处理的,以免出现安全漏洞。)

方法:

1. 自定义mybatis的拦截器MySqlInterceptor(继承 org.apache.ibatis.plugin.Interceptor)对执行的mapper接口进行拦截

2. 改写对应 intercept()方法。

3. 添加到项目文件中,进行拦截器配置。

以下代码仅做参考学习使用。

自定义拦截器代码如下:

package com.hlyjy.zj.interceptor;import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.apache.ibatis.binding.MapperMethod;
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.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.Properties;/*** @author junzhou* @date 2021/1/5 13:55* @description: 自定义 MyBatis 拦截器* 用于拦截 mapper 接口中的动态查询语句,只对 mapper 接口中的 searchByQuery 方法启作用* @since 1.8*/
@Intercepts({@Signature(type = Executor.class, method = "query",args = {MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class})})
public class MySqlInterceptor implements Interceptor {/*** 日志记录器*/private static final Logger logger= LoggerFactory.getLogger(MySqlInterceptor.class);/*** intercept 方法用来对拦截的 sql 进行具体的操作* 本拦截方法只对 mapper 接口中的 searchByQuery 方法进行拦截,实际每个方法都拦截了,* 只是只有 searchByQuery 方法时,才真正执行 拦截的相关操作* @param invocation 拦截器执行器* @return* @throws Throwable 异常信息*/@Overridepublic Object intercept(Invocation invocation) throws Throwable {//  logger.info("执行intercept方法:{}", invocation.toString());//  获取 invocation 传递的参数Object[] args = invocation.getArgs();MappedStatement ms = (MappedStatement) args[0];// 获取执行的该拦截器的全路径方法 比如你的 UserInfoMapper 接口的 getById 方法, com.xx.UserInfoMapper.getByIdString id = ms.getId();// 如果不是 searchByQuery 方法,就不进行相关的拦截操作if (!filterMethodById(id)){return invocation.proceed();}// 该参数类型 org.apache.ibatis.binding.MapperMethod$ParamMapObject parameterObject = args[1];// 获取传递的参数, 主要包含三个参数 1. 查询语句 searchQuery, 2. 查询偏移 pageOffset, 3. 查询每页的数据条数MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) parameterObject;// 对查询的条件进行重新拼接// searchQuery 查询的条件String searchQuery = "";// pageOffset 分页查询的偏移int pageOffset = 0 ;// pageSize 分页查询页面大小,即每页多少条数据int pageSize = 10;// 取出各个参数并赋值if (paramMap.containsKey("searchQuery")){searchQuery = (String) paramMap.get("searchQuery");}if (paramMap.containsKey("pageOffset")){pageOffset = (int) paramMap.get("pageOffset");}if (paramMap.containsKey("pageSize")){pageSize = (int) paramMap.get("pageSize");}BoundSql boundSql = ms.getBoundSql(parameterObject);// 获取原始查询的 sql 语句String origSql = boundSql.getSql();logger.error("原始SQL: {}", origSql);// 构建新的 sql 语句, 将 where 条件和 limit 条件加入String newSql = null;// 如果存在条件查询则 拼接条件,如果不存在,则只添加分页限制if (!searchQuery.equals("")){newSql =  origSql +" WHERE " + searchQuery + " LIMIT " + pageSize + " OFFSET " + pageOffset;}else {newSql = origSql + " LIMIT " + pageSize + " OFFSET " + pageOffset;}// 重新new一个查询语句对象BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), newSql,boundSql.getParameterMappings(), boundSql.getParameterObject());// 把新的查询放到 statement 里MappedStatement newMs = newMappedStatement(ms, new MySqlInterceptor.BoundSqlSqlSource(newBoundSql));for (ParameterMapping mapping : boundSql.getParameterMappings()) {String prop = mapping.getProperty();if (boundSql.hasAdditionalParameter(prop)) {newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));}}// 修改 MappedStatementObject[] queryArgs = invocation.getArgs();queryArgs[0] = newMs;logger.info("拦截了 " + id + " 相关执行。");return invocation.proceed();}/*** 定义一个内部辅助类,作用是包装 SQL*/class BoundSqlSqlSource implements SqlSource {private BoundSql boundSql;public BoundSqlSqlSource(BoundSql boundSql) {this.boundSql = boundSql;}@Overridepublic BoundSql getBoundSql(Object parameterObject) {return boundSql;}}/*** 根据获取到执行 id 找到对应的方法,只在 searchByQuery 方法上执行拦截* @param id 根据 MappedStatement 获取到的 id 属性* @return 是否是 searchByQuery 方法*/private boolean filterMethodById(String id){System.out.println("id: " + id);String[] names = id.split("\\.");System.out.println("names: " + names.length);return names[names.length - 1].equals("searchByQuery");}private MappedStatement newMappedStatement (MappedStatement ms, SqlSource newSqlSource) {MappedStatement.Builder builder = newMappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());builder.resource(ms.getResource());builder.fetchSize(ms.getFetchSize());builder.statementType(ms.getStatementType());builder.keyGenerator(ms.getKeyGenerator());if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0) {builder.keyProperty(ms.getKeyProperties()[0]);}builder.timeout(ms.getTimeout());builder.parameterMap(ms.getParameterMap());builder.resultMaps(ms.getResultMaps());builder.resultSetType(ms.getResultSetType());builder.cache(ms.getCache());builder.flushCacheRequired(ms.isFlushCacheRequired());builder.useCache(ms.isUseCache());return builder.build();}/**** 定义拦截的类 Executor、ParameterHandler、StatementHandler、ResultSetHandler当中的一个* @param target 需要拦截的类* @return*/@Overridepublic Object plugin(Object target) {if (target instanceof Executor) {return Plugin.wrap(target, this);}return target;}/*** 属性相关操作* 设置和自定义属性值* @param properties 属性值*/@Overridepublic void setProperties(Properties properties) {// 获取属性// String value1 = properties.getProperty("prop1");}}

配置类:

package com.hlyjy.zj.config;import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration;
import com.hlyjy.hbase.Interceptor.MySqlInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;@Configuration
@AutoConfigureAfter(PageHelperAutoConfiguration.class)
public class MyBatisConfig {@Autowiredprivate List<SqlSessionFactory> sqlSessionFactoryList;@PostConstructpublic void addMySqlInterceptor() {MySqlInterceptor interceptor = new MySqlInterceptor();for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {sqlSessionFactory.getConfiguration().addInterceptor(interceptor);}}}

在resource目录下新建META-INF目录,然后添加spring.factories文件,其中内容如下:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration,\
com.hlyjy.zj.config.MyBatisConfig  # 其中 com.hlyjy.zj.config 为你自己配置类的包名,MyBatisConfig 为我的配置类名 

如有不足之处,欢迎大家交流学习。

SpringBoot2整合Mybatis拦截器,拦截mapper接口的某个方法相关推荐

  1. spring拦截器 拦截和排除接口冲突

    以下为springboot案例: 场景:  某个规则下的绝大部分接口路径不需要经过拦截器, 但其中的某几个接口又需要经过拦截器. 例如: "/api/register/**" 模式 ...

  2. 自定义注解和拦截器,实现接口限流防刷

    我们的目的是在指定时间内,每个用户只能进行秒杀请求指定次数. 首先,定义一个注解 写一个拦截器.就是当执行某个方法之前,将请求截获: (这里实现的只是一个思路,由于StringRedisTemplat ...

  3. Stust2的拦截器的运行流程及使用方法、注意事项

    拦截器是Strust2的一大特色:拦截器是对用户请求(.do,.action或者其他)的一种审查和额外的处理.拦截器与程序核心代码分离,实现了AOP面向切面编程的技术原理:而且帮助程序完成用户请求的安 ...

  4. SpringBoot——使用拦截器拦截未登录用户

    前置知识SpringBoot配置拦截器基于HandlerInterceptor接口实现,关键三个方法 preHandle()执行目标之前 postHandle()执行目标之后 afterComplet ...

  5. axios config里自定义属性,使用拦截器拦截,无法拿到自定义属性问题

    axios config里自定义属性,使用拦截器拦截,无法拿到自定义属性问题 最新版本axios限制了键,对键值做了白名单处理. 解决思路: 修改源码中的内容,添加一个键来报错额外属性. 或者:使用老 ...

  6. mysql 自动生成mapper_Spring Boot整合mybatis并自动生成mapper和实体实例解析

    最近一直都在学习Java,发现目前Java招聘中,mybatis出现的频率挺高的,可能是目前Java开发中使用比较多的数据库ORM框架.于是我准备研究下Spring Boot和mybatis的整合. ...

  7. 在JSP中常见问题,防止SpringMVC拦截器拦截js等静态资源文件的解决方案

    在JSP中常见问题,防止SpringMVC拦截器拦截js等静态资源文件的解决方案 参考文章: (1)在JSP中常见问题,防止SpringMVC拦截器拦截js等静态资源文件的解决方案 (2)https: ...

  8. 拦截器 参数不过去 的解决方法

    拦截器 参数不过去 博客分类: struts2 还是同样的问题,拦截器在以前学的时候,学的不怎么领会,所以学过忘记了. 我很搞不清楚拦截器和校验器的区别呵呵,都是在xml文件中,当初学的时候,可能是基 ...

  9. 【项目经验】拦截器拦截入参出参

    文章目录 拦截器拦截入参出参 入参 出参 拦截器拦截入参出参 入参 @Overridepublic boolean preHandle(HttpServletRequest request, Http ...

最新文章

  1. 自信的真正含义--NLP
  2. slider使用TickPlacement获得游标效果
  3. mysql 自动 分库 备份_MySQL分库备份的方法
  4. 支撑位和压力位怎么看是什么意思?
  5. 【汇编语言】【ARM扩展资料】数据寻址
  6. python可能导致异常的代码_Python程序可能导致文件系统错误?
  7. 正则表达式在python中的应用_正则表达式:Python3中的应用简介
  8. Linux常用命令大全
  9. JPA结合querydsl使用
  10. 基于MC1496芯片的AM调制与解调
  11. iconfont在IE下不兼容问题
  12. 显示器的分辨率,字体像素
  13. 《淘宝店铺营销推广一册通》一2.2 选择店铺行业
  14. 优缺点 快速扫描 硬盘监测_有了这6款mac硬盘检测工具 你就能够快速检测磁盘的状态和错误情况...
  15. mac鼠标不能双击打开文件夹的解决方法
  16. Mac小技巧:同时选中多个文件
  17. ESLint:可组装的JavaScript和JSX检查工具
  18. 英特尔服务器主板怎么重装系统,英特尔u盘启动,小编教你英特尔主板怎么在bios中设置u盘启动...
  19. Typora缩小行间距
  20. 第一次买了自己的云服务器用来折腾些什么

热门文章

  1. 如何设置电脑锁屏后程序仍在运行
  2. error LNK1120: 1 个无法解析的外部命令。
  3. Matlab中fspecial函数 和imfilter函数的用法
  4. Visual Studio 中使用万能头文件 #include <bits/stdc++.h>
  5. 利用七牛云如何上传图片制作外链?
  6. 学习linux压缩命令压缩文档
  7. MySQL连接查询——连接查询的综合应用
  8. python中math函数_python中math模块函数
  9. MongoDB数据迁移之迁移工具Kettle
  10. VsCode插件安装及推荐