Mybatis typealiaspackage 通配符扫描方法

最近两天项目需求研究了一下mybatis拦截器。对于Mybatis拦截器发现其功能强大,虽很灵活但是其内部对象转换太麻烦很多接口没有完全暴露出来。甚至不得不通过反射的方式去取其内部关联对象。可能Mybatis也不希望用户直接对其内部Statement,以及ResultSetHandler等进行操作。那这样与直接JDBC又有何区别呢? 

通用查询其实也并非完全通用。只能是稍微的简化一下代码,减少程序员一些重复的工作罢了。本项目采用springMVC + Mybatis + EasyUi 进行构建。设想一种应用场景。我一个统计查询:统计四张表里不同数据,或者多表关联查询:从A表当中查询三个字段,从B表当中查询二个字段,从C表当中查询一个字段,从D表当中查询两个字段。这种场景对于Mybaits来说。几张表的关联查询比较头痛。两种方式,一种是建立实体对象(VO)多表关联查询然后建立映射。返回其VO实体类。另一种方式通过对象关联的方式,Mapper.xml里进行配置。两种方式在此不作讨论。(PS:如有高手有更好的方式解决这种场景请不吝赐教) 

本文主要讨论通过Mybatis拦截器实现直接取其 ResultSet 通过约定的SQL语句格式解析后生成数据格式。或者直接JSON化传给前台以作展示。 

拦截器: 

    由于我们不关心对象与字段的映射关联。所以我们只需要在 ResultSetHandler 当中进行拦截就行了,拦截其handleResultSets方法。 

直接上代码: 

