Java EE开发平台随手记2——Mybatis扩展1

  今天来记录一下对Mybatis的扩展,版本是3.3.0,是和Spring集成使用,mybatis-spring集成包的版本是1.2.3,如果使用maven,如下配置:

<properties>元素下添加

1 <mybatis.version>3.3.0</mybatis.version>
2 <mybatis.spring.version>1.2.3</mybatis.spring.version>

<dependencies>元素下添加

 1 <dependency>
 2   <groupId>org.mybatis</groupId>
 3   <artifactId>mybatis</artifactId>
 4   <version>${mybatis.version}</version>
 5 </dependency>
 6 <dependency>
 7   <groupId>org.mybatis</groupId>
 8   <artifactId>mybatis-spring</artifactId>
 9   <version>${mybatis.spring.version}</version>
10 </dependency>

  mybatis-spring的集成配置如下:

 1 <bean id="DialectDatabaseIdProvider" class="com.forms.beneform4j.core.dao.mybatis.provider.DialectDatabaseIdProvider"/>
 2     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" p:sqlSessionFactoryBeanName="sqlSessionFactory" p:basePackage="com.forms"
 3         p:annotationClass="org.springframework.stereotype.Repository"/>
 4     <bean id="sqlSessionFactory" p:dataSource-ref="dataSource" class="com.forms.beneform4j.core.dao.mybatis.SqlSessionFactoryBeanForSpring"
 5         p:configLocation="classpath:mybatis/mybatis-config.xml" p:databaseIdProvider-ref="DialectDatabaseIdProvider">
 6         <property name="mapperLocations">
 7             <array>
 8                 <value>classpath*:sql-mapper/ds1/*.xml</value>
 9                 <value>classpath*:com/forms/beneform4j/**/*.ds1.xml</value>
10             </array>
11         </property>
12     </bean> 

这里的p:databaseIdProvider-ref="DialectDatabaseIdProvider"算是我们的第一个扩展:

扩展1:添加自定义的数据库ID提供者

  添加这个扩展的目的,是为了能够根据不同的数据库写不同的sql-mapper配置,比如如下的配置,就可兼容不同数据库:

 1 <choose>
 2     <when test="_databaseId == ‘oracle‘">
 3     </when>
 4     <when test="_databaseId == ‘db2‘">
 5     </when>
 6     <when test="_databaseId == ‘mysql‘">
 7     </when>
 8     <when test="_databaseId == ‘oracle‘">
 9     </when>
10     <when test="_databaseId == ‘ase‘">
11     </when>
12     <when test="_databaseId == ‘iq‘">
13     </when>
14     <when test="_databaseId == ‘h2‘">
15     </when>
16 </choose>

那这里的oracle、db2字符串是怎么确定的呢?这就是名称为DialectDatabaseIdProvider的bean所做的事情了,基本上和Mybatis原生提供的VendorDatabaseIdProvider类似,根据数据源对象DataSource获取DatabaseMetaData,继而调用getDatabaseProductName获取产品名称,然后根据配置好的关键字确定数据库类型。可能读者会觉得这个扩展没多大必要,直接使用VendorDatabaseIdProvider就好了,的确如此,除了自己写的类有更大的控制权之外,没有增加多少功能。但DialectDatabaseIdProvider的实现是从数据库方言角度来做的,从这里可以引出第二个扩展:

扩展2:实现物理分页

Mybatis的分页查询是逻辑分页,这对于大多数应用是不适合的,于是需要实现物理分页。

主要的实现步骤:

