1. 概述
上篇我们介绍了构建Activiti的环境基础及与Spring的整合,本篇则着重介绍Activiti中的底层ORM框架,以使得我们在后续的扩展Activiti的实现提供了基础的数据库访问功能。
2. 引入MyBatis依赖库
增加mybatis-spring依赖包,如上图所示,具体的pom.xml文件如附件中的文件所示,在这里不贴代码了。
3. 配置MyBatis与Spring的基础配置组件
MyBatis已经提供了与Spring的整合,其依赖包为mybatis-spring,具体整合如下连接所示:
http://mybatis.github.io/spring/zh/
3.1. 配置SqlSessonFactoryBean及事务管理
<!-- Mybatis的SessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath*:com/hotent/**/mapping/*.xml"/> </bean>
【说明】其中mapperLocations指向Mybatis的Mapping XML文件
3.2 编写MyBatis基础访问类
我们提供数据库访问的底层的基础封装,如CRUD的处理,借助JAVA的代码模板功能,可以满足所有的子类实现数据库的基础访问处理功能。如下所示:
3.2.1数据库分页实现
只需要接收其分页的页码与页大小就可以实现分页处理,鉴于此,借用mbatis的分页的rowbounds,传给mybatis的本身底层的封装则可以。若需要支持更多的不同数据库的有效分页,本文不作介绍,宏天的BPM X3产品有更深入的使用及扩展。
package com.hotent.page; import org.apache.ibatis.session.RowBounds; /** * * <pre> * 描述:数据库分页类 * 构建组:activiti * 作者:csx * 邮箱:chensx@jee-soft.cn * 日期:2014年5月12日-下午12:18:43 * 版权:广州宏天软件有限公司版权所有 * 网址:http://www.jee-soft.cn * </pre> */ public class DefaultPage extends RowBounds{ /** * 最多显示页码数 */ public static final int DEFAULT_PAGE_SIZE = 20; //页码大小 private Integer pageSize=DEFAULT_PAGE_SIZE; //总记录数 private Integer totalItems=0; //当前页码 private Integer pageNo=1; private boolean isShowTotal=true; public DefaultPage() { } public DefaultPage(Integer pageNo,Integer pageSize){ this.pageNo=pageNo; this.pageSize=pageSize; } @Override public int getOffset() { return getStartIndex(); } @Override public int getLimit() { return getPageSize(); } public Integer getStartIndex(){ return (pageNo-1)*pageSize; } public Integer getPageSize() { return pageSize; } public Integer getTotalItems() { return totalItems; } public void setTotalItems(Integer totalItems) { this.totalItems = totalItems; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } public Integer getPageNo() { return pageNo; } public void setPageNo(Integer pageNo) { this.pageNo = pageNo; } public boolean isShowTotal() { return isShowTotal; } public void setShowTotal(boolean isShowTotal) { this.isShowTotal = isShowTotal; } }
3.2.2 IDAO 接口
package com.hotent.dao; import java.io.Serializable; import java.util.List; import com.hotent.page.DefaultPage; /** * * <pre> * 描述:TODO * 构建组:activiti * 作者:csx * 邮箱:chensx@jee-soft.cn * 日期:2014年5月12日-上午9:23:26 * 版权:广州宏天软件有限公司版权所有 * </pre> */ public interface IDao<T,PK extends Serializable> { /** * 按ID获取实体 * @param id * @return */ public T get(PK id); /** * 按ID删除实体 * @param id */ public void remove(PK id); /** * 按ID创建实体 * @param entity */ public void create(T entity); /** * 更新实体 * @param entity */ public void update(T entity); /** * 查询所有实体列表 * @return */ public List<T> getAll(); /** * 按分页查询所有实体 * @param page * @return */ public List<T> getAllByPage(DefaultPage page); }
3.2.3 MyBatisDAO实现
package com.hotent.dao; import java.io.Serializable; import java.util.List; import javax.annotation.Resource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.support.SqlSessionDaoSupport; import com.hotent.page.DefaultPage; /** * * <pre> * 描述:TODO * 构建组:activiti * 作者:csx * 邮箱:chensx@jee-soft.cn * 日期:2014年5月12日-上午9:31:02 * 版权:广州宏天软件有限公司版权所有 * 网址:http://www.jee-soft.cn * </pre> */ public abstract class MyBatisDao<T,PK extends Serializable> extends SqlSessionDaoSupport{ /** * 按ID获取单一记录 */ protected final String OP_GET=".get"; /* * 按ID删除记录 */ protected final String OP_DEL=".remove"; /** * 按ID更新记录 */ protected final String OP_UPD=".update"; /** * 添加记录 */ protected final String OP_CREATE=".create"; /** * 查询记录列表 */ protected final String OP_GETALL=".getAll"; /** * 返回当前实体的命名空间字符串名称 */ public abstract String getNamespace(); public void create(T entity) { this.getSqlSession().insert(getNamespace() + OP_CREATE, entity); } public void update(T entity) { this.getSqlSession().update(getNamespace() + OP_UPD, entity); } public void remove(PK entityId) { this.getSqlSession().delete(getNamespace() + OP_DEL, entityId); } public T get(PK entityId) { return this.getSqlSession().selectOne(getNamespace() + OP_GET,entityId); } public List<T> getAll() { return this.getSqlSession().selectList(getNamespace() + OP_GETALL, null); } public List<T> getAllByPage(DefaultPage page){ return this.getSqlSession().selectList(getNamespace() + OP_GETALL, null,page); } }
【说明】通过继承Mybatis的SqlSessionDaoSupport, 以及其获取的getSqlSession()来实现数据库的访问,但要注意一点,后续的所有的继承该基类的Dao,需要注入 sqlSessionFactory或sqlSessionTemplate。因此,如我们写一个学生的DAO,在使用上我们则需要在Spring配置文 件中按如下配置:
<bean id="studentDao" class="com.hotent.example.dao.StudentDao"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean>
3.3 配置基础AOP的事务
<!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 事务AOP拦截控制配置 --> <aop:config proxy-target-class="true"> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.hotent.dao.MyBatisDao.*(..))"/> </aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="is*" read-only="true"/> <tx:method name="find*" read-only="true"/> <tx:method name="query*" read-only="true"/> <tx:method name="*" isolation="DEFAULT"/> </tx:attributes> </tx:advice>
4. 编写访问学生表的DAO配置测试的Dao,如下所示:
在Spring中增加该Dao的配置,如下所示:
<bean id="studentDao" class="com.hotent.example.dao.StudentDao"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean>
注意其引用了sqlSessionFactory
5. 编写测试用例编写一学生DAO测试用例,实现基础的数据库访问功能,如创建、获取列表等。
代码如下所示:
package com.hotent.example.dao; import com.hotent.dao.MyBatisDao; import com.hotent.example.entity.Student; public class StudentDao extends MyBatisDao<Student, String>{ @Override public String getNamespace() { return Student.class.getName(); } }
编写测试用例:
package com.hotent.test.example; import java.util.Date; import java.util.List; import java.util.UUID; import javax.annotation.Resource; import org.junit.Assert; import org.junit.Test; import org.springframework.test.annotation.Rollback; import com.hotent.example.dao.StudentDao; import com.hotent.example.entity.Student; import com.hotent.page.DefaultPage; import com.hotent.test.BaseTestCase; /** * * <pre> * 描述:TODO * 构建组:activiti * 作者:csx * 邮箱:chensx@jee-soft.cn * 日期:2014年5月12日-上午10:35:20 * 版权:广州宏天软件有限公司版权所有 * 网址:http://www.jee-soft.cn * </pre> */ public class StudentDaoTest extends BaseTestCase{ @Resource StudentDao studentDao; @Test @Rollback(false) public void testCreateStudent(){ String guid=UUID.randomUUID().toString(); int ranId=new Double(10000*Math.random()).intValue(); Student student=new Student(); student.setId(guid); student.setName("张三"+ranId); student.setSex(new Short("1")); student.setBirthday(new Date()); student.setDesc("张三个人简介"); studentDao.create(student); Student student2=studentDao.get(guid); Assert.assertNotNull(student2); } @Test public void testGetAll(){ List<Student> list=studentDao.getAllByPage(new DefaultPage(1, 10)); Assert.assertTrue(list.size()>0); for(Student student:list){ System.out.println("student:" + student.getName()); } } }
执行如下结果如下所示:
【总结】
通过以上整合后,可以看到借助Mybatis实现数据库的访问其实很简单,但若手工来编写Mybatis的映射mapping文件其实是很繁琐的工作,宏天X3平台则提供代码生成器的方式来生成这些配置文件,甚至包括各个层次的代码部分。在本文则不作介绍,后续的Activiti的任务查询扩展我们则可以 基于该类进行二次开发。
具体的实现代码如附件: