SSH框架整合(XML方式)
一、搭建环境
新建web工程,准备搭建环境
1. Struts2环境搭建
1.1 导包
1. 导入Struts2的必需jar包(通过模板的jar包导入)
其中log4j的两个jar包不导,因为我们使用的是log4j.properties的配置文件,在Spring导入时使用log4j 1.x的版本.
2. 导入Sturts2与Spring的整合包struts2-spring-plugin-2.3.32.jar
3.导入Struts2的jar包如下,共12个包.(Spring处导入log4j的日志包)
1.2 Sturts2的配置文件
1. 修改web.xml配置Struts2的前端控制器
<!-- Struts2前端控制器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2. 配置Sturts2的核心配置文件struts2.xml到src(从模板中复制,删除到最简单的配置)
如果要添加配置提示,根据DTD文件添加到Xml Catalog中
1. 关闭开发者模式(常量设置从/org/apache/struts2/default.properties中查找)
缺点:开发者模式不能处理ajax的异常
但我们需要自动加载配置文件的功能,因此要开启自动加载配置文件的开关
2. 修改Sturts2的前端样式为simple
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- 关闭开发者模式 -->
<!-- <constant name="struts.devMode" value="true" /> -->
<constant name="struts.configuration.xml.reload" value="true" />
<!-- 使用简单样式 -->
<constant name="struts.ui.theme" value="simple" />
<!-- 自定义包,配置Action -->
<package name="default" namespace="/" extends="struts-default">
</package>
</struts>
3. 拷贝log4j.properties日志配置文件到src目录
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:\\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=info, stdout,file
4. Sturts2环境搭建完成
2. Spring4环境搭建
2.1 导包
1. Spring必需包(4+2) :
beans,context,core,expression.+ 两个日志jar包:apache-commen logging 1.x.jar与log4j.jar
2. Spring在web中使用的jar包: spring-web-4.2.4.RELEASE.jar
3. Spring操作数据库相关jar包:
spring-jdbc-4.2.4.RELEASE.jar spring-tx-4.2.4.RELEASE.jar(事务包,与jdbc包耦合)
4. 事务管理的jar包:(依赖AOP)
tx jdbc
aop的4个jar包 : aop联盟,Aspectj,Spring整合它们的两个jar包
5. Spring整合ORM框架的jar包
spring-orm-4.2.4.RELEASE.jar
6. Spring测试包:
spring-test-4.2.4.RELEASE.jar
这里共15个jar包.
与Struts2的jar包总共27个jar包。
2.2 Spring的核心监听器
以前获取ApplicationContext(Spring
容器)都是直接获取,每次都要根据配置文件重新创建一个Spring
容器.
在创建Spring
容器同时,需要对容器中对象初始化。而每次初始化容器的时候,都创建了新的容器对象,消耗了资源,降低了性能。
解决思路 : 保证Spring容器只有一个
解决方案:将Spring容器绑定到Web Servlet容器上,让Web容器来管理Spring容器的创建和销毁。
编写一个ServletContextListener监听器,在监听ServletContext到创建的时候,创建Spring容器,
并将其放到ServletContext的属性中保存(setAttribute(Spring容器名字,Spring容器对象) )。
我们无需手动创建该监听器,因为Spring提供了一个叫ContextLoaderListener的监听器,它位于spring-web.jar中。
在web.xml
中配置Spring
的核心监听器,将Spring
容器的创建绑定到ServletContext
上
Spring的核心监听器必须写在Struts2的前端控制前,才能对ServletContext的创建起到监听作用。
<!-- Spring的核心监听器 -->
<listener>
<!-- Spring提供的ContextLoaderListener监听器 -->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 全局参数 -->
<context-param>
<!-- 默认加载的配置文件在web-inf里的applicationContext.xml,因此需要修改 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
2.3 Spring的核心配置文件applicationContext.xml
复制核心配置文件到src目录下:
头约束包括:beans,context,tx,aop
-----------------------------------------------------------------------------
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
2.4 日志配置文件(Struts2搭建已经完成)
3 Hibernate5环境搭建
3.1 导包
1. 导入Hibernate5必需required文件夹中的jar包(9-1)
其中,javasist的版本与Struts2中的javasist版本冲突了,留下高版本的jar包。
2. 导入数据库驱动 1
mysql-connector-java-5.1.18-bin.jar
3. 导入连接池(数据源)C3P0的jar包 1
这里不用Hibernate提供的c3p0的jar包,Hibernate提供的3个c3p0的jar包全整合只需要一个.
我这里就从Spring提供的c3p0拷贝一个jar包过来。
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
Hibernate导入jar包10个。
3.2 Hibernate核心配置文件hibernate.cfg.xml
拷贝Hibernate的核心配置文件到src目录下
<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入Hibernate核心配置的DTD约束 -->
<!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>
<!--1. 基本配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_day02</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--2. 与本地线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>
<!--3. Hibernate的属性 -->
<!--Hibernate的方言配置,实现了跨数据库 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 显示sql语句 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!-- Hibernate表格的创建方式 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!--
设置隔离级别:
hibernate.connection.isolation = 4
1-Read uncommitted isolation
2-Read committed isolation
4-Repeatable read isolation
8-Serializable isolation
-->
<property name="hibernate.connection.isolation">4</property>
<!-- C3P0的供应商 -->
<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<!-- 最小连接 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 最大连接数 -->
<property name="hibernate.c3p0.max_size">20</property>
<!-- 连接超时时长 -->
<property name="hibernate.c3p0.timeout">120</property>
<!-- 每120秒检查空闲连接 -->
<property name="hibernate.c3p0.idle_test_period">120</property>
<!-- 最大statments数量 -->
<property name="hibernate.c3p0.max_statements">120</property>
<!-- 连接用完后,每次增加的连接数 -->
<property name="hibernate.c3p0.acquire_increment">2</property>
<!-- 每次都验证连接是否可用 -->
<property name="hibernate.c3p0.validate">false</property>
<!--4. 加载映射文件 -->
<mapping resource="com/itdream/domain/Customer.hbm.xml" />
</session-factory>
</hibernate-configuration>
到这里,SSH三个框架的环境基本就搭建完成了,下面去完成SSH框架的互相整合。
二、 整合Spring与Hibernate5框架
2.1 首先继续完成Hibernate5的环境搭建
根据需求完成Hibernate(ORM)框架的搭建。
例: 持久化类:Product
. 数据库表:product
. 建立持久化类与数据库表的映射Product.hbm.xml
//持久化类Product
public class Product {
private Integer pid;
private String pname;
private Double price;
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Product [pid=" + pid + ", pname=" + pname + ", price=" + price + "]";
}
}
---------------------------------------------------------------------------
根据Product持久化类创建映射关系配置文件Product.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 引入DTD约束 -->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 建立持久化类与表的映射关系 -->
<class name="com.itdream.ssh.domain.Product" table="product">
<!-- 建立持久化类标OID与数据库主键的映射,name与column相同可省略column -->
<id name="pid">
<generator class="native"/>
</id>
<!-- 配置持久化类普通属性与数据库字段的映射 -->
<property name="pname"/>
<property name="price"/>
</class>
</hibernate-mapping>
-----------------------------------------------------------------------------
在Hibernate.cfg.xml中加载该映射文件:
<mapping resource="com/itdream/ssh/domain/Product.hbm.xml" />
2.2 Spring与Hibernate框架的整合
Spring与Hibernate框架的整合有两种方式:完全整合【推荐】,半整合
我们的原则是能交给Spring托管的都给Spring框架管理,因此这里就不详解半整合
思想:将Hibernate中SessionFactory对象,由Spring管理。
通过 spring-orm包 提供 LocalSessionFactoryBean 实现。
Spring与Hibernate的完全整合:
优点:将hibernate参数配置到spring文件,没有hibernate配置文件 !!!SessionFactory由Spring管理.
根据Hibernate.cfg.xml: 需要三个方面的配置 (数据源配置、 常用属性配置、 hbm映射加载 )
1. 因此在applicationContext.xml中先注册c3p0数据源的bean:
从applicationContext中抽取数据源的变量,便于维护:
db.properties:
jdbc.dataSourceClass=com.mchange.v2.c3p0.ComboPooledDataSource
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
<!-- 引入外部配置文件,下面使用${key}取值 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 注册数据源 -->
<bean id="dataSource" class="${jdbc.dataSourceClass}">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
2. 将hibernate.cfg.xml的参数完全配置到applicationContext.xml中,由Spring管理SessionFactory.这样Spring容器创建的时候,会创建注入了数据源的SessionFacotory.
**这里注意导入LocalSessionFactoryBean的时候,不要导错版本的全包名,选择Hibernate5**
<!-- Spring管理SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 1.数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 2.Hibernate属性 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<!-- 3.Hibernate映射文件 -->
<property name="mappingResources">
<list>
<value>com/itdream/ssh/domain/Product.hbm.xml</value>
</list>
</property>
</bean>
修改hiberante.cfg.xml的名称为hibernate.cfg.bak.xml表示已经不用,或直接删除。
这里将hibernate.cfg.xml的参数全都配置到Spring中了,已经完成了完全整合。
测试是否整合成功:启动服务器,观察指定的数据库ssh中是否自动建表product
2.3 使用HibernateTemplate完成数据库操作
上面Spring与Hibernate的完全整合基本完成(还差事务管理的配置,这里根据实际操作待会设置)。
Spring提供了一个HibernateTemplate模板类大大简化了对数据库的操作.
为了简化HibernateTemplate的操作,Spring又提供了HibernateDaoSupport类
在开发时,只需要让DAO层继承HibernateDaoSupport
,Spring容器创建的时候,会创建注入了数据源的SessionFacotory
。在配置文件中,将SessionFactory
注入到DAO中,会调用父类的setter方法,它的setter方法内部会根据这个SessionFactory
生成一个HibernateTemplate
的对象,子类DAO可以直接获取使用。
ProductDAO:
//dao层,继承HibernateDaoSupport简化操作
public class ProductDAO extends HibernateDaoSupport {
// 添加商品
public void save(Product product) {
getHibernateTemplate().save(product);
}
// 删除商品
public void delete(Product product) {
getHibernateTemplate().delete(product);
}
// 修改商品信息(底层根据id修改)
public void update(Product product) {
getHibernateTemplate().update(product);
}
// 查询单个商品
public Product findByID(Integer pid) {
// 方式一:
return getHibernateTemplate().get(Product.class, pid);
// 方式二:(使用时才发送sql语句)
// return getHibernateTemplate().load(Product.class, pid);
}
// 查询所有商品
public List<Product> findAll() {
// 方式一:Spring提供了简单的方式
return getHibernateTemplate().loadAll(Product.class);
// 方式二:使用hql查询
// return getHibernateTemplate().find("from Product");
}
// ------复杂查询-----------
// 查询id大于x的商品(HQL语句查询)
public List<Product> findGreaterthanID(Integer pid) {
return (List<Product>) getHibernateTemplate().find("form Product where pid > ?", pid);
}
// 命名查询(sql语句与java代码解耦,写在Product.hbm.xml中)
// 模糊查询
public List<Product> findByNamedQuery(String name) {
return (List<Product>) getHibernateTemplate().findByNamedQuery("Product.findByNameLike", "%" + name + "%");
}
// 模糊查询(Criteria离线查询)
public List<Product> findByCriteria(DetachedCriteria criteria) {
return (List<Product>) getHibernateTemplate().findByCriteria(criteria);
}
}
---------------------------------------------------------------------------
ProductService:
public class ProductService {
// 注入ProductDAO
private ProductDAO productDAO;
public void setProductDAO(ProductDAO productDAO) {
this.productDAO = productDAO;
}
public void saveProduct(Product product) {
productDAO.save(product);
}
public void deleteProduct(Product product) {
productDAO.delete(product);
}
public void updateProduct(Product product) {
productDAO.update(product);
}
public Product findProductByID(Integer pid) {
return productDAO.findByID(pid);
}
public List<Product> findAllProduct() {
return productDAO.findAll();
}
public List<Product> findProductsGreaterthanID(Integer pid) {
return productDAO.findGreaterthanID(pid);
}
// Criteria离线查询
public List<Product> findProductsByCriteria(DetachedCriteria criteria) {
return productDAO.findByCriteria(criteria);
}
// 命名查询
public List<Product> findByNamedQuery(String name) {
return productDAO.findByNamedQuery(name);
}
}
Product.hbm.xml中配置命名查询的语句:
<!-- 全局hql语句 -->
<query name="Product.findByNameLike">
from Product where pname like ?
</query>
-------------------------------------------------------------------------
在applicationContext.xml中注册ProductDAO和ProductService:
<!-- Spring容器中bean的装配 -->
<!-- 注册ProductDAO -->
<bean id="productDAO" class="com.itdream.ssh.dao.ProductDAO">
<!-- 注入SessionFactory -->
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 注册ProductService -->
<bean id="productService" class="com.itdream.ssh.dao.ProductService">
<!-- 注入ProductDAO -->
<property name="productDAO" ref="productDAO"/>
</bean>
---------------------------------------------------------------------------
为上面ProductService中的所有方法配置事务管理:(基于AOP的Spring写好的增强类)
<!-- Spring事务管理 -->
<!-- 注册对应的事务管理器,注入数据源提供连接,这里是session以管理事务 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<!-- 注入数据源 -->
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 注册事务增强类,注入参数事务管理器,设置事务策略 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" />
<tx:method name="update*" />
<tx:method name="delete*" />
<tx:method name="find*" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut expression="execution(* com.itdream.ssh.dao.ProductService.*(..))" id="txPointcut"/>
<!-- 配置切入点与通知的关联 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
----------------------------------------------------------------------------
测试:
@RunWith(SpringJUnit4ClassRunner.class) // Spring整合Junit
@ContextConfiguration(locations ={"classpath:applicationContext.xml"}) // 指定配置文件
public class SpringTest {
// 注入测试bean:ProductService
@Autowired
@Qualifier("productService") // 根据bean的id注入
private ProductService productService;
@Test
public void saveTest() {
// 在实体类中提供无参与有参构造
Product product = new Product(null, "苹果8", 5999D);
Product product2 = new Product(null, "华为8", 6000D);
Product product3 = new Product(null, "小米6", 999D);
Product product4 = new Product(null, "vivo", 1699D);
Product product5 = new Product(null, "大米1", 100D);
productService.saveProduct(product);
productService.saveProduct(product2);
productService.saveProduct(product3);
productService.saveProduct(product4);
productService.saveProduct(product5);
}
@Test
public void updateTest() {
Product product = new Product(1, "大米3", 300D);
productService.updateProduct(product);
}
@Test
public void deleteTest() {
Product product = new Product();
product.setPid(4);
productService.deleteProduct(product);
}
@Test
public void findByIDTest() {
Product product = productService.findProductByID(2);
System.out.println(product);
}
@Test
public void findAllTest() {
List<Product> allProducts = productService.findAllProduct();
System.out.println(allProducts);
}
@Test
public void findProductsByCriteriaTest() {
DetachedCriteria criteria = DetachedCriteria.forClass(Product.class);
criteria.add(Restrictions.like("pname", "%米%"));
List<Product> productListByCriteria = productService.findProductsByCriteria(criteria);
System.out.println(productListByCriteria);
}
// 命名查询测试
@Test
public void findProductsByNameQueryTest() {
List<Product> listByNameQuery = productService.findByNamedQuery("%米%");
System.out.println(listByNameQuery);
}
}
测试成功
上面就完成了Hibernate与Spring整合的所有步骤:
- 导包
- Hibernate将SessionFactory交由Spring管理
- Spring对Service层的方法进行事务管理
applicationContext.xml的完全配置:(以后可以直接复制修改)
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 引入外部配置文件,下面使用${key}取值 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 注册数据源 -->
<bean id="dataSource" class="${jdbc.dataSourceClass}">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- Spring管理SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 1.数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 2.Hibernate属性 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<!-- 3.Hibernate映射文件 -->
<property name="mappingResources">
<list>
<value>com/itdream/ssh/domain/Product.hbm.xml</value>
</list>
</property>
</bean>
<!-- Spring事务管理 -->
<!-- 注册对应的事务管理器,注入数据源提供连接,这里是session以管理事务 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<!-- 注入数据源 -->
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 注册事务增强类,注入参数事务管理器,设置事务策略 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" />
<tx:method name="update*" />
<tx:method name="delete*" />
<tx:method name="find*" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut expression="execution(* com.itdream.ssh.dao.ProductService.*(..))" id="txPointcut"/>
<!-- 配置切入点与通知的关联 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
<!-- Spring容器中bean的装配 -->
<!-- 注册ProductDAO -->
<bean id="productDAO" class="com.itdream.ssh.dao.ProductDAO">
<!-- 注入SessionFactory -->
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 注册ProductService -->
<bean id="productService" class="com.itdream.ssh.dao.ProductService">
<!-- 注入ProductDAO -->
<property name="productDAO" ref="productDAO" />
</bean>
</beans>
注意:在导HibernateDaoSupport
包时注意版本
2.3 Spring与Struts2框架的整合
有完全整合与半整合两种方式。两种方式方法类似,完全整合在半整合的基础上使用applicationContext.xml
中不使用真正的Action
的全包名,而是使用伪类名,Struts2拿着这个伪类名去Spring
容器里面查找是否注册有该bean
,如果有直接从Spring
容器中取,否则自己创建。
这是导入了struts2-spring-plugin-2.3.32.jar
包,修改修struts的对象工厂为 spring (StrutsSpringObjectFactory),将默认Struts2
创建Action动作类对象的权利优先交给了Spring管理。
半整合:
由于有plugin的jar包,对象工厂变为spring之后, autoWire(自动绑定)机制被激活,默认按名称自动注入 bean.在struts.xml中配置jsp页面跳转Action动作类,Action动作类中提供需要注入的ProductService,提供它的setter方法,即完成了半整合.
完全整合[推荐]:
因为pluginjar包将对象工厂变为spring,开启了自动绑定机制,它会优先根据struts.xml中配置的class伪类名先去
Spring工厂中看有没有以这个伪类名注册的bean对象,如果有,从Spring工厂中直接取出来使用,如果没有,Struts2就自己
new 一个Action对象.
因此,在半整合的基础上,将Struts2页面访问Action的class全包名,改为在applicationContext.xml中注册的bean
的id名,这样优先查找spring容器时,就能通过Spring创建Action.
============================================================================
表单页面提交参数:
<s:form action="product_saveProduct.action" method="post">
商品名称:<s:textfield name="pname"/><br/>
商品价格:<s:textfield name="price"/><br/>
<s:submit value="提交"/>
</s:form>
struts.xml配置文件配置Action:
(class内使用伪类名,即applicationContext.xml中Action动作类的注册bean的id)
<!-- 自定义包,配置Action -->
<package name="default" namespace="/" extends="struts-default">
<action name="product_*" class="productAction" method="{1}"></action>
</package>
applicationContext.xml注册Action动作类 :
<!-- 注册ProductAction -->
<bean id="productAction" class="com.itdream.ssh.web.action.ProductAction" scope="prototype">
<!-- 注入Service -->
<property name="productService" ref="productService" />
</bean>
============================================================================
按照上面这么配置,Sturts2与Spring就完成了完全整合,Action动作类的创建交由给了Spring管理.并且可以使用Spring的AOP,属性注入等高级功能。
注意:Action
是多实例的,而Spring管理的对象是单实例的,因此注册bean
的时候,使用scope
设置其为多实例prototype
小结:
三、解决延迟加载问题
什么是延迟加载问题 ?
多表关系时,Spring的查找机制默认是懒加载的,在查找了员工数据,返回到表现层,Session关闭以后,表现层使用list时,
会发送sql语句查询关联的信息部门,这时候就会出错,因为session已经关闭了。
如何解决延迟加载问题?
方案一: 配置为立即加载 lazy=false (不推荐 )
我们查询的数据不一定都需要关联数据,太浪费资源。
方案二: Service方法返回前, 对延迟数据进行初始化 (缺点多写代码 )
List<Employee> list = dao.findAll ();
for(Employee e : list ){
Hibernate.initialize(e.getDepartment() );
}
【推荐】方案三: OpenSessionInView 机制 (将Session开启到表现层 最前面 Filter )
Spring框架提供了一个过滤器OpenSessionInViewFilter,让session对象在WEB层就创建,在WEB层销毁。
只需要配置该过滤器即可[需要配置在struts2 Filter前面]
web.xml:
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意:需要在struts2的核心过滤器之前进行配置
OpenSessionInViewFilter原理:
在request过程中维持session。延迟session的关闭,直到request结束,再自动关闭session。
缺点:
如果没有被事务管理的方法, OpenSessionInViewFilter 会将这些方法的事务变为 readOnly 的。
但是这个问题可以避免,在application的事务管理中:将事务拦截到的方法,都配置事务的属性。都设置好read-only的事务策略。
四、 各配置文件总结
SSH框架完全整合完毕后,各配置文件的最终形态:(以后使用直接修改)
此次整合用到的jar包37个。
4.1 web.xml配置文件
-
Spring
的核心监听器,将Spring容器与ServletContext
绑定,保证Spring
容器只有一个.- 前提:导入
Spring
的web
的jar包
- 前提:导入
-
OpenSessionView
过滤器,避免Spring与Hibernate
整合后的延迟加载问题,将Session
对象的关闭延迟到表现出。 -
Struts2
的前端控制器,拦截所有请求,进行统一处理(初始化,拦截器...)
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_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>day42_ssh2</display-name>
<!-- Spring的核心监听器 -->
<listener>
<!-- Spring提供的ContextLoaderListener监听器 -->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 全局参数 -->
<context-param>
<!-- 默认加载的配置文件在web-inf里的applicationContext.xml,因此需要修改 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- Struts2前端控制器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
4.2 struts.xml配置文件
- 开启配置文件自动加载
- 配置
Struts2
简单样式 - 根据页面请求,配置对应的
Action
- 这里的
class
使用伪类名,在applicationContext.xml
中配置对应的Action
动作类的bean
,完成整合
- 这里的
struts.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- 关闭开发者模式 -->
<!-- <constant name="struts.devMode" value="true" /> -->
<constant name="struts.configuration.xml.reload" value="true" />
<!-- 使用简单样式 -->
<constant name="struts.ui.theme" value="simple" />
<!-- 自定义包,配置Action -->
<package name="default" namespace="/" extends="struts-default">
<action name="product_*" class="productAction" method="{1}"></action>
</package>
</struts>
4.3 applicationContext.xml配置文件
- 配置数据源
- 这里是与
Hibernate
整合,因此配置SessionFactory
,将hibernate.cfg.xml的所有参数配置都配置到applicationContext.xml配置文件的sessionFactory
中- 注入数据源
- 配置Hibernate属性
- 加载Hibernate的映射文件
- 事务管理的配置
- 确定增强类Service(注册)
- 注册Spring提供的事务增强类
<tx:advice>
相当于注册- 注入事务管理器,属性transaction-manager="transactionManager"
- 配置事务的属性策略read-only等
- 注册事务管理器
<bean id="transactionManager" class="HibernateTransactionManager....">
- 注入数据源提供连接Session管理事务
- 配置切面aspect:
<aop:config>
- 定义切入点
<aop:pointcut>
- 配置切入点与通知的关联
<aop:advisor>
- 定义切入点
-
Spring容器bean
的装配注册- 其中注册DAO层,需要注入数据源,使
HibernateDaoSupport
能够生成HibernateTemplate
.
- 其中注册DAO层,需要注入数据源,使
appliactionContext.xml:
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 引入外部配置文件,下面使用${key}取值 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 注册数据源 -->
<bean id="dataSource" class="${jdbc.dataSourceClass}">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- Spring管理SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 1.数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 2.Hibernate属性 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<!-- 3.Hibernate映射文件 -->
<property name="mappingResources">
<list>
<value>com/itdream/ssh/domain/Product.hbm.xml</value>
</list>
</property>
</bean>
<!-- Spring事务管理 -->
<!-- 注册对应的事务管理器,注入数据源提供连接,这里是session以管理事务 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<!-- 注入数据源 -->
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 注册事务增强类,注入参数事务管理器,设置事务策略 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" />
<tx:method name="update*" />
<tx:method name="delete*" />
<tx:method name="find*" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut
expression="execution(* com.itdream.ssh.service.ProductService.*(..))"
id="txPointcut" />
<!-- 配置切入点与通知的关联 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>
<!-- Spring容器中bean的装配 -->
<!-- 注册ProductDAO -->
<bean id="productDAO" class="com.itdream.ssh.dao.ProductDAO">
<!-- 注入SessionFactory -->
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 注册ProductService -->
<bean id="productService" class="com.itdream.ssh.service.ProductService">
<!-- 注入ProductDAO -->
<property name="productDAO" ref="productDAO" />
</bean>
<!-- 注册ProductAction -->
<bean id="productAction" class="com.itdream.ssh.web.action.ProductAction" scope="prototype">
<!-- 注入Service -->
<property name="productService" ref="productService" />
</bean>
</beans>
4.4 log4j.properties与自定义的db.properties
log4j.properties:
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:\\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=info, stdout,file
----------------------------------------------------------------------------
db.properties:
jdbc.dataSourceClass=com.mchange.v2.c3p0.ComboPooledDataSource
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssh
jdbc.username=root
jdbc.password=root
4.5 持久化类对应的映射文件Xxx.hbm.xml
这里面主要为了展示一下,命名查询的hql
语句的定义:
<!-- 全局hql语句 -->
<query name="Product.findByNameLike">
from Product where pname like ?
</query>
总结完毕。