自定義mybatis map返回類(lèi)型

1.需求背景

設(shè)定訂單表order暖呕,要根據(jù)訂單類(lèi)型統(tǒng)計(jì)訂單數(shù)據(jù)勾栗,大致sql如下:

select order_type , count(1)  as order_num from order group by order_type;

Mybatis無(wú)法將以上sql以指定key:order_type;value:order_num存入至map中。

而Mybatis默認(rèn)返回的List<Map<String, Object>>遏插,是以每個(gè)字段name作為key调煎,字段的值作為value蔫磨,放入至Map<String,Object>的List數(shù)組纳寂。
因此自定義一種可以指定key主穗、value字段的Mybatis插件將非常有用。

2.自定義Mybatis攔截器實(shí)現(xiàn)Mybaits Map返回類(lèi)型

有關(guān)于Mybatis攔截器的介紹請(qǐng)參閱Mybatis攔截器毙芜;

由Mybatis源碼可知忽媒,返回結(jié)果集是ResultSetHandler接口的handleResultSets方法實(shí)現(xiàn)的,源碼如下:

public interface ResultSetHandler {  
      <E> List<E> handleResultSets(Statement stmt) throws SQLException; 
      void handleOutputParameters(CallableStatement cs) throws SQLException;
}

當(dāng)我們需要返回Map時(shí)腋粥,只需要對(duì)此方法進(jìn)行攔截晦雨,重新組裝返回結(jié)果數(shù)據(jù);當(dāng)需要攔截時(shí)隘冲,執(zhí)行invocation.proceed()闹瞧。首先我們定義MapParam.java類(lèi),用去標(biāo)識(shí)結(jié)果集需要攔截展辞,此外在該類(lèi)中指定返回結(jié)果集Map的key和value名稱(chēng)奥邮,以及value返回類(lèi)型。MapParam代碼如下:

public class MapParam extends HashMap {   
      // key名稱(chēng) 
      public static final String KEY_FIELD = "keyField";    
      // value名稱(chēng) 
      public static final String VALUE_FIELD = "valueField";    
      // value值類(lèi)型 
      public static final String VALUE_CLASS = "valueClass";    
      public MapParam(){    }    
      public MapParam(String keyField, String valueField, String valueClass){        
                this.put(KEY_FIELD, keyField);        
                this.put(VALUE_FIELD, valueField);        
                this.put(VALUE_CLASS, valueClass);    }   
      // value值類(lèi)型枚舉類(lèi) 
      public enum ValueClass {        
                INTEGER("integer"),        
                BIG_DECIMAL("bigDecimal");        
                private String code;       
                public String getCode() {            
                         return code;        
                }        
                ValueClass(String code){            
                        this.code = code;       
                }    
       }
}

通過(guò)類(lèi)MapParam罗珍,我們可以定義key和value的字段值洽腺,還可以定義value的值類(lèi)型;

接下來(lái)覆旱,我們定義MapInterceptor.java蘸朋,通過(guò)對(duì)返回結(jié)果集方法handleResultSets攔截,返回需要指定的Map數(shù)據(jù)扣唱。少說(shuō)廢話(huà)藕坯,直接上代碼:

@Intercepts(@Signature(method="handleResultSets", type=ResultSetHandler.class, args={Statement.class}))
public class MapInterceptor implements Interceptor {    
         //日志    private static final Logger logger = LoggerFactory.getLogger(MapInterceptor.class);    
         @Override    
        public Object intercept(Invocation invocation) throws Throwable {        
              // 獲取代理目標(biāo)對(duì)象        
             Object target = invocation.getTarget();        
             if (target instanceof DefaultResultSetHandler) { 
             DefaultResultSetHandler resultSetHandler = (DefaultResultSetHandler) target;           
             // 利用反射獲取參數(shù)對(duì)象            
             ParameterHandler parameterHandler = reflect(resultSetHandler);
            Object parameterObj = parameterHandler.getParameterObject();
            // 參數(shù)對(duì)象為MapParam進(jìn)入處理邏輯            
            if (parameterObj instanceof MapParam) {
                    MapParam mapParam = (MapParam) parameterObj;               
                   // 獲取當(dāng)前statement                
                   Statement stmt = (Statement) invocation.getArgs()[0];               
                  // 根據(jù)maoParam返回處理結(jié)果               
                   return handleResultSet(stmt.getResultSet(), mapParam);            
             }       
           }       
 return invocation.proceed();   
 }
@Override
public Object plugin(Object target) {    
          return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}

private Object handleResultSet(ResultSet resultSet, MapParam mapParam){   
          if (null != resultSet){        
          // 獲取key field name        
          String keyFieldName = (String)mapParam.get(MapParam.KEY_FIELD);
          // 獲取value field name        
          String valueFieldName = (String)mapParam.get(MapParam.VALUE_FIELD);        
         // 值類(lèi)型        
         String valueClass = (String) mapParam.get(MapParam.VALUE_CLASS);
          List<Object> resultList = new ArrayList<Object>();        
          Map<Object, Object> map = new HashMap<Object, Object>();        
         try {            
              while (resultSet.next()) {                
              Object key = resultSet.getObject(keyFieldName);                
               Object value ;               
               // 根據(jù)值類(lèi)型轉(zhuǎn)換值               
                if (StringUtils.equals(valueClass, MapParam.ValueClass.INTEGER.getCode())) {                    
                     value = resultSet.getInt(valueFieldName);                
               } else if(StringUtils.equals(valueClass, MapParam.ValueClass.BIG_DECIMAL.getCode())) {                    
                     value = resultSet.getBigDecimal(valueFieldName);                
               } else {                    
                    value = resultSet.getObject(valueFieldName);               
             }               
                   map.put(key, value);            
            }        
           } catch (SQLException e) {            
                   logger.error("map interceptor轉(zhuǎn)換異常,{}", e.getMessage());        
           } finally {            
                   // 關(guān)閉result set            
                  closeResultSet(resultSet);        
         }       
          resultList.add(map);        
          return resultList;    
}    
return  null;
}

private void closeResultSet(ResultSet resultSet) {    
         try {       
                 if (resultSet != null) {            
                        resultSet.close();        
                 }    
             } catch (SQLException e) {        
                  logger.error("關(guān)閉 result set異常,{}", e.getMessage());   
                 }
}

private ParameterHandler reflect(DefaultResultSetHandler resultSetHandler){
      Field field = ReflectionUtils.findField(DefaultResultSetHandler.class, "parameterHandler");    
      field.setAccessible(true);    
      Object value = null;    
      try {       
               value = field.get(resultSetHandler);    
       } catch (Exception e) {        
              logger.error("默認(rèn)返回結(jié)果集反射參數(shù)對(duì)象異常噪沙,{}", e.getMessage()); 
      }    
     return (ParameterHandler)value;
}

@Intercepts(@Signature(method="handleResultSets", type=ResultSetHandler.class, args={Statement.class}))注解代碼含義炼彪,@Intercepts用于表示該類(lèi)為攔截器,@Signature用于標(biāo)識(shí)需要攔截的方法名曲聂、返回類(lèi)型及方法參數(shù)值霹购。

進(jìn)入ResultSetHandler的handleResultSets方法,都會(huì)進(jìn)入此攔截器朋腋,當(dāng)需要的請(qǐng)求參數(shù)為類(lèi)MapParam時(shí)齐疙,執(zhí)行處理,否則執(zhí)行invocation.proceed()旭咽。
代碼寫(xiě)的很詳細(xì)贞奋,再次無(wú)需再重復(fù)講述。

3.具體實(shí)現(xiàn)

注冊(cè)攔截器:

<bean id="sqlSessionFactory" 
        <property name="plugins">        
              <array>            
                    <bean class="com.test.common.interceptor.MapInterceptor"/>        
              </array>    
          </property>
</bean>

dao層代碼:

MapParam params = new MapParam("orderType","orderNum",MapParam.ValueClass.INTEGER.getCode());
Map<String,Integer> find(MapParam params);

xml代碼:

<select id="find" resultType="map" parameterType="MapParam">  
    select order_type as orderType , count(1)  as orderNum from order group by order_type;
</select>  

打印結(jié)果格式:
“mobileOrder”:“100”
“partsOrder”:“200”
“normalOrder”:“500”

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末穷绵,一起剝皮案震驚了整個(gè)濱河市轿塔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖勾缭,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揍障,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡俩由,警方通過(guò)查閱死者的電腦和手機(jī)毒嫡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)幻梯,“玉大人兜畸,你說(shuō)我怎么就攤上這事〉馍遥” “怎么了咬摇?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)煞躬。 經(jīng)常有香客問(wèn)我肛鹏,道長(zhǎng),這世上最難降的妖魔是什么汰翠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任龄坪,我火速辦了婚禮昭雌,結(jié)果婚禮上复唤,老公的妹妹穿的比我還像新娘。我一直安慰自己烛卧,他們只是感情好佛纫,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著总放,像睡著了一般呈宇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上局雄,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天甥啄,我揣著相機(jī)與錄音,去河邊找鬼炬搭。 笑死蜈漓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宫盔。 我是一名探鬼主播融虽,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼灼芭!你這毒婦竟也來(lái)了有额?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎巍佑,沒(méi)想到半個(gè)月后茴迁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萤衰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年笋熬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腻菇。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡胳螟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出筹吐,到底是詐尸還是另有隱情糖耸,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布丘薛,位于F島的核電站嘉竟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏洋侨。R本人自食惡果不足惜舍扰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望希坚。 院中可真熱鬧边苹,春花似錦、人聲如沸裁僧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)聊疲。三九已至茬底,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間获洲,已是汗流浹背阱表。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贡珊,地道東北人最爬。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像飞崖,于是被迫代替她去往敵國(guó)和親烂叔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis 固歪? MyBatis 是支持定制化 SQL蒜鸡、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的...
    笨鳥(niǎo)慢飛閱讀 5,527評(píng)論 0 4
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理胯努,服務(wù)發(fā)現(xiàn),斷路器逢防,智...
    卡卡羅2017閱讀 134,711評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法叶沛,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法忘朝,繼承相關(guān)的語(yǔ)法灰署,異常的語(yǔ)法,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,664評(píng)論 18 399
  • 隔了半年之后的蘋(píng)果。ヽ(  ̄д ̄;)ノ
    Mister_閱讀 201評(píng)論 0 2