SSH+Activiti+Dbutil框架搭建旅程(附源码)
来源:互联网 发布:usb端口检测软件 编辑:程序博客网 时间:2024/04/24 01:23
最近公司在做一个类似于接口管理的小型的系统,老板安排小编来亲自搭建一套框架,于是小编硬着头皮开始了第一个架构之旅。下面就来谈一下小编整个的分析。
技术选型篇
根据目前的项目的大小,就是类似于一个工作流管理的接口流程,于是小编根据目前项目的情况,于是就定下了Struts2+Spring+Hibernate+Activiti,再加上我们的Tomact服务器,就可以搞定了。技术选型就这样结束了,主要是项目的要求不高,像高并发、多线程等问题就设计不到,所以非常的简单。至于项目管理工具,经小伙伴们的要求,用的是目前流程的分布式项目管理工具Git,基本就这么多了。
框架设计篇
有了初步的技术选型,小编就开始了框架搭建。先看一下整体包图结构。
有了宏观的认识,下面小编来一点一点的来分析下整个流程。
Dao层
由于Dao用的是Hibernate,所以在设计的时候就直接用了HiberanteTemplate,这样很方便,毕竟是别人都给封装好的框架,但是小编又知道Hibernate批量插入操作的话,又会涉及到性能的问题,因此设计了另外一层Dao层,用纯JDBC封装的Dao层,这样的话,如果大批量操作的话,就可以解决性能问题了。
从上图中可以看出,整个把所有的泛型方法都抽象到了BaseDao中,这里面分别包括两部分,一部分是Hibernate的增删、改查;另一部分时纯JDBC的增删改查操作。然后然自己每个数据访问Dao层直接继承上述两个即可。在这个过程中曾出现过问题,如果学习过Apache Dbutil框架的话,我们知道protected QueryRunner runner,需要注入数据源,在这个过程中,小编通过HibernateTemplate各种方法来注入,都不成功,最终通过SessionFactoryUtils来解决的,如下所示
SessionFactoryUtils.getDataSource(sessionFactory);
其实也并不难,我们试想Hibernate的底层也就是把JDBC给封装了而已。
Service层
有了Dao的封装,下面来看一下Servcie的封装,小编把那些单一的业务逻辑操作,也给抽象了一层,防止每个具体的业务逻辑层写一些重复的单一的业务逻辑方法,比如都根据ID查询某张表的操作,直接抽象一层而已。
如上图所示,小编把单一的业务逻辑抽象了一层BaseServce,并且找了一层实现BaseServiceImpl,以后每个业务逻辑层,只要让接口继承BaseService,让业务实现继承BaseServiceImpl即可,这样就实现了单一业务逻辑的抽象。
Controller层
控制层小编也抽象了一层,抽象出一个BaseAction,在里面把所有的工作流的组件服务直接给注入进去了。并且还让这个BaseAction继承了ActionSupport,同时实现了ModelDriven。
<span style="font-family:Comic Sans MS;font-size:18px;">package com.tgb.interfaceSystem.Base;import java.lang.reflect.ParameterizedType;import javax.annotation.Resource;import org.activiti.engine.HistoryService;import org.activiti.engine.IdentityService;import org.activiti.engine.ManagementService;import org.activiti.engine.RepositoryService;import org.activiti.engine.RuntimeService;import org.activiti.engine.TaskService;import com.opensymphony.xwork2.ActionSupport;import com.opensymphony.xwork2.ModelDriven;public abstract class BaseAction<T> extends ActionSupport implements ModelDriven<T> {//数据引擎服务组件注入@Resourcepublic RepositoryService repositoryService;@Resourcepublic RuntimeService runtimeService;@Resourcepublic TaskService taskService;@Resourcepublic HistoryService historyService;@Resourcepublic IdentityService identityService;@Resourcepublic ManagementService managementService;// =============== ModelDriven的支持 ==================protected T model;public BaseAction() {try {// 通过反射获取model的真实类型ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();Class<T> clazz = (Class<T>) pt.getActualTypeArguments()[0];// 通过反射创建model的实例model = clazz.newInstance();} catch (Exception e) {throw new RuntimeException(e);}}public T getModel() {return model;}}</span>
上述就是BaseAction的所有操作,这样每一个具体的Action扩展起来就方便多了。
配置文件
下面来说一下配置文件把!好像整个过程中并没有出现配置文件,小编把所有的配置都通过Spring的配置文件全部管理起来,包括Hibernate配置,依赖注入、事务配置以及工作流组件注入等
<span style="font-family:Comic Sans MS;font-size:18px;"><?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd" default-autowire="no"><!--开启Spring注解扫描 --><context:component-scan base-package="com.tgb.interfaceSystem.*" /><!-- 配置数据源 --><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><!--数据库连接信息配置 --><property name="url" value="${jdbc.url}" /><property name="driverClassName" value="${jdbc.driverClassName}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /><!-- 其他配置 --><!--maxActive: 最大连接数量--> <property name="maxActive" value="200"/> <!--minIdle: 最小空闲连接--> <property name="minIdle" value="5"/> <!--maxIdle: 最大空闲连接--> <property name="maxIdle" value="40"/> <!--initialSize: 初始化连接--> <property name="initialSize" value="30"/> <!-- 连接被泄露时是否打印 --> <property name="logAbandoned" value="true"/> <!--removeAbandoned: 是否自动回收超时连接--> <property name="removeAbandoned" value="false"/> <!--removeAbandonedTimeout: 超时时间(以秒数为单位)--> <property name="removeAbandonedTimeout" value="30"/> <!--maxWait: 超时等待时间以毫秒为单位 1000等于60秒--> <property name="maxWait" value="1000000"/> <!-- 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位. --> <property name="timeBetweenEvictionRunsMillis" value="10000"/> <!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 --> <property name="numTestsPerEvictionRun" value="10"/> <!-- 1000 * 60 * 30 连接在池中保持空闲而不被空闲连接回收器线程--> <property name="minEvictableIdleTimeMillis" value="10000"/> </bean><!-- 配置外部数据库连接信息 --><context:property-placeholder location="classpath:db.properties" /><bean id="sessionFactory"class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"><!-- 1.配置datasource --><property name="dataSource" ref="dataSource"></property><!-- 2.配置Hibernate属性 --><property name="hibernateProperties"><props><prop key="hibernate.hbm2ddl.auto">update</prop><prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop><prop key="hibernate.show_sql">true</prop><prop key="hibernate.format_sql">false</prop><!--事务隔离级别 --><prop key="hibernate.connection.isolation">2</prop><!--启用本地线程 --><prop key="hibernate.current_session_context_class">thread</prop><prop key="hibernate.jdbc.batch_size">100</prop></props></property><!-- 配置映射文件 已经不采用配置文件的形式了 --><!-- <property name="mappingLocations"> <list> <value>classpath:cn/itcast/ssh/domain/*.hbm.xml</value> </list> </property> --><!--3.指定进行了Hibernate注解开发的包,方便框架进行扫描设置 --> <property name="packagesToScan"><list><value>com.tgb.interfaceSystem.entity</value></list></property> </bean><!-- 创建SessionFactory,这是spring整合hibernate的核心 --><!--用LocalSessionFactoryBean的形式的话,需要采用配置文件的形式进行注入实体,本次不采,而采用AnnotationSessionFactoryBean形式,此类继承与LocalSessionFactoryBean --><!-- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 1.配置datasource <property name="dataSource" ref="dataSource"></property> 2.配置Hibernate属性 <property name="hibernateProperties"> <value> hibernate.hbm2ddl.auto=update hibernate.show_sql=true hibernate.dialect=org.hibernate.dialect.MySQL5Dialect </value> </property> 3.配置映射文件 <property name="mappingLocations"> <list> <value>classpath:cn/itcast/ssh/domain/*.hbm.xml</value> </list> </property> </bean> --><!-- 配置事务 --><!-- 1.配置事务管理器 --><bean id="transManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory"></property></bean><!--采用注解形式进行事务的管理操作 --><!-- <tx:annotation-driven transaction-manager="transManager"/> --><!-- 2.配置事务通知,定义事务管理通知,采用注解形式进行事务管理 --><!--tx:advice:定义事务管理的通知(环绕通知) transaction-manager:声明事务管理的实现类 tx:method:定义参与事务管理的方法 --> <tx:advice id="txAdvice" transaction-manager="transManager"><tx:attributes><!-- 定义事务需要管理的方法name name=“get*” 定义参与事务管理的方法,支持通配符 timeout timeout=-1 定义事务超时时间,-1为永不超时 read-only read-only=“false” 定义事务种类为只读事务或读写事务 no-rollback-for 异常名称 定义不参与事务回滚的异常名 rollback-for 异常名称 定义参与事务回滚的异常名 isolation Isolation 定义事务隔离级 propagation propagation 定义事务的传播属性 --><tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED"read-only="false" /><tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED"read-only="false" /><tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED"read-only="false" /><tx:method name="*" read-only="true" /></tx:attributes></tx:advice> <!-- 3.配置切面,定义AOP --><aop:config><!-- 定义切入点,切入点为业务逻辑层的所有接口中的方法 --><aop:pointcut expression="execution(* com.tgb.interfaceSystem.service..*.*(..))"id="aopPointcut" /><!-- 定义一个切面,为其声明对应的通知和切入点 --><aop:advisor advice-ref="txAdvice" pointcut-ref="aopPointcut" /></aop:config> <!-- Activiti的相关配置信息 --><!-- 流程引擎的配置bean --><bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"><property name="dataSource" ref="dataSource" /><property name="databaseSchemaUpdate" value="true" /><property name="transactionManager" ref="transManager" /><!--注入所需要的工作流的相关流程文件 --><property name="deploymentResources"><list><!-- <value>bpmn/event.bpmn</value> --><value>classpath:/bpmn/*</value></list></property></bean><!-- 流程引擎的bean --><bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"><property name="processEngineConfiguration" ref="processEngineConfiguration" /></bean><!-- 服务组件的bean --><bean id="repositoryService" factory-bean="processEngine"factory-method="getRepositoryService" /><bean id="runtimeService" factory-bean="processEngine"factory-method="getRuntimeService" /><bean id="taskService" factory-bean="processEngine"factory-method="getTaskService" /><bean id="historyService" factory-bean="processEngine"factory-method="getHistoryService" /><bean id="identityService" factory-bean="processEngine"factory-method="getIdentityService" /> <bean id="managementService" factory-bean="processEngine"factory-method="getManagementService" /> </beans> </span>
Dao方法
下面来看一下Dao层方法吧!小编精心封装了好久,主要是HiberanteDao层的方法。
<span style="font-family:Comic Sans MS;font-size:18px;">package com.tgb.interfaceSystem.Base;import java.io.Serializable;import java.lang.reflect.ParameterizedType;import java.sql.Connection;import java.sql.SQLException;import java.util.List;import java.util.Map;import java.util.Set;import javax.annotation.Resource;import javax.sql.DataSource;import org.apache.commons.dbutils.QueryRunner;import org.aspectj.org.eclipse.jdt.core.dom.ThisExpression;import org.hibernate.HibernateException;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.jdbc.Work;import org.hibernate.metadata.ClassMetadata;import org.hibernate.type.Type;import org.springframework.orm.hibernate3.HibernateCallback;import org.springframework.orm.hibernate3.SessionFactoryUtils;import org.springframework.orm.hibernate3.support.HibernateDaoSupport;import com.tgb.interfaceSystem.action.bean.QueryResult;import com.tgb.interfaceSystem.util.TUtils;/** * @ClassName: BaseDaoImpl * @Description: 公共底层方法的实现类 * @author: LUCKY * @date:2015年9月26日 下午1:25:29 * @param <T> */public abstract class BaseHibernateDaoImpl<T> extends HibernateDaoSupportimplements BaseDao<T> {protected QueryRunner runner;public DataSource dataSource;public Connection connection;@Resourcepublic void setSessionFacotry(SessionFactory sessionFacotry) throws Exception {dataSource=getDataSource(sessionFacotry);connection = dataSource.getConnection();runner=new QueryRunner(dataSource); super.setSessionFactory(sessionFacotry);}// 获得JDBC的数据库连接操作//public Connection connection; private Class<T> clazz;// 用来获得Connection的连接操作public abstract DataSource getDataSource(SessionFactory sessionFactory) throws Exception;// 构造函数,用来实例化泛型Tpublic BaseHibernateDaoImpl(){this.clazz = TUtils.getGenericSuperclass(this.getClass());// 通过构造函数调用子类的方法,来为connection进行赋值的操作//try {////////getHibernateTemplate().getSessionFactory().openSession().doWork(new Work() {//////// ////public void execute(Connection connection) throws SQLException {//////// this.connection=connection;////}////});// ////////dataSource=getDataSource();////connection=dataSource.getConnection("root", "123456");////} catch (Exception e1) {////System.out.println(e1.getMessage());//e1.printStackTrace();//}finally{////}}// -------------------------------------------添加方法--------------------------------------------------------------------------------/* * 根据集合来添加或者更新方法,如果实体处于persient状态的话,则是更新操作 如果是transient状态的话,测试添加操作 * * @param list 要添加的实体集合 */public void saveOrUpdateAll(List list) {getHibernateTemplate().saveOrUpdateAll(list);}/* * 保存实体方法 * * @param t 要保存的实体 * * @return 保存后的实体 */public T saveEntity(T t) {getHibernateTemplate().save(t);return t;}/* * 批量添加对象实体,如果实体库中没有的话,调用的是添加方法 库中有的话,会自动调用更新方法 * * @param t 要添加的实体对象 */public void saveOrUpdateObject(T t) {getHibernateTemplate().saveOrUpdate(t);}// -------------------------------------------更新方法--------------------------------------------------------------------------------/* * 更新实体方法 * * @param t 要更新的实体 */public void update(T t) {getHibernateTemplate().update(t);}public void merge(T t) {getHibernateTemplate().merge(t);}// -------------------------------------------删除方法--------------------------------------------------------------------------------/* * 删除实体方法 * * @param t 要删除的实体 */public void delete(T t) {getHibernateTemplate().delete(t);}/* * 根据实体id进行删除实体 * * @param id 实体id */public void deleteById(Serializable id) {T objecT = this.get(getEntityClass(), id);if (objecT != null) {delete(objecT);}}// -------------------------------------------查询方法--------------------------------------------------------------------------------/* * 根据实体类型和实体ID来查询实体操作 * * @param entityClass 实体的class类型 * * @param id 实体的id * * @return 要查询的实体 */public T get(Class<T> entityClass, Serializable id) {return getHibernateTemplate().get(entityClass, id);}/** * @Title: getEntityClass * @Description: 得到泛型中的实体类型 * @param @return * @return Class<T> * @throws */public Class<T> getEntityClass() {Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];return entityClass;}/* * @param clazz 实体的class类型 * * @return 查询某个实体类的库中的所有信息 */public List<T> getObjects(Class clazz) {return getHibernateTemplate().loadAll(clazz);}/** * @Author: Charles * @Description: 获取表主键类型 * @param clazz * @return Type: */public Type getPkType() {ClassMetadata meta = getHibernateTemplate().getSessionFactory().getClassMetadata(getEntityClass());return meta.getIdentifierType();}/** * 获取主键名 */public String getPkColunmName() {ClassMetadata meta = getHibernateTemplate().getSessionFactory().getClassMetadata(getEntityClass());return meta.getIdentifierPropertyName();}/** * 获取实体类型名 * */public String getEntityClassName() {ClassMetadata meta = getHibernateTemplate().getSessionFactory().getClassMetadata(getEntityClass());return meta.getEntityName();}/* * @param obj 对象实体 * * @return 根据对象获取某个类的所有对象 */public List getObjectsByExample(T obj) {return getHibernateTemplate().findByExample(obj);}// 分页查询开始/** * hql分页查询 * * @param hql * 查询字符串 * @param queryResult * 查询结果 * @param values * 查询值 * @return */@SuppressWarnings("unchecked")public QueryResult hqlQueryPage(final String hql,final QueryResult queryResult, final Map values) {return getHibernateTemplate().execute(new HibernateCallback() {@Overridepublic QueryResult doInHibernate(Session session)throws HibernateException, SQLException {Query query = session.createQuery(hql).setFirstResult((queryResult.getCurrentPage().intValue() - 1)* queryResult.getPageSize().intValue()).setMaxResults(queryResult.getPageSize().intValue());Set keys = values.keySet();for (Object o : keys) {query.setParameter((String) o, values.get(o));}queryResult.setResultList(query.list());String countHql = "select count(*) " + hql; // 封装查询总记录条数Long allCount = getAllCount(countHql, values); // 总记录条数queryResult.setAllCount(allCount);queryResult.calcuatePage(); // 计算总页数return queryResult;}});}/** * hql查询得到总查询数目 * * @param hql * 查询字符串 * @param values * 查询值 * @return */@SuppressWarnings("unchecked")public Long getAllCount(final String hql, final Map values) {return getHibernateTemplate().execute(new HibernateCallback() {@Overridepublic Object doInHibernate(Session session)throws HibernateException, SQLException {Query query = session.createQuery(hql);Set keys = values.keySet();for (Object o : keys) {query.setParameter((String) o, values.get(o));}return query.uniqueResult();}});}/* * 根据Hql语句,进行查询相应的实体 * * @param hql hql语句 * * @param param hql语句中的参数 * * @return */public List findHql(final String hql, final Map<String, Object> param) {return getHibernateTemplate().execute(new HibernateCallback<List>() {@Overridepublic List<T> doInHibernate(Session session)throws HibernateException {Query query = session.createQuery(hql);if (param != null && param.size() > 0) {for (String property : param.keySet()) {query.setParameter(property, param.get(property));}}return query.list();}});}}</span>
不知各位注意过上面的一个批量添加的方法没有,如下
public void saveOrUpdateAll(List list) {
getHibernateTemplate().saveOrUpdateAll(list);
}
小编测试过该方法,在数据1W条的情况下,用户15秒,确实挺快的。以后可以用此方法做批量操作。
总结
这也算是小编第一次框架的搭建,在其中学习到了很多知识,对于技术的学习,尤其是不能懒惰,多多练习即可。
- SSH+Activiti+Dbutil框架搭建旅程(附源码)
- 手把手搭建SSH+Activiti(附加源码)
- android 框架搭建附源码
- Eclipse上搭建SSH(struts-2.2.3 + spring-2.5.6 + hibernate-3.6.8)框架-附源码
- Eclipse上搭建SSH(struts-2.2.3 + spring-2.5.6 + hibernate-3.6.8)框架-附源码
- Eclipse上搭建SSH(struts-2.2.3 + spring-2.5.6 + hibernate-3.6.8)框架-附源码
- (三)activiti框架搭建
- ssh框架总结(框架分析+环境搭建+实例源码)
- Activiti源码分析(框架、核心类。。。)
- SSH搭建的框架,提供源码
- dbutil框架
- DButil框架
- Activiti学习文档(一)之整合SSH框架开发
- JAVA小白启蒙篇:第一个SSM框架搭建示例(附源码下载)
- SSM框架---搭建示例(业务原理并附源码下载)
- spring+SpringMVC+Mybtis+maven+SSM框架搭建附源码
- SSH框架总结(框架分析+环境搭建+实例源码下载)
- 【转】SSH框架总结(框架分析+环境搭建+实例源码下载)
- Connecting C++ and XAML
- 关系查询语言
- 插入排序与冒泡排序
- Mysql之Mysqldump
- 模块、包
- SSH+Activiti+Dbutil框架搭建旅程(附源码)
- [Leetcode] Add Digits
- 从道德经中学习java
- 移动前端开发之viewport的深入理解
- Mac OS X挂载ntfs文件系统
- 如何搭建一个独立博客——简明Github Pages与Hexo教程
- CocoaPods安装和使用教程
- File类
- Mysql检查表进行repair、optimize