zoukankan      html  css  js  c++  java
  • 关于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,调用下一个拦截器拦截目标方法。

                 

  • 相关阅读:
    Asp.net MVC 利用 Nopi 导出 Excel
    React 中 调用 Asp.net WebApi
    Node.js mysql 连接池使用事务自动回收连接
    __far和__near的小问题
    注册博客园了,以后在这里写写随笔。
    Electron客户端开发入门必备的知识点
    公司组织构架的三大类型
    经济学中的人性抉择(下)
    经济学中的人性抉择(上)
    模拟音乐播放器播放条样式
  • 原文地址:https://www.cnblogs.com/SmallHan/p/8127327.html
Copyright © 2011-2022 走看看