Java代码   收藏代码
  1. /* 
  2.  * E2ESQM-W 业务端故障诊断系统  
  3.  * FileName:MybatisPageInterceptor.java 
  4.  * Company: ZZNode Technology Co., Ltd. 
  5.  */  
  6. package com.zznode.e2esqm.core.commons;  
  7.   
  8. import java.lang.reflect.Field;  
  9. import java.sql.ResultSet;  
  10. import java.sql.Statement;  
  11. import java.util.ArrayList;  
  12. import java.util.HashMap;  
  13. import java.util.List;  
  14. import java.util.Map;  
  15. import java.util.Properties;  
  16.   
  17. import org.apache.ibatis.executor.resultset.ResultSetHandler;  
  18. import org.apache.ibatis.mapping.BoundSql;  
  19. import org.apache.ibatis.plugin.Interceptor;  
  20. import org.apache.ibatis.plugin.Intercepts;  
  21. import org.apache.ibatis.plugin.Invocation;  
  22. import org.apache.ibatis.plugin.Plugin;  
  23. import org.apache.ibatis.plugin.Signature;  
  24.   
  25. /** 
  26.  * Mybatis直接返回JSON格式拦截组件 
  27.  * @author wangkaiping 
  28.  * @version V1.0, 2013-5-17 下午11:43:16 
  29.  */  
  30. @Intercepts( {@Signature(method = "handleResultSets", type = ResultSetHandler.class, args = {Statement.class}) })  
  31. public class MybatisJsonInterceptor implements Interceptor{  
  32.       
  33.     @Override  
  34.     public Object intercept(Invocation invocation) throws Throwable {  
  35.         ResultSetHandler resultSetHandler = (ResultSetHandler) invocation.getTarget();  
  36.         BoundSql boundsql = (BoundSql) ReflectUtil.getFieldValue(resultSetHandler, "boundSql");  
  37.         String sql = boundsql.getSql();  
  38.         if(sql.indexOf("t_sys_privilege ch") != -1){ //测试代码写死的    这里应该根据SQL特殊标识进行解析  
  39.             String subSql = sql.substring(6, sql.indexOf("from"));  
  40.             System.out.println(subSql); // 解析字段格式为:  t.id as ID,t.name as 名称,t.age as 年龄   
  41.             String [] colmns = subSql.split(",");  
  42.             List<String> colmnsArr = new ArrayList<String>(); //字段别名集合。  
  43.             for(String i : colmns){  
  44.                 String [] asName = i.split("as");  
  45.                 colmnsArr.add(asName[1]);  
  46.             }  
  47.               
  48.             Statement statement = (Statement) invocation.getArgs()[0]; //取得方法的参数Statement  
  49.             ResultSet rs = statement.getResultSet(); // 取得结果集  
  50.             List<Map> list = new ArrayList<Map>(); // 方法要求返回一个List  list里装的是K,V的键值对。 K字段别名V值 以便后续JSON化前台直接展示  
  51.             while(rs.next()){  
  52.                 if(colmnsArr.size() >0) {  
  53.                     Map<String,Object> map = new HashMap<String,Object>();  
  54.                     for(int i=0 ;i<colmnsArr.size();i++){  
  55.                         Object obj = rs.getObject(colmnsArr.get(i).trim());  
  56.                         map.put(colmnsArr.get(i).trim(), obj); //取得结果集后K、V关联后放到MAP当中  
  57.                     }  
  58.                     list.add(map);  
  59.                 }  
  60.             }  
  61.             return list;//这里直接返回,不要再去invocation.proceed();  
  62.         }  
  63.         return invocation.proceed();  
  64.     }  
  65.   
  66.     @Override  
  67.     public Object plugin(Object target) {  
  68.         return Plugin.wrap(target, this);   
  69.     }  
  70.   
  71.     @Override  
  72.     public void setProperties(Properties properties) {  
  73.         System.out.println(properties.getProperty("databaseType"));   
  74.     }  
  75.       
  76.       
  77.     /** 
  78.      * 反射工具类 
  79.      * @author wangkaiping 
  80.      * @version V1.0, 2013-5-17 下午11:58:50 
  81.      */  
  82.     private static class ReflectUtil {  
  83.           
  84.         /** 
  85.          * 利用反射获取指定对象的指定属性 
  86.          * @param obj 目标对象 
  87.          * @param fieldName 目标属性 
  88.          * @return 目标属性的值 
  89.          */  
  90.         public static Object getFieldValue(Object obj, String fieldName) {  
  91.             Object result = null;  
  92.             Field field = ReflectUtil.getField(obj, fieldName);  
  93.             if (field != null) {  
  94.                 field.setAccessible(true);  
  95.                 try {  
  96.                     result = field.get(obj);  
  97.                 } catch (IllegalArgumentException e) {  
  98.                     // TODO Auto-generated catch block  
  99.                     e.printStackTrace();  
  100.                 } catch (IllegalAccessException e) {  
  101.                     // TODO Auto-generated catch block  
  102.                     e.printStackTrace();  
  103.                 }  
  104.             }  
  105.             return result;  
  106.         }  
  107.   
  108.         /** 
  109.          * 利用反射获取指定对象里面的指定属性 
  110.          * @param obj 目标对象 
  111.          * @param fieldName 目标属性 
  112.          * @return 目标字段 
  113.          */  
  114.         private static Field getField(Object obj, String fieldName) {  
  115.             Field field = null;  
  116.             for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz  
  117.                     .getSuperclass()) {  
  118.                 try {  
  119.                     field = clazz.getDeclaredField(fieldName);  
  120.                     break;  
  121.                 } catch (NoSuchFieldException e) {  
  122.                     // 这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。  
  123.                 }  
  124.             }  
  125.             return field;  
  126.         }  
  127.   
  128.         /** 
  129.          * 利用反射设置指定对象的指定属性为指定的值 
  130.          * @param obj 目标对象 
  131.          * @param fieldName 目标属性 
  132.          * @param fieldValue 目标值 
  133.          */  
  134.         public static void setFieldValue(Object obj, String fieldName,String fieldValue) {  
  135.             Field field = ReflectUtil.getField(obj, fieldName);  
  136.             if (field != null) {  
  137.                 try {  
  138.                     field.setAccessible(true);  
  139.                     field.set(obj, fieldValue);  
  140.                 } catch (IllegalArgumentException e) {  
  141.                     // TODO Auto-generated catch block  
  142.                     e.printStackTrace();  
  143.                 } catch (IllegalAccessException e) {  
  144.                     // TODO Auto-generated catch block  
  145.                     e.printStackTrace();  
  146.                 }  
  147.             }  
  148.         }  
  149.     }    
  150.   
  151. }  


Mybatis 整合 Spring 配置代码 。  这里我们重写了SqlSessionFactoryBean。所以这里用的是自己的。其中我们把我们的拦截器直接注入进去了。 

一个是分页的拦截器,一个是上面的我们的直接返回JSON格式的拦截器。 

Java代码   收藏代码
  1. <bean id="myBatisPageIntercept" class="com.zznode.e2esqm.core.commons.MybatisPageInterceptor">  
  2.         <property name="databaseType" value="oracle"></property>  
  3.     </bean>  
  4.     <bean id="myBatisJsonIntercept" class="com.zznode.e2esqm.core.commons.MybatisJsonInterceptor"></bean>  
  5.     <!-- SqlSessionFactory -->  
  6.     <bean id="sqlSessionFactory" class="com.zznode.e2esqm.core.commons.PackagesSqlSessionFactoryBean">  
  7.         <property name="dataSource" ref="dataSource" />  
  8.         <!-- 根据实际情况修改或添加多个 -->  
  9.         <property name="typeAliasesPackage" value="com.zznode.e2esqm.**.entity" />  
  10.         <property name="plugins">  
  11.             <list>  
  12.                                 <!-- 注入拦截器-->   
  13.                 <ref bean="myBatisPageIntercept"/>  
  14.                 <ref bean="myBatisJsonIntercept"/>  
  15.             </list>  
  16.         </property>  
  17.     </bean>   



