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秒,确实挺快的。以后可以用此方法做批量操作。



 总结

 这也算是小编第一次框架的搭建,在其中学习到了很多知识,对于技术的学习,尤其是不能懒惰,多多练习即可。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机重力传感器坏了怎么办 锤子手机重力传感器坏了怎么办 平板电脑没有开关键怎么办 手机重力感应器坏了怎么办 苹果手机重力感应器坏了怎么办 苹果手机陀螺仪坏了怎么办 狗狗的爪子肿了怎么办 压缩文件之后显示拒绝访问怎么办 压缩文件解压后全散开了怎么办 dnf助手改名字用完了怎么办 缅甸 佤邦 办中国护照 怎么办? 电脑玩游戏网络延迟大怎么办 qq好友空间锁了怎么办 卡盟进货额不足怎么办 被朋友骗了钱怎么办 联通在学校网差怎么办 前夫把我微信拉黑 孩子的事怎么办 微信好友验证疑似被盗怎么办 我的世界被banip怎么办 dnf深渊宝珠出了怎么办 吞噬魔4个球吃了怎么办 dnf没有支援兵了怎么办 家里没通天然气怎么办 苹果6p16g不够用怎么办 魅蓝手机内存不够用怎么办 3dmax灯光全黑怎么办 高压15o低压1oo怎么办 源码一位乘法中c怎么办 怀孕搬了重东西怎么办 深蹲力量不涨怎么办 ps4连接显示器分辨率低怎么办 大疆失去链接后怎么办 脑袋被锤了几拳怎么办 华为手机变板砖怎么办 电脑网页打开很慢怎么办 网页加载速度太慢.怎么办 cad字显示不出来怎么办 dell笔记本打不开机怎么办 手机系统界面已停止运行怎么办 大石退出菊丸怎么办 word空白页面突然变大了怎么办