1、添加数据库方言接口

 1 public interface IDialect {
 2
 3     /**
 4      * 数据库类型
 5      */
 6     enum DBType {
 7         Oracle, DB2, H2, MySql, ASE, IQ
 8     }
 9
10     /**
11      * 获取数据库类型
12      * @return 数据库类型枚举常量
13      */
14     public DBType getType();
15
16     /**
17      * 获取可能的数据库驱动类名称
18      * @return 驱动类名数组
19      */
20     public String[] getDriverClassNames();
21
22     /**
23      * 生成计算总记录数的SQL
24      * @param sql 原始SQL
25      * @return 计算总记录数的SQL
26      */
27     public String getTotalSql(String sql);
28
29     /**
30      * 获取查询指定范围记录的SQL
31      * @param sql     原始SQL
32      * @param offset  返回的开始记录索引
33      * @param limit   查询的数据大小
34      * @return 查询第(offset, offset + limit]条记录的SQL,索引从1开始
35      */
36     public String getScopeSql(String sql, long offset, int limit);
37 }

不同的数据库具体怎么实现就不贴了;

2、添加mybatis分页和物理分页的适配类

1 public class PageAdapter extends RowBounds{
2
3 }

在调用Mybatis的分页查询时,使用该适配类参数,例如:

1 public <E> List<E> selectList(String sqlId, Object parameter, IPage page) {
2         RowBounds adapter = new PageAdapter(page);
3         return sqlSession.selectList(sqlId, parameter, adapter);
4 }

这里IPage封装了分页对象,可以获取当前页数、分页大小等等。

3、编写Mybatis插件,拦截sql执行,如果包含PageAdapter参数,则做分页逻辑处理

(1)获取数据库方言接口的具体实现类,这里可以根据Connection对象识别、也可以使用ThreadLocal对象,还可以在适配类中添加方言对象传进来

(2)如果需要计算总记录条数(分页对象中不包含总记录数),根据数据库方言,获取计算总记录条数的sql,然后执行,并将总计录条数反写会分页对象

(3)根据数据库方言和分页对象,获取需要从数据库查询的当前页数据的sql,然后调用拦截器的执行方法继续之前执行

4、将mybatis插件配置到spring配置文件或mybatis配置文件中,启用该插件即可。

  说到Mybatis插件,实际上并不只是做了分页处理一件事,还可以格式化sql、进行sql拦截处理等等,这里就包括我们的第三个扩展:

扩展3:SQL拦截1——语句拦截

主要的实现步骤:

1、添加SQL字符串拦截接口

 1 public interface ISqlInterceptor {
 2
 3     /**
 4      * 执行SQL拦截
 5      * @param jndi    数据源
 6      * @param src     原SQL
 7      * @param context 上下文环境
 8      * @param root    根对象
 9      * @return 拦截后的SQL
10      */
11     public String intercept(IJndi jndi, String src, Map<String, Object> context, Object root);
12 }

这里的IJndi对象是数据源对象的一个抽象,可以获取相应的数据库方言对象、和数据源对应的特定属性等

 1 public interface IJndi{
 2
 3     /**
 4      * 获取数据源名称
 5      * <p>
 6      *       默认为spring配置中的beanId
 7      * </p>
 8      * @return 数据源名称
 9      */
10     public String getName();
11
12     /**
13      * 是否默认数据源
14      * <p>
15      *   默认情况下,如果spring配置中的beanId等于dataSource(不区分大小写)则设置为默认数据源,如果不存在dataSource,则设置第一个数据源为默认数据源
16      * </p>
17      * @return 是否默认数据源
18      */
19     public boolean isDefault();
20
21     /**
22      * 获取数据库方言
23      * <p>
24      *      根据数据库产品名称自动判断哪个数据库方言
25      * </p>
26      * @return 和数据源对应的数据库方言
27      */
28     public IDialect getDialect();
29
30     /**
31      * 获取数据源
32      * @return 对应的数据源
33      */
34     public DataSource getDataSource();
35
36     /**
37      * 获取属性
38      * @return
39      */
40     public Properties getProperties();
41 }

2、在平台配置中,添加sql拦截的配置,可以配置一系列的拦截

