1.使用HibernateDaoSupport简化整合代码

原理:HibernateDaoSupport类有一个HibernateTemplate成员变量,提供一个setSessionFactory的方法,用于注入SessionFactory,把HibernateTemplate创建出来。

image

1)让dao类继承HibernateDaoSupport类

1
2
3
4
5
6
7
8
9
10
11
12
public class ProductDao extends HibernateDaoSupport implements IProductDao {

@Override
public List<Product> findAll() {
return this.getHibernateTemplate().loadAll(Product.class);
}

@Override
public void save(Product p) {
this.getHibernateTemplate().save(p);
}
}

2)简化applicationContext.xml配置文件

1
2
3
4
5
6
7
8
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- configLocation:用于加载hibernate.cfg.xml文件 -->
<property name="configLocation" value="classpath:/hibernate.cfg.xml"/>
</bean>
<!-- 创建dao -->
<bean id="productDao" class="gz.itheima.dao.impl.ProductDao">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

2.Spring整合Hibernate 的两套方案

2.1 存在hibernate.cfg.xml文件

1
2
3
4
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- configLocation:用于加载hibernate.cfg.xml文件 -->
<property name="configLocation" value="classpath:/hibernate.cfg.xml"/>
</bean>

2.2 不需要hibernate.cfg.xml文件(重点看)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 注入连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 注入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>
<!-- 注入映射文件的信息 -->
<property name="mappingResources">
<array>
<value>gz/itheima/entity/Category.hbm.xml</value>
<value>gz/itheima/entity/Product.hbm.xml</value>
</array>
</property>
</bean>

3.Spring整合Struts2

3.1 单独开发业务层,把事务切换到业务层

1)类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ProductBiz implements IProductBiz {
//注入dao
private IProductDao productDao;
public void setProductDao(IProductDao productDao) {
this.productDao = productDao;
}

@Override
public List<Product> findAll() {
return productDao.findAll();
}

@Override
public void save(Product p) {
productDao.save(p);
}

}

2)配置

1
2
3
4
<!-- 创建biz -->
<bean id="prductBiz" class="gz.itheima.biz.impl.ProductBiz">
<property name="productDao" ref="productDao"/>
</bean>

修改事务配置,把切入点换成业务层类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 配置Spring的事务管理 -->
<!-- 1.创建事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 2.创建事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 3.配置切面 -->
<aop:config>
<aop:pointcut expression="execution(* gz.itheima.biz.impl.*Biz.*(..))" id="myPT"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPT"/>
</aop:config>

3)测试

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:/applicationContext.xml"})
public class Demo1 {
//注入biz
@Resource(name="productBiz")
private IProductBiz productBiz;
@Test
public void test1(){
Product p =new Product();
p.setName("vivo");
productBiz.save(p);
}
}

注意:一旦把事务换到了业务层后,dao层的测试代码就不可用了!因为dao层没有事务啦!

3.2 单独使用Struts2框架

1)包

Struts2最小包(12)

注意:不要导入javassist-3.11.0.GA.jar,因为hibernate框架有了这个包,并且版本更高!

2)类和页面

Add.jsp页面

1
2
3
4
5
6
7
8
9
10
11
<s:form action="product_add">
<table border="1">
<tr>
<td>产品名称</td>
<td><s:textfield name="name"/></td>
</tr>
<tr>
<td><input type="submit" value="保存"/></td>
</tr>
</table>
</s:form>

ProductAction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ProductAction extends ActionSupport implements ModelDriven<Product>{
//接收参数
private Product p = new Product();
/**
* 保存数据
*/
public String add(){
System.out.println(p);
//调用业务
//回显信息页面
ActionContext ac = ActionContext.getContext();
ac.put("msg", "添加成功");
return SUCCESS;
}

@Override
public Product getModel() {
return p;
}
}

3)配置

Web.xml

1
2
3
4
5
6
7
8
9
<!-- struts的核心过滤器 -->
<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>

Struts.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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>
<!-- 修改struts的UI模块 ,该为简单模板-->
<constant name="struts.ui.theme" value="simple"/>

<package name="ssh" extends="struts-default" namespace="/">
<action name="product_*" class="gz.itheima.web.ProductAction" method="{1}">
<result>/succ.jsp</result>
</action>
</package>

</struts>

4)测试

部署tomcat,浏览器访问:

http://localhost:8080/day38_04_ssh_1/add.jsp

3.3 Spring框架整合Strut2

1)在Spring没有整合Struts2的情况下,需要手动到spring的IOC工厂获取biz对象

1
2
3
4
//1.不整合的情况下,直接调用spring的IOC工厂的biz的对象
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
productBiz = (IProductBiz)context.getBean("productBiz");
productBiz.save(p);
1
注意:这种情况下,action每次都需要重新读取applicationContext.xml文件,重新创建IOC工厂,效率是非常低的!

2)Spring框架整合struts2(重点)

原理:Spring框架提供了一个web监听器,放在spring-web的jar里面。

image

这个web监听器(ContextLoaderListener),主要是用于在项目启动的时候,一次性地把applicationContext.xml文件加载进内存,方便表现层去使用spring的对象。

image

整合步骤:

1)导入spring-web的jar包

image

2)在web.xml配置web监听器

1
2
3
4
5
6
7
8
9
10
<!-- 配置spring的web监听器,用于加载applicationContext.xml -->
<!-- 默认情况下,到WEB-INF目录下读取applicationContext.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 修改web监听器读取文件的路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>

3)修改action代码,从内存取出biz对象

1
2
3
4
5
6
//2.Spring整合struts2
//从内存中取出biz对象
ApplicationContext context =
WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());
productBiz = (IProductBiz)context.getBean("productBiz");
productBiz.save(p);

注意:这种情况下,action的代码比较麻烦,所以struts2提供了整合spring的方案,简化action获取biz对象的代码

3.4 Struts2框架整合Spring

1)导入struts2-spring-plugin的jar包

image

Struts-plugin.xml : 编写了一个拦截器。主要用于让action获取到spring环境的对象

image

2)修改action类和配置文件

方案一:Action对象是由Struts2创建的(根据spring的名称(bean的id)自动匹配)

1
2
3
4
5
6
7
8
private IProductBiz productBiz;
public void setProductBiz(IProductBiz productBiz) {
this.productBiz = productBiz;
}
<!-- 创建biz -->
<bean id="productBiz" class="gz.itheima.biz.impl.ProductBiz">
<property name="productDao" ref="productDao"/>
</bean>

方案二:Action对象是由Spring创建 (推荐使用)

在applicationContext.xml创建action对象

1
2
3
4
<!-- 创建 action -->
<bean id="productAction" class="gz.itheima.web.ProductAction">
<property name="prdoBiz" ref="productBiz"/>
</bean>

修改struts.xml文件的class属性

1
2
3
<action name="product_*" class="productAction" method="{1}">
<result>/succ.jsp</result>
</action>

image

注意:在方案二的情况,spring创建出来的action必须是设置成多例,否则会出现线程并发问题!

1
2
3
<bean id="productAction" class="gz.itheima.web.ProductAction" scope="prototype">
<property name="prdoBiz" ref="productBiz"/>
</bean>

4.解决Hibernate延迟加载数据显示问题

原理:spring框架设计了一个过滤器:OpenSessionInViewFilter

image

image

配置步骤:

在web.xml配置过滤器

1
2
3
4
5
6
7
8
9
<!-- 注意:OpenSessionInViewFilter必须配置在struts2的前面 -->
<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的配置前面才会生效!

问题建议