相信大家对拦截器并不陌生,对mybatis也不陌生。
有用过pagehelper的,那么对mybatis拦截器也不陌生了,按照使用的规则触发sql拦截,帮我们自动添加分页参数 。
那么今天,我们的实践 自定义mybatis拦截器也是如此, 本篇文章实践的效果:
针对一些使用 单个实体类去接收返回结果的 mapper方法,我们拦截检测,如果没写 limit 1 ,我们将自动帮忙填充,达到查找单条数据 效率优化的效果。
ps: 当然,跟着该篇学会了这个之后,那么可以扩展的东西就多了,大家按照自己的想法或是项目需求都可以自己发挥。 我该篇的实践仅仅作为抛砖引玉吧。
实践的准备 :
整合mybatis ,然后故意写了3个查询方法, 1个是list 列表数据,2个是 单条数据 。
高考几天时间考完我们通过自己写一个mybatisinterceptor实现 mybatis框架的interceptor来做文章:
mybatisinterceptor.java :
import org.apache.ibatis.executor.executor;import org.apache.ibatis.mapping.*;import org.apache.ibatis.plugin.*;import org.apache.ibatis.ssion.resulthandler;import org.apache.ibatis.ssion.rowbounds;import org.springframework.stereotype.component; import java.lang.reflect.method;import java.util.*; /** * @author jcccc * @description * @date 2021/12/14 16:56 */@component@intercepts({ @signature(type = executor.class, method = "update", args = {mappedstatement.class, object.class}), @signature(type = executor.class, method = "query", args = {mappedstatement.class, object.class, rowbounds.class, resulthandler.class})})public class mybatisinterceptor implements interceptor { @override public object intercept(invocation invocation) throws throwable { //获取执行参数 object[] objects = invocation.getargs(); mappedstatement ms = (mappedstatement) objects[0]; //解析执行sql唐诗三百首幼儿早教朗诵的map方法,开始自定义规则匹配逻辑 string mappermethodallname = ms.getid(); int lastindex = mappermethodallname.lastindexof("."); string mapperclassstr = mappermethodallname.substring(0, lastindex); string mapperclassmethodstr = mappermethodallname.substring((lastindex + 1)); class<?> mapperclass = class.forname(mapperclassstr); method[] methods = mapperclass.getmethods(); class<?> returntype; for (method method : methods) { if (method.getname().equals(mapperclassmethodstr)) { returntype = method.getreturntype(); if (returntype.isassignablefrom(list.class)) { system.out.println("返回类型是 list"); system.out.println("针对list 做一些操作"); } el if (returntype.isassignablefrom(t.class)) { system.out.println("返回类型是 t"); system.out.println("针对t 做一些操作"); } el{ boundsql boundsql = ms.getsqlsource().getboundsql(objects[1]); string oldsql = boundsql.getsql().tolowerca(locale.china).replace("[\\t\\n\\r]", " "); if (!oldsql.contains("limit")){ string newsql = boundsql.getsql().tolowerca(locale.china).replace("[\\t\\n\\r]", " ") + " limit 1"; boundsql newboundsql = new boundsql(ms.getconfiguration(), newsql, boundsql.getparametermappings(), boundsql.getparameterobject()); mappedstatement newms = newmappedstatement(ms, new myboundsqlsqlsource(newboundsql)); for (parametermapping mapping : boundsql.getparametermappings()) { string prop = mapping.getproperty(); if (boundsql.hasadditionalparameter(prop)) { newboundsql.tadditionalparameter(prop, boundsql.getadditionalparameter(prop)); } } object[] queryargs = invocation.getargs(); queryargs[0] = newms; system.out.println("打印新sql语句" + newsql); } } } } //继续执行逻辑 return invocation.proceed(); } @override public object plugin(object o) { //获取代理权 if (o instanceof executor) { //如果是executor(执行增删改查操作),则拦截下来 return plugin.wrap(o, this); } el { return o; } } /** * 定义一个内部辅助类,作用是包装 sql */ class myboundsqlsqlsource implements sqlsource { private boundsql boundsql; public myboundsqlsqlsource(boundsql boundsql) { this.boundsql = boundsql; } @override public boundsql getboundsql(object parameterobject) { return boundsql; } } private mappedstatement newmappedstatement(mappedstatement ms, sqlsource newsqlsource) { mappedstatement.builder builder = new mappedstatement.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.resultttype(ms.getresultttype()); builder.cache(ms.getcache()); builder.flushcacherequired(ms.isflushcacherequired()); builder.ucache(ms.isucache()); return builder.build(); } @override public void tproperties(properties properties) { //读取mybatis配置文件中属性 } }
简单代码端解析:
① 拿出执行参数,里面有很多东西给我们用的,我本篇主要是用mappedstatement。大家可以发挥自己的想法。 打debug可以自己看看里面的东西。
//获取执行参数object[] objects = invocation.getargs();mappedstatement ms = (mappedstatement) objects[0];
② 这里我主要是使用了从mappedstatement里面拿出来的id,做切割分别切出来 目前执行的sql的mapper是哪个,然后方法是哪个。
string mappermethodallname = ms.getid();int lastindex = mappermethodallname.lastindexof(".");string mapperclassstr = mappermethodallname.substring(多媒体教学的优点0, lastindex);string mapperclassmethodstr = mappermethodallname.substring((lastindex + 1));
③ 这就是我自己随便写的一下,我直接根据切割出来的mapper类找出里面的方法,主要是为了拿出每个方法的返回类型,因为 我这篇实践内容就是,判断出单个pojo接受的mapper方法,加个limit 1 , 其他的 list 、t 、 page 等等这些,我暂时不做扩展。
class<?> mapperclass = class.forname(mapperclassstr);method[] methods = mapperclass.getmethods();class<?> returntype;
④这一段代码就是该篇的拓展逻辑了,从mappedstatement里面拿出 sqlsource,然后再拿出boundsql,然后一顿操作 给加上limit 1 , 然后new 一个新的mappedstatement,一顿操作塞回去invocation 里面
boundsql boundsql = ms.getsqlsource().getboundsql(objects[1]);string oldsql = boundsql.getsql().tolowerca(locale.china).replace("[\\t\\n\\r]", " ");if (!oldsql.contains("limit")){ str炒股心得ing newsql = boundsql.getsql().tolowerca(locale.china).replace("[\\t\\n\\r]", " ") + " limit 1"; boundsql newboundsql = new boundsql(ms.getconfiguration(), newsql, boundsql.getparametermappings(), boundsql.getparameterobject()); mappedstatement newms = newmappedstatement(m感恩母亲的作文200字s, new myboundsqlsqlsource(newboundsql)); for (parametermapping mapping : boundsql.getparametermappings()) { string prop = mapping.getproperty(); if (boundsql.hasadditionalparameter(prop)) { newboundsql.tadditionalparameter(prop, boundsql.getadditionalparameter(prop)); } } object[] queryargs = invocation.getargs(); queryargs[0] = newms; system.out.println("打印新sql语句:" + newsql);}
ok,最后简单来试试效果 :
最后再重申一下,本篇文章内容只是一个抛砖引玉,随便想的一些实践效果,大家可以按照自己的想法发挥。
最后再补充一个 解决 mybatis自定义拦截器和pagehelper 拦截器 冲突导致失效的问题出现的
解决方案:
加上一个拦截器配置类
mydatasourceinterceptorconfig.java :
import org.apache.ibatis.ssion.sqlssionfactory;import org.springframework.beans.factory.annotation.autowired;import org.springframework.context.applicationlistener;import org.springframework.context.event.contextrefreshedevent;import org.springframework.stereotype.component; import java.util.list; /** * @author jcccc * @description * @date 2021/12/14 16:56 */@componentpublic class mydatasourceinterceptorconfig implements applicationlistener<contextrefreshedevent> { @autowired private mybatisinterceptor mybatisinterceptor; @autowired private list<sqlssionfactory> sqlssionfactories; @override public void onapplicationevent(contextrefreshedevent contextrefreshedevent) { for (sqlssionfactory factory : sqlssionfactories) { factory.getconfiguration().addinterceptor(mybatisinterceptor); } }}
最后最后再补充多一些,
文中 针对拦截的是executor 这种接口的插件,
其实 还可以使用parameterhandler、resultthandler、statementhandler。
每当执行这四种接口对象的方法时,就会进入拦截方法,然后我们可以根据不同的插件去拿不同的参数。
类似:
@signature(method = "prepare", type = statementhandler.class, args = {connection.class,integer.class})
然后可以做个转换,也是可以取出相关的 boundsql 等等 :
if (!(invocation.gettarget() instanceof routingstatementhandler)){ return invocation.proceed(); } routingstatementhandler statementhandler = (routingstatementhandler) invocation.gettarget(); boundsql boundsql = statementhandler.getboundsql(); string sql = boundsql.getsql().toupperca();
parameterhandler、resultthandler、statementhandler、executor ,不同的插件拦截,有不同的使用场景,想深入的看客们,可以深一下。
到此这篇关于springboot自定义mybatis拦截器实现扩展的文章就介绍到这了,更多相关springboot mybatis拦截器内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
本文发布于:2023-04-04 09:17:10,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/0a7e76f580bda02e18729a681f55b8e3.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:Springboot自定义mybatis拦截器实现扩展.doc
本文 PDF 下载地址:Springboot自定义mybatis拦截器实现扩展.pdf
留言与评论(共有 0 条评论) |