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

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

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实现一些需要关联或者多表联合查询,统计呀等类型查询方式的 一种解决方案。

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

原文地址:https://www.cnblogs.com/skinchqqhah/p/10350010.html

时间: 2024-11-13 08:52:06

Mybatis typealiaspackage 通配符扫描方法的相关文章

Spring整合MyBatis (使用扫描包配置mapper代理)

Spring整合MyBatis (使用扫描包配置mapper代理) pojo是根据表生成的实体类,属性名要跟字段名相同,不相同sql语句查询时用别名. 首先导jar包 实体类 public class User { private Integer id; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址 } 1 2 3

mybatis开发dao的方法

mybatis开发dao的方法 1.1     SqlSession使用范围 1.1.1     SqlSessionFactoryBuilder 1 //以流的方式读取总的配置文件 2 Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); 3 4 //生成SqlSessionFactory 5 SqlSessionFactory sqlSessionFactory = new SqlSessionFa

mybatis(基于annotation的方法知道就行了)

MyBatisUtil.java UserMapper.java package edu.hhxy.btais.util; import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFacto

转:spring与mybatis三种整合方法

哎,csdn没转载功能,只能复制了.. 本文主要介绍Spring与Mybatis三种常用整合方法,需要的整合架包是mybatis-spring.jar,可通过链接http://code.google.com/p/mybatis/下载到. 1.采用数据映射器(MapperFactoryBean)的方式,不用写mybatis映射文件,采用注解方式提供相应的sql语句和输入参数.  (1)Spring配置文件: <!-- 引入jdbc配置文件 -->     <context:property

struts2.5框架使用通配符指定方法常见错误

struts2.5框架使用通配符指定方法(常见错误) 在学习struts框架时经常会使用到通配符调用方法,如下: <package name="shop" namespace="/" extends="struts-default"> <!-- 配置Action --> <actionname="user_*" class="userAction" method="{

MyBatis学习--mybatis开发dao的方法

简介 使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法. 主要概念介绍: MyBatis中进行Dao开发时候有几个重要的类,它们是SqlSessionFactoryBuilder.SqlSessionFactory.SqlSession. SqlSession中封装了对数据库的操作,如:查询.插入.更新.删除等.通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryB

spring与mybatis三种整合方法

1.采用MapperScannerConfigurer,它将会查找类路径下的映射器并自动将它们创建成MapperFactoryBean.spring-mybatis.xml: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.

mybatis常用经典分页方法

来自棱镜学院-在线IT教育www.prismcollege.com 分页方法一: 可以查看如下代码,新建一个数据库分页基础类 package com.ssm.utils.pagination.pagebounds; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spr

求最大子数组的和,算法导论只分治递归求解,暴力求解,记忆扫描方法。

#include<iostream> #include<vector> using namespace std; /*******************************************************************************************/ // 分治方法,利用递归的思想 // ugly_chen 2014.11.3 22:24 //说明:把数组分为两部分,右边部分和左边部分,要不就是右边部分和左边部分之和. // ---