最近在做一个CRM的项目,用的是SSH,所以想在这里和你们分享一下项目中的运用
先说说框架整合.最初的架构是最简单的Struts2+Spring5+Hibernate5,
数据库使用的是MySQL,现在贴出所有需要的
Pom jar包
-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zking.maven</groupId> <artifactId>ssh</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.10.RELEASE</spring.version> <hibernate.version>5.2.5.Final</hibernate.version> <struts2.version>2.5.16</struts2.version> <mysql.version>5.1.40</mysql.version> <servlet.version>4.0.0</servlet.version> <c3p0.version>0.9.5.2</c3p0.version> <jsp-api.version>2.0</jsp-api.version> <log4j.version>1.2.17</log4j.version> <aspectj.version>1.8.10</aspectj.version> <fastjson.version>1.2.47</fastjson.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>${jsp-api.version}</version> <scope>provided</scope> <exclusions></exclusions> </dependency> <!-- Spring核心依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring Web依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring整合ORM框架依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <!-- struts2 核心依赖 --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>${struts2.version}</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-json-plugin</artifactId> <version>${struts2.version}</version> </dependency> <!-- Struts2 和 Spring 整合依赖 --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-spring-plugin</artifactId> <version>${struts2.version}</version> </dependency> <!-- Hibernate 核心以来 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> <exclusions> <exclusion> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> </exclusion> </exclusions> </dependency> <!-- junit 依赖 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- C3P0 依赖 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>${c3p0.version}</version> </dependency> <!-- MySQL 依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- AspectJ 依赖 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <!-- 二级缓存ehcache --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.4</version> </dependency> <!-- 整合 hibernate-ehcache --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.4</version> </dependency> <!--JDK9移除的Jar包--> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.1.2</version> </dependency> <!-- log4j2 依赖,如要使用encache 则需要配置slf4j --> <!-- jstl依赖 ssh项目可以用struts标签代替 --> <!-- <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> --> <!-- jsp自定义标签依赖(必须与tomcat的版本一致) tomcat-jsp-api --> <!-- <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jsp-api</artifactId> <version>7.0.79</version> </dependency> --> </dependencies> <build> <finalName>ssh</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project>
好了 准备工作做完了
开始建立对应的Xml 文件了
各部分的配置及文件分别是
struts.xml;
Hibernate.cfg.xml,jdbc.properties
applicationContext.xml;
首页 我们要对spring 与 hibernate 进行整合 我们知道 spring 在SSH中 类似于黏合剂 它上接 hibernate 下接 struts2,对
hibernate首先整合 主要是方便做测试 以及调试 工作
hibernate.cfg.xml 的配置如下
-
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 数据库隔离级别 --> <property name="connection.isolation">2</property> <!--方言,sql信息等 --> <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <property name="show_sql">true</property> <property name="format_sql">true</property> <!--<property name="hbm2ddl.auto">none</property>--> <!-- 配置二级缓存 --> <property name="cache.use_second_level_cache">true</property> <!-- 配置二级缓存使用的产品 --> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <!--设置hibernate.use_identifier_rollback为true,delete时会将对象置空 --> <property name="hibernate.use_identifier_rollback">true</property> <!-- <property name="hibernate.c3p0.max_size">10</property> <property name="hibernate.c3p0.min_size">5</property> <property name="c3p0.acquire_increment">2</property> <property name="c3p0.idle_test_period">2000</property> <property name="c3p0.timeout">2000</property> <property name="c3p0.max_statements">10</property> --> <!--设定 jdbc的Statement 读取数据的时候每次从数据库中去除的记录条数 --> <property name="hibernate.jdbc.fetch_size">100</property> <!--设定对数据库进行批量删除,批量更新插入的时候的批次大小,此两项设置对mysql无效。 --> <property name="jdbc.batch_size">30</property> <property name="connection.url">jdbc:mysql://localhost:3306/mytest</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <mapping class="com.zking.module.custormer.entity.OrdersEntity"/> <!----> </session-factory> </hibernate-configuration>
注意 在自己我们没有对hibernate 与MYSQL 进行完全的配置 ,以为还有数据库的密码与用户信息等,我们没有在这里进行配置,主要原因是
1.我们会为其配置一个数据源 文件 jdbc.properties 将对应属性 设置在这里面 方便 以后进行更改
2.其次是以为,spring5需要为其配置一个C3p0 数据源 所以 干脆 我们就这样做 会方便的多
你也可以 在hebernate 中 进行测试 后 再建立数据源
jdbc.properties
-
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/mytest jdbc.driverClass=com.mysql.jdbc.Driver jdbc.user=root jdbc.password=12345 jdbc.initialPoolSize=5 jdbc.maxPoolSize=10
-
OrdersEntity的映射文件 如下
-
package com.zking.module.custormer.entity; import javax.persistence.*; import java.sql.Timestamp; @Entity @Table(name = "orders", schema = "mytest", catalog = "") public class OrdersEntity { private int odrId; private String odrCustomer; private Timestamp odrDate; private String odrAddr; private String odrStatus; @Id @Column(name = "odr_id") public int getOdrId() { return odrId; } public void setOdrId(int odrId) { this.odrId = odrId; } @Basic @Column(name = "odr_customer") public String getOdrCustomer() { return odrCustomer; } public void setOdrCustomer(String odrCustomer) { this.odrCustomer = odrCustomer; } @Basic @Column(name = "odr_date") public Timestamp getOdrDate() { return odrDate; } public void setOdrDate(Timestamp odrDate) { this.odrDate = odrDate; } @Basic @Column(name = "odr_addr") public String getOdrAddr() { return odrAddr; } public void setOdrAddr(String odrAddr) { this.odrAddr = odrAddr; } @Basic @Column(name = "odr_status") public String getOdrStatus() { return odrStatus; } public void setOdrStatus(String odrStatus) { this.odrStatus = odrStatus; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; OrdersEntity that = (OrdersEntity) o; if (odrId != that.odrId) return false; if (odrCustomer != null ? !odrCustomer.equals(that.odrCustomer) : that.odrCustomer != null) return false; if (odrDate != null ? !odrDate.equals(that.odrDate) : that.odrDate != null) return false; if (odrAddr != null ? !odrAddr.equals(that.odrAddr) : that.odrAddr != null) return false; if (odrStatus != null ? !odrStatus.equals(that.odrStatus) : that.odrStatus != null) return false; return true; } @Override public int hashCode() { int result = odrId; result = 31 * result + (odrCustomer != null ? odrCustomer.hashCode() : 0); result = 31 * result + (odrDate != null ? odrDate.hashCode() : 0); result = 31 * result + (odrAddr != null ? odrAddr.hashCode() : 0); result = 31 * result + (odrStatus != null ? odrStatus.hashCode() : 0); return result; } @Override public String toString() { return "OrdersEntity{" + "odrId=" + odrId + ", odrCustomer='" + odrCustomer + '\'' + ", odrDate=" + odrDate + ", odrAddr='" + odrAddr + '\'' + ", odrStatus='" + odrStatus + '\'' + '}'; } }
好了 hibernate 准备工作基本 完成
开始集成了
在spring的配置文件中配置 如下
<?xml version="1.0" encoding="UTF-8"?>
-
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
-
<!-- 上面需要 引入aop tx context 这样他的标签才可以引用 他们分别是切面 与 事物-->
<!-- 自动扫描 ,注解式要一定需要--> <context:component-scan base-package="com.zking"></context:component-scan> <!-- 导入资源文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 配置C3P0 数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="initialPoolSize" value="${jdbc.initialPoolSize}"></property> <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property> </bean> <!-- 配置SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> <!-- <property name="mappingLocations" value="classpath:com/arisu/entites/*.hbm.xml"></property> --> </bean> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 启用事务注解 --> <!-- <tx:annotation-driven transaction-manager="transactionManager"/> --> <!-- 配置事务属性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 根据方法名指定事务属性 --> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 配置事务切点 --> <aop:config> <aop:pointcut expression="execution(* *..service.impl.*.*(..))" id="txPointCut"/> <!-- 切入点 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> <!-- 关联起来 --> </aop:config>
这里 我本来是采用注解式 开发的 这样 我们就不需要配置事物这些东西了
但是 注解式 开发 后期维护 起来 很麻烦
好处在于 我们的 依赖的注入 完全可以直接用 注解的方式
所以 我们2种 都用吧
各个优点我们都有了 这样的话 事物 我们就用 AOP 其他 不用管
spring会帮你处理
好了 到这一步时 我们得做测试了
来个Test 测试类
-
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-beans.xml");
-
SessionFactory dataSource = (SessionFactory) ctx.getBean("sessionFactory");
-
Session session = dataSource.getCurrentSession();
-
System.out.println(session);
这里主要测试 session 是否已经取到 我们操作 hibernate 就要用到 session 所以 它 必须 要取到的
SessionFactory 是从 spring applicationContext-beans.xml 取到的
这里从 SessionFactory 取session 有2种方式
getCurrentSession() 与 openSession() 主要在于 他们 处理事物的区别
getCurrentSession()可以帮你自动开启事物 而 后面那个就不可以了
进行到这里 spring 与 hibernate 配置工作就完成了
开始 进行 struts2 与 spring的整合了
接下来在web.xml中指定spring的配置文件.
web.xml内容如下:
-
<?xml version="1.0" encoding="UTF-8"?>
-
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-*.xml</param-value> </context-param> <context-param> <param-name>pattern</param-name> <param-value>yyyy-MM-dd hh:mm:ss</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
配置 struts2 的核心处理器 已经 hibernate 的监听
现在Hibernate已经纳入Spring的管理了.看看下面的业务代码,Service层的bean也已经被Spring管理了.
OrdersServiceImpl.java如下
-
package com.zking.module.custormer.service.impl; import com.zking.module.custormer.dao.OrdersDao; import com.zking.module.custormer.entity.OrdersEntity; import com.zking.module.custormer.service.OrdersService; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; @Service("ordersService") public class OrdersServiceImpl implements OrdersService { @Resource private OrdersDao ordersDao; @Override public List getAll() { return ordersDao.getAll(); } }
@Service: 该注解添加到业务层,表示这个类由spring管理.
@Resource是 取到 spring 的 依赖 它在dao层 我们已经注入了
OrdersAction.java如下
-
package com.zking.module.custormer.action; import com.alibaba.fastjson.JSONObject; import com.zking.base.action.BaseAction; import com.zking.module.custormer.entity.CstLinkmanEntity; import com.zking.module.custormer.entity.OrdersEntity; import com.zking.module.custormer.service.OrdersService; import com.zking.module.custormer.util.ResponseUtil; import org.apache.struts2.ServletActionContext; import org.springframework.stereotype.Controller; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; @Controller public class Orders extends BaseAction<OrdersEntity> { @Resource private OrdersService ordersService; // 查询 public void list() throws Exception { HttpServletRequest req = ServletActionContext.getRequest(); List<OrdersEntity> list = ordersService.getAll(); System.out.println(list.size()); JSONObject result = new JSONObject(); result.put("total", list.size()); result.put("rows", list); System.out.println(result.toJSONString()); HttpServletResponse response = ServletActionContext.getResponse(); try { ResponseUtil.write(response,result); } catch (Exception e) { e.printStackTrace(); } // return SUCCESS; } }
注意 我们在自己继承了 一个自己写的类BaseAction 他的作用是提高开发效率
为什么呢?
BaseAction.java 如下
package com.zking.base.action;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.util.ServletContextAware;
import org.dom4j.rule.Mode;
import org.springframework.stereotype.Controller;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
@Controller
public class BaseAction<T> extends ActionSupport implements ModelDriven<T>,ServletRequestAware,ServletResponseAware,ServletContextAware{
public static final String SUCCESS="success";
public static final String FAILED="failed";
public static final String LIST="list";
public static final String EDIT="edit";
public static final String DETAIL="detail";
protected Object result;
protected String message;
public Object getResult() {
return result;
}
public String getMessage() {
return message;
}
protected T model;
@Override
public T getModel() {
ParameterizedType type = (ParameterizedType)this.getClass().getGenericSuperclass();
System.out.println(type);
Class clazz = (Class)type.getActualTypeArguments()[0];
System.out.println(clazz);
try {
if(model==null) {
model = (T)clazz.newInstance();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return model;
}
protected ServletContext application;
@Override
public void setServletContext(ServletContext context) {
this.application = context;
}
protected HttpServletResponse response;
@Override
public void setServletResponse(HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
response.setHeader("content-type", "text/html;charset=UTF-8");
this.response = response;
}
protected HttpServletRequest request;
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
}
我们可以在所以Action 都继承他 他里面包含了
ActionSupport , ModelDriven<T>,ServletRequestAware,ServletResponseAware,ServletContextA
还定义了常量,重要的是getModel()这个方法 ,因为实现了
ModelDriven 所以 我们 需要 实例我们的 实体类 前台 传参就不是 类名.属性名了 直接是属性名 就 可以了
而getModel()就可以获取到 在这里我们将它设置为泛型 所以 在Action 里面 继承就可以直接插入他的类型
此外 还 包括 request , response 等 获取 ,这样必要的 东西在Action 里面 都包有 ,效率就提高了
好了 该配置 struts.xml 了 内容如下:
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
- "http://struts.apache.org/dtds/struts-2.5.dtd">
- <struts>
- <!-- 配置为开发模式 -->
- <constant name="struts.devMode" value="false" />
- <!-- 把扩展名配置为action -->
- <constant name="struts.action.extension" value="action" />
- <!-- 把主题配置为simple -->
- <constant name="struts.ui.theme" value="simple" />
- <package name="default" namespace="/" extends="struts-default">
- <!--当struts2与spring整合后,class属性可以写bean的名称,在Action 里面 我们已经注入了Orders ,
- 所以 Class 里面 小写的 orders就完成 配置了-->
- <!--这个是struts2 的 新特性 大概是 安全性的原因 吧 如果 要用通配符 就 必须加上这个 这个 是在 2.3以后
- 版本 要加入这个-->
-
<global-allowed-methods>regex:.*</global-allowed-methods>
- <action name="Orders_*" class="orders" method="{1}">
- <result name="list" >/WEB-INF/jsp/roleAction/list.jsp</result>
- <result name="toList" type="redirectAction">role_list</result>
- <result name="saveUI">/WEB-INF/jsp/roleAction/saveUI.jsp</result>
- </action>
- </package>
- </struts>
到这里就完全完成了 在这里做个测试 看 JSP跳 Action 是否成功 如果不成功检查配置 是否有问题
其实 SSH的整合 还是算 比较容易的 主要是要根据步骤去做 好处当然是在于方便调试 啊 不要 一气呵成
的就配置完 不然 哪里报错 都不知道 还有 在企业中 注解式 开发 还是有比较多的人使用 以为他相对于配置版
开发效率 大大提高 并且 比较容易 所以 还不会注解版的同学 都 了解 一下 其实 用的 标签 也就 几个 在不同
层 的 注解而已 ,此外 我们应用了BaseAction 其实 开发中 你也 可以往dao层 继续 加入BaseDao 因为dao层
与数据库打交道 所以增删改查是必须的 里面 泛型的使用 之后,Dao其他的类 继承后 就不需要写增删改查了
就会提高很过的效率