SSH 框架整合技术:
  3. Spring与Struts2整合(对比SpringWeb):

    Spring 与 Struts2 整合的目的有两个:
      (1)在 Struts2 的 Action 中,即 View 层,获取到 Service。然后就实现了在 Struts2 项目中 View 层、Service 层、Dao 层的联通。
      (2)将 Action 实例交由 Spring 容器管理。

    代码详解:

    (1) 将 Servlet 修改成 Action:

 package com.tongji.actions;

 import com.tongji.beans.Student;
import com.tongji.service.IStudentService; public class RegisterAction {
private String name;
private int age; //声明Service对象
private IStudentService service; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public IStudentService getService() {
return service;
} public void setService(IStudentService service) {
this.service = service;
} public String execute() {
Student student = new Student(name, age);
service.addStudent(student);
return "success";
}
}

    注意:直接将Service作为Action的属性

    (2) 在 Spring 配置文件中注册 Action 的 Bean
      在 Spring 的配置文件中将 Action 作为一个普通 Bean 进行定义,并在配置文件中完成 Service 的注入。即添加如下代码:

          <!-- 注册Action:必须指定Action的scope为prototype,因为Action是多例的 -->
          <bean id="registerAction" class="com.tongji.actions.RegisterAction" scope="prototype">
              <property name="service" ref="studentService"/>
          </bean>

    (3) Struts2 配置文件中的 class 使用伪类名
      Struts2 配置文件中的<action/>标签的 class 属性值不再是 Action 的全类名了,而是个伪类名:Spring 配置文件中该 Bean 的 id 名。

 <?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>
<package name="ssh" namespace="/test" extends="struts-default">
<!-- class的值是Spring容器中Action的Bean的id值,此时的class的属性值称为 伪类 -->
<action name="register" class="registerAction">
<result>/welcome.jsp</result>
</action>
</package>
</struts>

    (4) 修改前端页面:

 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html>
<head>
<title>index</title>
</head> <body>
<form action="test/register.action" method="POST">
name:<input type="text" name="name"/><br>
age:<input type="text" name="age"/><br>
<input type="submit" value="submit"/>
</form>
</body>
</html>
 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html>
<head>
<title>welcome</title>
</head> <body>
welcome you!
</body>
</html>

    (5) 其余代码都不变,发布运行即可。

  补充问题:当将事务织入到 Service 层后,在 Dao 层通过 load()等具有延迟加载功能的方法加载实体时,会出现异常。

  View 层要读取一个对象的某属性值,所以在 View 层调用了 Service 层的对象获取方法。此时 Service 层就会去调用 Dao 层,欲从 DB 中读取数据。但由于 Service 层并非是真正需要数据的一方,即 Servcie 层并非真正需要数据的详情。又由于 Dao 层使用了延迟加载技术,所以返回给 Service 层一个数据为空的代理对象。当 Service 获取到了这个对象后,马上将这个对象返回给了 View 层。Service 层认为任务完成,所以将事务进行了关闭。由于 Session 必须在事务环境下运行,且事务在提交或回滚后,会首先将Session 关闭,而后关闭事务。所以事务关闭前,Session 就已经消失。当 View 层收到 Service 层发送来的对象,并使用其详情时,发现为空。此时 View 层向 Service 层发出进行真正查询请求时,Service 层的 Session 已经不存在,所以,会报出 Session 为空的异常。

  解决办法:

  问题的主要原因是事务应用在业务层,而延迟加载使得对 Hibernate 的 Session 的连续使用放在了 View 层。若要 Session 不进行自动关闭,必须使其所在的事务环境不能在 Service 层就结束,所以可以将 Session 的开启放在 View 层。  
    只需在 web.xml 中注册一个过滤器 OpenSessionInViewFilter(开启 Session 在 View),只要用户提交请求,就会先执行该过滤器,将 Session 开启。

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<!-- 指定Spring配置文件的名称及位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param> <!-- 注册监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <!-- 注册OpenSessionInViewFilter,要求其必须在Struts启动项这个Filter的前面注册 -->
<filter>
<filter-name>OpenSessionInView</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
<!-- 默认OpenSessionInViewFilter加载的SessionFactory名称为sessionFactory
这里指定自己定义的SessionFactory的名称,让OpenSessionInViewFilter加载 -->
<!-- <init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>mySessionFactory</param-value>
</init-param> -->
</filter>
<filter-mapping>
<filter-name>OpenSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <!-- 注册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.jsp</welcome-file>
</welcome-file-list> </web-app>

    注册过滤器时需要注意:
    (1)该过滤器会自动从 Spring 配置文件中查找名称为 sessionFactory 的 Bean。若定义的不是这个名称,则需通过初始化参数<init-param/>进行指定。

    
    (2)该过滤器应注册在 StrutsPrepareAndExecuteFilter 的前面,即在进入 Struts2 之前先执行过滤,否则还会出现noSession的问题。其注册顺序可以从 Struts2 的流程图中看出。

    
    过滤器的执行都是通过过滤器链串起来执行的,即当前的 Filter 通过在自己的 doFilter() 方法中执行 chain.doFilter()来调用执行下一下过滤器。
      查看 StrutsPrepareAndExecuteFilter 的源码可以看出,只有当没有 Action 要执行时,才可能会执行其它的过滤器,即调用 chain.doFilter()。否则,只要有 Action 能够匹配上执行,那么就没有 chain.doFilter()方法要执行了,即 Struts2 的 StrutsPrepareAndExecuteFilter 将成为最后一个被执行的 Filter。所以,只有将 OpenSessionInViewFilter 放到 Struts2 的过滤器StrutsPrepareAndExecuteFilter 的前面才会被执行到。
    

    至此,SSH整合就结束了。