3、在Mybatis插件中,根据Mybatis执行上下文找到IJndi对象、参数对象、拦截前的sql,调用平台配置中的sql拦截,并将返回值反写会mybatis上下文中

  可能有人会问,这种语句拦截有什么作用呢?

  其实我们就是利用这种机制,来实现不同应用系统使用不同的表前缀,比如平台中有一个BF_USER表,A系统建表的时候统一添加A_前缀,B系统建表的时候统一添加前缀B_,那么,在平台中怎么知道访问的具体表呢?我们的做法是,在平台中添加一个平台表前缀的配置,然后实现一个SQL拦截,将符合特别语法{{BF}}的替换为Beneform4jConfig.getBeneform4jTablePrefix() + "BF",这种SQL语句的拦截,有点类似于使用${}语法。

扩展4:SQL拦截2——参数拦截

  如果是SQL语句拦截是使用${}语法,那么参数拦截则是#{}语法了。

主要实现步骤:

1、添加参数拦截接口

 1 public interface IStatementParameterResolver {
 2
 3     /**
 4      * 是否可以解析表达式
 5      * @param jndi  数据源对象
 6      * @param expression 表达式
 7      * @return 如果可以解析,返回true,否则返回false
 8      */
 9     public boolean isSupport(IJndi jndi, String expression);
10
11     /**
12      * 执行参数解析
13      * @param jndi  数据源对象
14      * @param parameterObject  参数对象
15      * @param expression       表达式
16      * @return 解析后的值
17      */
18     public Object resolver(IJndi jndi, Object parameterObject, String expression);
19 }

这里有两个方法,第一个方法判断当前的拦截器实现类是否支持#{}内部的表达式,如果支持,就调用第二个方法处理参数。这种先判断是否支持,然后在支持的情况下再继续处理的类责任链模式在Spring MVC中用的也相当普通。

2、编写Mybatis原生接口ParameterHandler的实现类,在其中调用参数拦截接口来实现不同参数的解析

3、在Mybatis插件中,替换ParameterHandler接口的实现类。

  在新平台中,利用参数拦截主要实现了一种效果,就是在mybatis的sql-mapper文件中直接执行SpEL表达式或OGNL表达式。例如:

1 <select id="selectList">
2         SELECT * FROM BF_PARAM_ENUM_DEF
3         <where>
4             <if test="null != paramCode and ‘‘ != paramCode">
5             and PARAM_CODE = #{@bean.getName(), jdbctType=VARCHAR}
6             </if>
7         </where>
8     </select>

这里的bean是Spring容器管理的bean,getBean就是调用其getBean方法了。

  今天记录到这里,下周继续。

时间: 2024-08-28 23:15:15

Java EE开发平台随手记2——Mybatis扩展1的相关文章

Java EE开发平台随手记6——Mybatis扩展4

这篇博客中来说一下对Mybatis动态代理接口方式的扩展,对于Mybatis动态代理接口不熟悉的朋友,可以参考前一篇博客,或者研读Mybatis源码. 扩展11:动态代理接口扩展 我们知道,真正在Mybatis动态代理接口方式背后起作用的是SqlSession接口,类似地,我们的动态代理接口扩展则是基于IDaoTemplate接口,同样的,也需要解决相同的三个基本问题: 问题1:确定需要执行的sqlId 原生用法是根据包名.接口名.方法名去查找,但我们推荐添加一个sqlId的查找策略接口: pu

Java EE开发平台随手记5——Mybatis动态代理接口方式的原生用法

为了说明后续的Mybatis扩展,插播一篇广告,先来简要说明一下Mybatis的一种原生用法,不过先声明:下面说的只是Mybatis的其中一种用法,如需要更深入了解Mybatis,请参考官方文档,或者研读源码. 我们知道,使用Mybatis的方式有很多种,从是否集成上分,可以单独使用,也可以和Spring集成使用:从使用方式上分,可以编写静态工具类,在静态工具中调用SqlSession,也可以直接注入SqlSession/ SqlSessionTemplate,还可以编写Dao接口,让mybat

Java EE开发平台随手记1

