因业务需要,需将结果集序列化为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拦截器,对结果集进行拦截的更多相关文章

  1. Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求

    Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求 >>>>>>>>>>>>>>&g ...

  2. axios token header response request http拦截器 axios实现登录、拦截、登出

    axios token header response request http拦截器 axios实现登录.拦截.登出 一个项目学会前端实现登录拦截 https://github.com/superm ...

  3. springboot2.0+ 使用拦截器导致静态资源被拦截

    在spring1.0+的版本中,配置拦截器后是不会拦截静态资源的.其配置如下: @Configuration public class WebMvcConfig extends WebMvcConfi ...

  4. EntityFramework6.0的Sql读写分离拦截器 和 MVC的 Action拦截器 对比

    EF的DbCommandInterceptor类 拦截: EF6.1也出来不少日子了,6.1相比6.0有个很大的特点就是新增了System.Data.Entity.Infrastructure.Int ...

  5. struts2-权限拦截器、日志拦截器、execAndWait(进度条)拦截器配置

    1.权限拦截器 package login; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.Serv ...

  6. SpringMVC拦截器(实现登录验证拦截器)

    本例实现登陆时的验证拦截,采用SpringMVC拦截器来实现 当用户点击到网站主页时要进行拦截,用户登录了才能进入网站主页,否则进入登陆页面 核心代码 首先是index.jsp,显示链接 <%@ ...

  7. 在ASP.NET Core MVC中子类Controller拦截器要先于父类Controller拦截器执行

    我们知道在ASP.NET Core MVC中Controller上的Filter拦截器是有执行顺序的,那么如果我们在有继承关系的两个Controller类上,声明同一种类型的Filter拦截器,那么是 ...

  8. springboot项目配置拦截器,进行登陆等拦截

    新建拦截类: public class LoginInterceptor implements HandlerInterceptor{ private static Log logger = LogF ...

  9. SpringVC 拦截器+自定义注解 实现权限拦截

    1.springmvc配置文件中配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns= ...

  10. Struts2默认拦截器栈及内建拦截器使用具体解释

    Struts2内建拦截器介绍:   alias (别名拦截器):同意參数在跨越多个请求时使用不同别名,该拦截器可将多个Action採用不同名字链接起来,然后用于处理同一信息.  autowiring  ...

随机推荐

  1. Solon集成(02)- 轻松吃下小馒头 Dubbo

    Solon详解系列文章: Solon详解(一)- 快速入门 Solon详解(二)- Solon的核心 Solon详解(三)- Solon的web开发 Solon详解(四)- Solon的事务传播机制 ...

  2. Angular8 ie兼容性解决

    启用腻子脚本 polyfills.ts /* IE9, IE10 and IE11 requires all of the following polyfills. */ import 'core-j ...

  3. docker的run操作

    docker的run到底做了什么操作呢? 它会优先寻找本地的镜像,如果没有就到仓库找,找不到返回错误,查找不到该镜像.能找到就拉这镜像下来,以该镜像为模板生产容器实例运行. 备注:图不是自己画的,截图 ...

  4. 【5】进大厂必须掌握的面试题-Java面试-spring

    spring面试问题 Q1.什么是spring? Spring本质上是一个轻量级的集成框架,可用于用Java开发企业应用程序. Q2.命名Spring框架的不同模块. 一些重要的Spring Fram ...

  5. 身为电气人,为什么也要学习C语言编程?人生苦短,我学编程!

    说起编程大家可能都听过,但编程究竟是怎么一回事你弄懂了吗? 编程=对计算机程序进行编写,这些程序可以是现在手里拿着的手机.办公的电脑.你点击的页面.浏览的网页,都是有程序让它执行你要它做的事情. PL ...

  6. 快速掌握Java8 Stream函数式编程技巧

    函数式编程优势 "函数第一位",即函数可以出现在任何地方. 可以把函数作为参数传递给另一个函数,还可以将函数作为返回值. 让代码的逻辑更清晰更优雅. 减少了可变量(Immutabl ...

  7. 【CodeForces】835F Roads in the Kingdom

    一.题目 题目描述 王国有\(n\)座城市与\(n\)条有长度的街道,保证所有城市直接或间接联通,我们定义王国的直径为所有点对最短距离中的最大值,现因财政危机需拆除一条道路并同时要求所有城市仍然联通, ...

  8. spring boot: 用thymeleaf嵌套循环展示多层数据(spring boot 2.3.2)

    一,什么情况下会用到嵌套循环? 当我们展示多个分类时,每个分类下又展示出推荐的前几个商品,   这时我们需要用到嵌套循环 看一个例子: 说明:刘宏缔的架构森林是一个专注架构的博客,地址:https:/ ...

  9. CentOS 8 安装 oniguruma 和 oniguruma-devel

    一,oniguruma是什么? oniguruma是一个处理正则表达式的库,我们之所以需要安装它, 是因为在安装php7.4的过程中,mbstring的正则表达式处理功能对这个包有依赖性, 所以我们要 ...

  10. Hadoop框架:DataNode工作机制详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.工作机制 1.基础描述 DataNode上数据块以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是数据块元数据包括长度.校验.时 ...