spring boot 实现mybatis拦截器
spring boot 实现mybatis拦截器
项目是个报表系统,服务端是简单的Java web架构,直接在请求参数里面加了个query id参数,就是mybatis mapper的query id,刚好对接接口的请求参数,没有使用接口模式。
基于这种特性,分页使用了PageHelper插件,但是只使用获取指定范围记录这部分,查询的总条数是自己实现的(插件的总条数,需要创建查询对象实现),直接在查询后多发送一次数据库请求,使用自定义的拦截器,拦截查询的请求(默认注入一个参数,等于指定值),在正常的SQL前后 拼接上 "select count(1) coun from (" +sql+")",直接在数据库中,查询结果集的条数。如下:
if ( mapParam.get("count") != null && mapParam.get("count").toString().equalsIgnoreCase("sum")) {
// 从StatementHandler中取出查询的SQL
String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
sql = "select count(1) coun from ( " + sql + " )";
// 将修改的SQL放回StatementHandler中
metaStatementHandler.setValue("delegate.boundSql.sql", sql);
}
mybatis的 拦截器配置如下:
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 支持通过Mapper接口参数来传递分页参数 -->
<property name="supportMethodsArguments" value="true"/>
<property name="rowBoundsWithCount" value="true"/>
<property name="reasonable" value="true"/>
</plugin>
<!-- mybatis写出sql记录控件(拦截器) -->
<!-- 自己写的那个拦截器 -->
<plugin interceptor="com.xx.SqlInterceptorCount">
<!-- 方言 -->
<property name="dialect" value="oracle"/>
</plugin> </plugins>
Java使用如下:
// 从数据库查询
result = QueryMapper.getObjFromDB(paras.get("qdi"),paras);
// 查询当前sql 的总条数
total = QueryMapper.getQdiSum(paras.get("qdi"),paras);
查 total 的时候,给paras,默认注入一个count参数。
paras.put("count", "sum");
hashMap = (HashMap)session.selectList(qdi, paras).get(0);
用起来还是很酸爽的。
--------------朴素的分割线------------------
进入主题
为迎合时代的发展,领导的召唤,项目架构改版,迁入springboot,方便统一管理(监控)
程序员就开干了啊。。。
。。。
。。。
。。。
。。。
。。。
// 程序员挥汗如雨中
几天后,springboot的项目开发完了,但是遇到个问题,mybatis的拦截器不生效,配置如下:
mybatis:
mapper-locations: classpath:mapper/*.xml
事实上,并没有配置,不过可以加个mybatis的配置文件,像这样,如下:
mybatis:
mapper-locations: classpath:mapper/*.xml
configuration:
interceptions: cn.utstarcom.statplatform7.interceptor.SqlInterceptorCount
config-location: classpath:mybatis-config.xml
mbatis-config.xml 内容如下:
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 支持通过Mapper接口参数来传递分页参数 -->
<property name="supportMethodsArguments" value="true"/>
<property name="rowBoundsWithCount" value="true"/>
<property name="reasonable" value="true"/>
</plugin>
<!-- mybatis写出sql记录控件(拦截器) -->
<!-- 自己写的那个拦截器 -->
<plugin interceptor="com..SqlInterceptorCount">
<!-- 方言 -->
<property name="dialect" value="oracle"/>
</plugin> </plugins>
拦截器内容如下:
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class SqlInterceptorCount implements Interceptor {
private Logger logger = LoggerFactory.getLogger(SqlInterceptorCount.class);
private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();
@Override
public Object intercept(Invocation invocation) throws Throwable {
try {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,
DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
// HashMap mapParam = (HashMap) metaStatementHandler.getValue("delegate.boundSql.parameterObject");
Object paramObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
if (paramObject instanceof Map) {
HashMap paramMap = (HashMap)paramObject;
if (paramMap.get("count") != null && paramMap.get("count").toString().equalsIgnoreCase("sum")) {
// get sql from StatementHandler
String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
sql = "select count(1) coun from ( " + sql + " )";
// set moidfy sql to StatementHandler
metaStatementHandler.setValue("delegate.boundSql.sql", sql);
}
}
} catch (Exception e) {
logger.error("throw exception and will not handle the mybatis sql");
}
// process the next query process
return invocation.proceed();
}
/**
*
* @param o
* @return
*/
@Override
public Object plugin(Object o) {
return null;
}
@Override
public void setProperties(Properties properties) {
}
}
事实上,mybatis的配置文件和配置的 interceptions,不能使用(我当然知道是),启动没有问题,数据库也可以操作,但是拦截器没有生效。
1、在又是一大圈的乱找,发现个说法,在拦截器上加个 @Component 注解就可以了。
然后,还是不行,这个更惨,只要查询数据库,都会返回个null ,又没有报错信息,只是个null
2、又是网上一通乱找,看到个说法:说拦截器只有 plugin方法执行了,intercept方法没有执行
debug 一下,发现问题了,加上@Component 注解,plugin方法执行了,返回个null,知道为什么吗,看下plugin的代码:
@Override
public Object plugin(Object o) { return null;
}
我去
不返回null,返回什么
不返回null,返回什么
不返回null,返回什么
之后接简单了,plugin 方法是实现 Interceptor 接口的时候,IDEA生成的方法,有个默认实现,返回null
改改:
@Override
public Object plugin(Object o) { // logger.info("Interceptor : SqlInterceptorCount is running, but this is plugin method not intercept method");
/*
use Intercepts annotation,intercept StatementHandler method prepare
*/
if (o instanceof StatementHandler) {
return Plugin.wrap(o, this);
}
return o;
}
在传入对象是 STATEMENTHandler的对象的时候,把方法转发到intercept 方法,拦截器可以正常执行了。
结论就是:
springboot下的mybatis拦截器,和单独用mybatis的拦截器一样,但是不需要配置,直接在拦截器前面加个@Component 注解,在plugin 方法中将请求转发到intercept方法拦截即可,不需要其他配置。
完整代码如下:
@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class SqlInterceptorCount implements Interceptor { private Logger logger = LoggerFactory.getLogger(SqlInterceptorCount.class);
private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory(); @Override
public Object intercept(Invocation invocation) throws Throwable { try {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,
DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); // HashMap mapParam = (HashMap) metaStatementHandler.getValue("delegate.boundSql.parameterObject");
Object paramObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
if (paramObject instanceof Map) {
HashMap paramMap = (HashMap)paramObject;
if (paramMap.get("count") != null && paramMap.get("count").toString().equalsIgnoreCase("sum")) {
// get sql from StatementHandler
String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
sql = "select count(1) coun from ( " + sql + " )";
// set moidfy sql to StatementHandler
metaStatementHandler.setValue("delegate.boundSql.sql", sql);
}
}
} catch (Exception e) {
logger.error("throw exception and will not handle the mybatis sql");
}
// process the next query process
return invocation.proceed();
} /**
*
* @param o
* @return
*/
@Override
public Object plugin(Object o) { // logger.info("Interceptor : SqlInterceptorCount is running, but this is plugin method not intercept method");
/*
use Intercepts annotation,intercept StatementHandler method prepare
*/
if (o instanceof StatementHandler) {
return Plugin.wrap(o, this);
}
return o;
} @Override
public void setProperties(Properties properties) { }
}
spring boot 实现mybatis拦截器的更多相关文章
- spring boot中注册拦截器
拦截器是动态拦截Action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重 ...
- spring boot 过滤器、拦截器的区别与使用
原文:https://blog.csdn.net/heweimingming/article/details/79993591 拦截器与过滤器的区别: 1.过滤器和拦截器触发时机不一样,过滤器是在请求 ...
- Spring Boot实战:拦截器与过滤器
一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,A ...
- spring boot配置springMVC拦截器
spring boot通过配置springMVC拦截器 配置拦截器比较简单, spring boot配置拦截器, 重写preHandle方法. 1.配置拦截器: 2重写方法 这样就实现了拦截器. 其中 ...
- Spring Boot 如何使用拦截器、过滤器、监听器?
过滤器 过滤器的英文名称为 Filter, 是 Servlet 技术中最实用的技术. 如同它的名字一样,过滤器是处于客户端和服务器资源文件之间的一道过滤网,帮助我们过滤掉一些不符合要求的请求,通常用作 ...
- Spring Boot下使用拦截器
Spring Boot对于原来在配置文件配置的内容,现在全部体现在一个类中,该类需要继承自WebMvcConfigurationSupport类,并使用@Configuration进行注解,表示该类为 ...
- spring boot 2.x拦截器导致静态资源404终极解决办法
首先添加application文件static路径,我的是yml文件 spring: mvc: static-path-pattern: /static/**然后注册拦截器类如下方法; @Overri ...
- 【Spring Boot】Spring Boot之自定义拦截器
一.拦截器的作用 将通用的代码抽取出来,达到复用的效果.比如可以用来做日志记录.登录判断.权限校验等等 二.如何实现自定义拦截器 1)创建自定义拦截器类并实现HandlerInterceptor类 / ...
- Spring boot实现自定义拦截器
Sprintboot的拦截器提供了精细的控制:在request被响应之前.request被响应之后.request全部结束之后至视图渲染之前 三个时间点,我们都可以通过编写他们的函数来控制. 首先新建 ...
随机推荐
- Android 性能测试之内存 --- 追加腾讯性能案例,安卓抓取性能扫盲帖
内存测试: 思路 目前做的是酒店APP,另下载安装几个个第三方酒店的APP以方便对比(相当于可以做竞品测试) 数据的获取来源是ADB底层命令,而且最好是不需要root权限,因为很多手机root很麻烦或 ...
- Unity3D研究院之设置自动旋转屏幕默认旋转方向
如下图所示,在处理屏幕默认旋转方向的时候可以在这里进行选择,上下左右一共是4个方向. 策划的需求是游戏采用横屏,但是要求支持两个方向自动旋转,如下图所示,我的设置是这样的. Default Orien ...
- f5版本升级
1)上传系统IOS及Hotfix 点击import按钮,选择要上传的文件.上传成功的话就会显示上传成功的10.2.4的iso文件 2)通过CLI命令行方式上传补丁 通过SSH工具将ISO以及Hotfi ...
- solr简介、学习详细过程!(超详细~)
solr是什么呢? 一.Solr它是一种开放源码的.基于 Lucene Java 的搜索服务器,易于加入到 Web 应用程序中. 二.Solr 提供了层面搜索(就是统计).命中醒目显示并且支持多种输出 ...
- chorem浏览器无法下载
下载的时候指定字节的长度 context.Response.AddHeader("Content-Length", bytes.Length.ToString()); contex ...
- gson所需jar包
共需要四个jar包,分别为: gson-2.0.jar log4j-1.2.17.jar slf4j-api-1.7.10.jar slf4j-log4j12-1.7.10.jar 如果想要进行文件读 ...
- ios证书安装和打包流程
iOS开发流程 1.拿到源文件 2文件目录大致名字 一.证书配置 参考网站:http://www.jianshu.com/p/9d9e3699515e (证书配置参考地址) 准备工作 首先要有苹 ...
- Java 和 Javascript的关系
写这篇文章是因为看到有人问这个问题,在想怎么会有这种SB问题,不过想想当初SB的我貌似也搞不清两者的关系,认知还是需要一个过程. 然后看到比较经典的回答有:Java 和Javascript的关系就像雷 ...
- (转)在WinForm中选择本地文件
相信很多朋友在日常的编程中总会遇到各钟各样的问题,关于在WinForm中选择本地文件就是很多朋友们都认为很难的一个学习.net的难点, 在WebForm中提供了FileUpload控件来供我们选择本地 ...
- PAT 1007 素数对猜想(20)
1007 素数对猜想(20 分) 让我们定义dn为:dn=pn+1−pn,其中pi是第i个素数.显然有d1=1,且对于n>1有dn是偶数."素 ...