Spring4笔记12--SSH整合3--Spring与Struts2整合的更多相关文章

  1. Spring与Struts2整合VS Spring与Spring MVC整合

    Spring与Struts2整合,struts.xml在src目录下 1.在web.xml配置监听器 web.xml <!-- 配置Spring的用于初始化ApplicationContext的 ...

  2. spring与struts2整合出现错误HTTP Status 500 - Unable to instantiate Action

    在进行spring和struts2整合的时候因为大意遇到了一个问题,费了半天神终于找到了问题所在,故分享出来望广大博友引以为戒!! 我们都知道在spring和struts2整合时,spring接管了a ...

  3. SSM整合(2): spring 与 mybatis 整合

    在进行完spring与springmvc整合之后, 继续 spring与mybatis的整合. 既然是操作数据库, 那必然不能缺少了连接属性 一. db.properties jdbc.driver= ...

  4. Spring与Struts2整合时action自动注入的问题

    当Struts和Spring框架进行整合时,原本由action实例化对象的过程移交给spring来做(这个过程依赖一个叫struts2-spring-plugin的jar包,这个包主要的功能就是实现刚 ...

  5. Spring与Struts2整合

    Spring与Struts2为什么要整合呢? 把Action实例交给Spring来管理!! 1.单独测试Struts是否添加成功(jar包和配置文件),先单独测试,不要整合之后再测试,容易出问题 we ...

  6. SSM整合(1): spring 与 springmvc 整合

    久没有写博客了, 今年事情太多了, 也没了心思. 去深圳出差,  更重要的结婚的事情, 一茬接一茬. 好在最近闲暇一些, 就想记录一些曾经困扰过我的问题(现在用spring boot真是太方便了, 很 ...

  7. Spring注解与Spring与Struts2整合

    @Component @Controller @Service @Repository 四大注解作用基本一样,只是表象在不同层面 @Resource @Scope Struts2与Spring整合:1 ...

  8. Spring和Struts2整合

    目的:spring容器管理Action类,代替Servlet 步骤:主要在配置文件 Struts2: 添加支持spring的jar包, 配置<action class="Action类 ...

  9. spring+hibernate+Struts2 整合(全注解及注意事项)

    最近帮同学做毕设,一个物流管理系统,一个点餐系统,用注解开发起来还是很快的,就是刚开始搭环境费了点事,今天把物流管理系统的一部分跟环境都贴出来,有什么不足的,请大神不吝赐教. 1.结构如下 2.jar ...

  10. spring与struts2整合出现常见错误

    错误信息 严重: Exception starting filter struts2 Unable to load configuration. - bean - jar:file:/F:/Strut ...

随机推荐

  1. Delphi 判断一个字符串是否为数字

    //函 数 名: IsDigit//返 回 值: boolean//日       期:2011-03-01//参       数: String//功       能: 判断一个字符串是否为数字// ...

  2. 基于c的简易计算器一

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <malloc.h&g ...

  3. 【大数据】Azkaban学习笔记

    一 概述 1.1 为什么需要工作流调度系统 1)一个完整的数据分析系统通常都是由大量任务单元组成: shell脚本程序,java程序,mapreduce程序.hive脚本等 2)各任务单元之间存在时间 ...

  4. Alpha 冲刺 —— 十分之六

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 测试服务器并行能力 学习MSI.CUDA ...

  5. 【BZOJ4709】【Jsoi2011】柠檬

    Description 传送门 题意简述:将序列划分成任意多段,从每一段选出一个数\(x\),获得\(在这一段出现的次数x*(x在这一段出现的次数)\)的贡献.求总贡献最大值. Solution ​ ...

  6. 【51Nod1847】奇怪的数学题

    ​ 记\(f(x)=\)\(x\)的次大因数,那么\(sgcd(i,j)=f(gcd(i,j))\). 下面来推式子: \[ \begin{aligned} \sum_{i=1}^n\sum_{j=1 ...

  7. ThinkPHP 5.x远程命令执行漏洞分析与复现

    0x00 前言 ThinkPHP官方2018年12月9日发布重要的安全更新,修复了一个严重的远程代码执行漏洞.该更新主要涉及一个安全更新,由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的 ...

  8. php版本的code review软件

    phabricator, http://www.oschina.net/p/phabricator

  9. git的一些常见问题

    from:http://hi.baidu.com/mvp_xuan/blog/item/2ba062d8cd2c9fc939012fae.html 关于linux上建库等操作请看文章: http:// ...

  10. Python高手之路【四】python函数装饰器,迭代器

    def outer(func): def inner(): print('hello') print('hello') print('hello') r = func() print('end') p ...