过完春节以来,一直在负责搭建公司的新Java EE开发平台,所谓新平台,其实并不是什么新技术,不过是将目前业界较为流行的框架整合在一起,做一些简单的封装和扩展,让开发人员更加易用. 和之前负责具体的项目开发不同,不能只是功能实现就可以,还需要考虑更多的非功能性需求,比如性能.安全性.易用性.可维护性.易扩展性.兼容性等等,因此有很多在实际项目中觉得方便易用的功能不得不因种种原因而舍弃:另一方面,也常常会偶尔有一些新想法.新构想,但因缺乏实践论证,也往往没有加入进来:此外,对于平台中已经添加的那些

java快速开发平台可视化开发表单

XJR java快速开发平台,简单的理解就是:开发人员以某种编程语言或者某几种编程语言(比如:目前流行的多种web技术,包括springboot, JPA,Druid, Activiti,Lombok,swagger,poi,WebSocket,Jquery,BootStrap, maven,Jenkins 等等 )为基础,将各种需要的功能封装在不同的层中,具大家调用而开发出来的一个软件. 这个软件其实不是一个最终的软件产品,它是一个二次开发软件框架,用户可以在这个产品上进行各种各样的软件产品的

JAVA高速开发平台 - 开源 免费 - JEECG

JEECG 微云高速开发平台 当前最新版本号: 3.6.2(公布日期:20160315) 下载地址:http://git.oschina.net/jeecg/jeecg 前言: 随着 WEB UI 框架 ( EasyUI/Jquery UI/Ext/DWZ) 等的逐渐成熟,系统界面逐渐实现统一化,代码生成器也能够生成统一规范的界面! 代码生成+手工MERGE半智能开发将是新的趋势,单表数据模型和一对多数据模型的增删改查功能直接生成使用,可节省60%工作量,高速提高开发效率!! ! 简单介绍 JE

Java EE开发四大常用框架

我们对Java EE的框架有过很多介绍, 本文将对Java EE中常用的四个框架做一下系统的归纳,希望大家喜欢. Struts Struts是一个基于Sun Java EE平台的MVC框架,主要是采用Servlet和JSP技术来实现的. Struts框架可分为以下四个主要部分,其中三个就和MVC模式紧密相关: 1.模型 (Model),本质上来说在Struts中Model是一个Action类(这个会在后面详细讨论),开发者通过其实现商业逻辑,同时用户请求通过控制器(Controller)向Act

JAVA快速开发平台 - 开源 免费 - JEECG

JEECG 微云快速开发平台 当前最新版本: 3.6.2(发布日期:20160315) 下载地址:http://git.oschina.net/jeecg/jeecg 前言: 随着 WEB UI 框架 ( EasyUI/Jquery UI/Ext/DWZ) 等的逐渐成熟,系统界面逐渐实现统一化,代码生成器也可以生成统一规范的界面! 代码生成+手工MERGE半智能开发将是新的趋势,单表数据模型和一对多数据模型的增删改查功能直接生成使用,可节省60%工作量,快速提高开发效率!!! 简介 JEECG(

Java EE开发的四大框架

Java EE中最常用的四个框架分别是:Struts.Spring.Hibernate.Swing.下面就说说这四个框架的特点,希望大家喜欢. Struts Struts是一个基于Sun Java EE平台的MVC框架,主要是采用Servlet和JSP技术来实现的. Struts框架可分为以下四个主要部分,其中三个就和MVC模式紧密相关: 1.模型 (Model),本质上来说在Struts中Model是一个Action类(这个会在后面详细讨论),开发者通过其实现商业逻辑,同时用户请求通过控制器(

Java EE 开发环境搭建

下载安装Java EE SDK 版本:Java Platform,Enterprise Edition 7 SDK (with JDK 7u45) 下载页面: http://www.oracle.com/technetwork/java/javaee/downloads/java-ee-7-sdk-with-jdk-u45-2066865.html 文件名:java_ee_sdk-7-jdk7-windows.exe 安装路径:D:\glassfish4 环境变量设置 JAVA_HOME=D:\