重写的SqlSessionFactoryBean  代码如下 : 

Java代码   收藏代码
  1. package com.zznode.e2esqm.core.commons;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.apache.ibatis.plugin.Interceptor;  
  6. import org.apache.log4j.Logger;  
  7. import org.mybatis.spring.SqlSessionFactoryBean;  
  8.   
  9. import com.zznode.e2esqm.utils.PackageUtils;  
  10. import com.zznode.e2esqm.utils.Utils;  
  11.   
  12. /** 
  13.  * Spring Mybatis整合 
  14.  * 通过通配符方式配置typeAliasesPackage 
  15.  * @author sunjian   
  16.  * @version 1.0 2013-2-25 
  17.  */  
  18. public class PackagesSqlSessionFactoryBean extends SqlSessionFactoryBean{  
  19.       
  20.     private final static Logger log = Logger.getLogger(PackagesSqlSessionFactoryBean.class);  
  21.       
  22.     @Override  
  23.     public void setTypeAliasesPackage(String typeAliasesPackage) {  
  24.         List<String> list = PackageUtils.getPackages(typeAliasesPackage);  
  25.         if(list!=null&&list.size()>0){  
  26.             super.setTypeAliasesPackage(Utils.join(list.toArray(), ","));  
  27.         }else{  
  28.             log.warn("参数typeAliasesPackage:"+typeAliasesPackage+",未找到任何包");  
  29.         }  
  30.     }  
  31.   
  32.     @Override  
  33.     public void setPlugins(Interceptor[] plugins) {  
  34.         // TODO Auto-generated method stub  
  35.         super.setPlugins(plugins);  
  36.     }  
  37. }  



Mapper接口测试代码  注意SQL语句每个字段必须写,以as别名的方式生成JSON的 KEY 

方法 : 

@Select("select ch.id as ID,ch.name as 名称,ch.uri as URI,ch.icon as 图标,ch.description as 描述,ch.ord as 排序号") 
public List testPri(); 


测试返回结果 : 

[{图标=pencil, 排序号=12, 名称=角色管理, 状态=1, ID=4, 父ID=1, 描述=角色管理, 类型=1, URI=role/list.do}, {图标=pictures, 排序号=21, 名称=ITV测试, 状态=1, ID=5, 父ID=3, 描述=ITV测试, 类型=1, URI=itvTestAction.do?list}, {图标=pictures, 排序号=14, 名称=菜单权限, 状态=1, ID=8, 父ID=1, 描述=菜单权限, 类型=1, URI=privilege/toList.do}, {图标=pie, 排序号=13, 名称=部门管理, 状态=1, ID=6, 父ID=1, 描述=部门管理 , 类型=1, URI=department/department.do}, {图标=pie, 排序号=2, 名称=系统日志, 状态=1, ID=61, 父ID=60, 描述=系统日志, 类型=1, URI=systemLog/list.do}, {图标=pie, 排序号=3232, 名称=主界面, 状态=1, ID=10, 父ID=5, 描述=管理界面所有功能, 类型=2, URI=panel/*}, {图标=pie, 排序号=3232, 名称=权限功能, 状态=1, ID=11, 父ID=3, 描述=权限所有功能, 类型=2, URI=privilege/*}, {图标=pie, 排序号=3232, 名称=所有权限, 状态=1, ID=12, 父ID=3, 描述=42433424, 类型=2, URI=*}, {图标=pie, 排序号=2, 名称=全局参数, 状态=1, ID=62, 父ID=1, 描述=系统全局参数, 类型=1, URI=sysParameter/toList.do}, {图标=pencil, 排序号=1, 名称=系统管理, 状态=1, ID=1, 父ID=-1, 描述=系统管理, 类型=1, URI=#}, {图标=pie, 排序号=11, 名称=用户管理, 状态=1, ID=2, 父ID=1, 描述=用户管理, 类型=1, URI=user/list.do}, {图标=folder, 排序号=2, 名称=ITV测试, 状态=1, ID=3, 父ID=-1, 描述=ITV测试, 类型=1, URI=#}, {图标=pie, 排序号=31, 名称=日志管理, 状态=1, ID=60, 父ID=-1, 描述=日志管理, 类型=1, URI=systemLog/list.do}] 

这里只是我的测试代码,还有很多需要完善 

这里只是关于Mybatis实现一些需要关联或者多表联合查询,统计呀等类型查询方式的 一种解决方案。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值