關於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,調用下一個攔截器攔截目標方法。

             


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM