关于mybatis拦截器,对结果集进行拦截
因业务需要,需将结果集序列化为json返回,于是,网上找了好久资料,都是关于拦截参数的处理,拦截Sql语法构建的处理,就是很少关于对拦截结果集的处理,于是自己简单的写了一个对结果集的处理,
记录下。
一、MyBatis的框架设计图
参考:http://blog.csdn.net/luanlouis/article/details/40422941
1.如何将结果集改成我们想要的格式呢?
1.1 由原理图我们可知,ResultSetHandler负责将resultSet转换为list,那么我们能不能在转换的时候加上自己的逻辑,我想应该是可以的,但是因为源码看不太懂,想想还是算了。
- 1 public List<Object> handleResultSets(Statement stmt) throws SQLException {
- 2 final List<Object> multipleResults = new ArrayList<Object>();
- 3
- 4 int resultSetCount = 0;
- 5 ResultSetWrapper rsw = getFirstResultSet(stmt);
- 6
- 7 List<ResultMap> resultMaps = mappedStatement.getResultMaps();
- 8 int resultMapCount = resultMaps.size();
- 9 validateResultMapsCount(rsw, resultMapCount);
- 10
- 11 while (rsw != null && resultMapCount > resultSetCount) {
- 12 ResultMap resultMap = resultMaps.get(resultSetCount);
- 13
- 14 //将resultSet
- 15 handleResultSet(rsw, resultMap, multipleResults, null);
- 16 rsw = getNextResultSet(stmt);
- 17 cleanUpAfterHandlingResultSet();
- 18 resultSetCount++;
- 19 }
- 20
- 21 String[] resultSets = mappedStatement.getResulSets();
- 22 if (resultSets != null) {
- 23 while (rsw != null && resultSetCount < resultSets.length) {
- 24 ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
- 25 if (parentMapping != null) {
- 26 String nestedResultMapId = parentMapping.getNestedResultMapId();
- 27 ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
- 28 handleResultSet(rsw, resultMap, null, parentMapping);
- 29 }
- 30 rsw = getNextResultSet(stmt);
- 31 cleanUpAfterHandlingResultSet();
- 32 resultSetCount++;
- 33 }
- 34 }
- 35
- 36 return collapseSingleResultList(multipleResults);
- 37 }
1.2 排除第一种方案,那么能不能跳过这个方法执行我们的自己的逻辑,答案是可以的,接下来我们会用到mybatis的拦截器。
2.定义mybatis拦截器,用来拦截handleResultSets
2.1 我们需要拿到MappedStatement(维护了一条<select|update|delete|insert>节点的封装)这个对象,才能获得resultType是什么类型,用于判断,那我们该怎么获取这个对象呢? 首先我们到方法handleResultSets所属类中的源码里面看看 。
(1) MappedStatement 是怎么生成的呢?由源码我们可知,是用过构造函数赋值的
- 1 public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql,
- 2 RowBounds rowBounds) {
- 3 this.executor = executor;
- 4 this.configuration = mappedStatement.getConfiguration();
- 5 this.mappedStatement = mappedStatement;
- 6 this.rowBounds = rowBounds;
- 7 this.parameterHandler = parameterHandler;
- 8 this.boundSql = boundSql;
- 9 this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
- 10 this.objectFactory = configuration.getObjectFactory();
- 11 this.resultHandler = resultHandler;
- 12 }
(2) 那么既然存在这个属性,就能获取到这个对象么,可是,当我尝试去找获得 MappedStatement这个对象的方法时,并未找到,所以我只能自己加上去了!
- 1 public MappedStatement getMappedStatement() {
- 2 return mappedStatement;
- 3 }
2.1 我们在拦截器中就能使用MappedStatement 对象,从而获得resultType的类型,为什么要这样做呢?因为我只想实现当resultType为String的时候,才执行我自己的逻辑。
- 1 @Intercepts({ @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = { Statement.class }) })
- 2 public class JsonPlugin implements Interceptor {
- 3
- 4 public Object intercept(Invocation invocation) throws Throwable {
- 5 List<String> resList = new ArrayList<String>();
- 6
- 7 DefaultResultSetHandler defaultResultSetHandler = (DefaultResultSetHandler) invocation.getTarget();
- 8 //MappedStatement维护了一条<select|update|delete|insert>节点的封装
- 9 MappedStatement mappedStatement = defaultResultSetHandler.getMappedStatement();
- 10 //获取节点属性的集合
- 11 List<ResultMap> resultMaps = mappedStatement.getResultMaps();
- 12 int resultMapCount = resultMaps.size();
- 13 //获取当前resutType的类型
- 14 Class<?> resultType = resultMaps.get(0).getType();
- 15 if (resultMapCount > 0 && resultType.getName().equals("java.lang.String")) {
- 16 Object[] obj = invocation.getArgs();
- 17 Statement statement = (Statement) invocation.getArgs()[0];
- 18 //获得结果集
- 19 ResultSet resultSet = statement.getResultSet();
- 20
- 21 if (resultSet != null) {
- 22 //获得对应列名
- 23 ResultSetMetaData rsmd = resultSet.getMetaData();
- 24 List<String> columnList = new ArrayList<String>();
- 25
- 26 for (int i = 1; i <= rsmd.getColumnCount(); i++) {
- 27 columnList.add(rsmd.getColumnName(i));
- 28 }
- 29 while (resultSet.next()) {
- 30 LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
- 31 for (String colName : columnList) {
- 32 map.put(colName, resultSet.getObject(colName));
- 33 }
- 34 JSONObject.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd hh:mm:ss";// 设置日期格式
- 35 resList.add(JSON.toJSONString(map, SerializerFeature.WriteMapNullValue,
- 36 SerializerFeature.DisableCircularReferenceDetect,
- 37 SerializerFeature.WriteDateUseDateFormat));
- 38 }
- 39 return resList;
- 40 }
- 41 }
- 42 return invocation.proceed();
- 43 }
- 44
- 45 public Object plugin(Object target) {
- 46 // 读取@Signature中的配置,判断是否需要生成代理类
- 47 if (target instanceof ResultSetHandler) {
- 48 return Plugin.wrap(target, this);
- 49 } else {
- 50 return target;
- 51 }
- 52 }
- 53
- 54 public void setProperties(Properties properties) {
- 55
- 56 }
2.2 加入拦截器配置
- <!-- 拦截器配置开始 -->
- <plugins>
- <plugin interceptor="com.smallhan.base.interceptor.JsonPlugin" />
- </plugins>
3.测试结果
3.1 ResultType为String的时候,如下图所示,并且绕过handleResultSets
3.2 ResultType为其他类型的时候,跳过我们自己写的逻辑,执行invocation.proceed,调用下一个拦截器拦截目标方法。
关于mybatis拦截器,对结果集进行拦截的更多相关文章
- Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求
Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求 >>>>>>>>>>>>>>&g ...
- axios token header response request http拦截器 axios实现登录、拦截、登出
axios token header response request http拦截器 axios实现登录.拦截.登出 一个项目学会前端实现登录拦截 https://github.com/superm ...
- springboot2.0+ 使用拦截器导致静态资源被拦截
在spring1.0+的版本中,配置拦截器后是不会拦截静态资源的.其配置如下: @Configuration public class WebMvcConfig extends WebMvcConfi ...
- EntityFramework6.0的Sql读写分离拦截器 和 MVC的 Action拦截器 对比
EF的DbCommandInterceptor类 拦截: EF6.1也出来不少日子了,6.1相比6.0有个很大的特点就是新增了System.Data.Entity.Infrastructure.Int ...
- struts2-权限拦截器、日志拦截器、execAndWait(进度条)拦截器配置
1.权限拦截器 package login; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.Serv ...
- SpringMVC拦截器(实现登录验证拦截器)
本例实现登陆时的验证拦截,采用SpringMVC拦截器来实现 当用户点击到网站主页时要进行拦截,用户登录了才能进入网站主页,否则进入登陆页面 核心代码 首先是index.jsp,显示链接 <%@ ...
- 在ASP.NET Core MVC中子类Controller拦截器要先于父类Controller拦截器执行
我们知道在ASP.NET Core MVC中Controller上的Filter拦截器是有执行顺序的,那么如果我们在有继承关系的两个Controller类上,声明同一种类型的Filter拦截器,那么是 ...
- springboot项目配置拦截器,进行登陆等拦截
新建拦截类: public class LoginInterceptor implements HandlerInterceptor{ private static Log logger = LogF ...
- SpringVC 拦截器+自定义注解 实现权限拦截
1.springmvc配置文件中配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns= ...
- Struts2默认拦截器栈及内建拦截器使用具体解释
Struts2内建拦截器介绍: alias (别名拦截器):同意參数在跨越多个请求时使用不同别名,该拦截器可将多个Action採用不同名字链接起来,然后用于处理同一信息. autowiring ...
随机推荐
- Python+Appium自动化测试(11)-location与size获取元素坐标
appium做app自动化测试过程中,有时需要获取控件元素的坐标进行滑动操作.appium中提供了location方法获取控件元素左上角的坐标,再通过size方法获取控件元素的宽高,就可以得到控件元素 ...
- MeteoInfoLab脚本示例:AIRS Swath HDF数据
例子中的AIRS Swath HDF数据在Polar Stereographic(南极)投影中接近矩形,需要先从数据中读出经纬度及相关数据数组,利用surfacem函数绘制Swath数据(散点),在s ...
- ORM查询相关的操作
必知必会13条 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.setti ...
- 资源管理神器Clover
开开心心地上班,这时你得打开我的电脑,点进D盘,打开某个项目;然后还得打开XX文档,还有.... 最后的最后,你的桌面便成了这个样子 每天你都得天打开多个文件夹,切换时找文件找的晕头转向而烦恼. 每天 ...
- 用cgroup限制内存以防止Linux因内存用尽卡死
Linux在内存用尽的情况下,整个界面,包括tty和ctrl-alt-F1都会卡住难以响应.虽然Linux内核有OOM Killer机制杀掉吃内存的进程,但经常内存用尽时连OOM Killer都无法动 ...
- js拖拽上传 文件上传之拖拽上传
由于项目需要上传文件到服务器,于是便在文件上传的基础上增加了拖拽上传.拖拽上传当然属于文件上传的一部分,只不过在文件上传的基础上增加了拖拽的界面,主要在于前台的交互, 从拖拽的文件中获取文件列表然后调 ...
- k8s 命令创建pod
[root@master kubernetes]# kubectl create deploy ngx-dep --image=nginx:1.14-alpine deployment.apps/ng ...
- 如何使用 Gin 和 Gorm 搭建一个简单的 API 服务 (三)
修改数据结构 基本的 API 已经定义好了,现在是个修改 Person 对象结构的好时机.只要修改 Person 结构体,数据库和 API 都会自动做出相应的修改. 我要做的是在 Person ...
- zookeeper的客户端常用操作
一,查看当前zookeeper的版本: [root@localhost conf]# echo stat|nc 127.0.0.1 2181 Zookeeper version: 3.5.6-c11b ...
- centos搭建离线epel源
准备 有一个联网的机器,并已经配置好epel源 安装reposync和createrepo命令 yum install yum-utils #reposync在这里 yum install creat ...