- 浏览: 689347 次
- 性别:
- 来自: 成都
文章分类
- 全部博客 (129)
- Java (13)
- Android (9)
- J2ee (3)
- Swt/jface (0)
- SSH (9)
- C/C++ (1)
- php (1)
- Algorithm (2)
- Apache/Nginx (12)
- Bea/Tomcat (2)
- Oracle/Mysql (10)
- Sql/derby (17)
- Unix/Linux (11)
- Hadoop (1)
- Hbase (15)
- Redis (2)
- Lucene/Solr (0)
- Httpclient (1)
- Groovy (2)
- SoftwareEng (2)
- HTML/JS/CSS (3)
- Flex (1)
- log4j (1)
- Protocol (3)
- windows (0)
- Tools (1)
- docker (1)
- k8s (1)
- Business (3)
- Others (3)
最新评论
6.4 Spring整合Struts
虽然Spring也提供了自己的MVC组件,但一来Spring的MVC组件过于繁琐,二 来Struts的拥护者
实在太多。因此,很多项目都会选择使用Spring整合Struts框架。而且Spring确实可以无缝整合
Struts框架,二者结合成一个更实际的J2EE开发平台。
6.4.1 利用Struts的PlugIn来启动Spring容器
使用Spring的Web应用时,不用手动创建Spring容器,而是通过配置文件声明式地创建Spring容器。
因此,在Web应用中创建Spring容器有如下两个方式:
● 直接在web.xml文件中配置创建Spring容器。
● 利用第三方MVC框架的扩展点,创建Spring容器。
其实第一种创建Spring容器的方式更加常见。为了让Spring容器随Web应用的启动而自动启动,有如
下两个方法:
● 利用ServletContextListener实现。
● 采用load-on-startup Servlet实现。
Spring提供ServletContextListener的一个实现类ContextLoaderListener,该类可以作为Listener
使用,会在创建时自动查找WEB-INF/下的applicationContext.xml文件,因此,如果只有一个配置文
件,并且文件名为applicationContext.xml,只需在web.xml文件中增加如下配置片段即可:
<listener> <listener-class>org.springframework.web.context. ContextLoaderListener</listener-class> </listener>
如果有多个配置文件需要载入,则考虑使用<context-param>元素来确定配置文件的文件名。
ContextLoaderListener加载时,会查找名为contextConfigLocation的参数。因此,配置context-
param时,参数名字应该是contextConfigLocation。
带多个配置文件的web.xml文件如下:
<?xml version="1.0" encoding="GBK"?> <!-- 指定Web配置文件的根元素,以及相应的Schema信息 --> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <!-- 确定多个配置文件 --> <context-param> <!-- 参数名为contextConfigLocation --> <param-name>contextConfigLocation</param-name> <!-- 多个配置文件之间以“,”隔开 --> <param-value>/WEB-INF/daoContext.xml,/WEB-INF/ applicationContext.xml</param-value> </context-param> <!-- 采用listener创建ApplicationContext实例 --> <listener> <listener-class>org.springframework.web.context. ContextLoaderListener</listener-class> </listener> </web-app>
如果没有通过contextConfigLocation指定配置文件,Spring会自动查找application- Context.xml
配置文件;如果有contextConfigLocation,则利用该参数确定的配置文件。如果无法找到合适的配
置文件,Spring将无法正常初始化。
Spring根据bean定义创建WebApplicationContext对象,并将其保存在web应用的ServletContext中。
大部分情况下,应用中的Bean无须感受到ApplicationContext的存在,只要利用ApplicationContext
的IoC即可。
如果需要在应用中获取ApplicationContext实例,可以通过如下代码获取:
//获取当前Web应用的Spring容器
WebApplicationContext ctx =
WebApplicationContextUtils.getWebApplicationContext(servletContext);
除此之外,Spring提供了一个特殊的Servlet类ContextLoaderServlet。该Servlet在启动时,会自动
查找WEB-INF/下的applicationContext.xml文件。
当然,为了让ContextLoaderServlet随应用的启动而启动,应将此Servlet配置成load-on-startup的
Servlet,load-on-startup的值小一点比较合适,这样可以保证Application- Context更快的初始化。
如果只有一个配置文件,并且文件名为applicationContext.xml,在web.xml文件中增加如下一段即可:
<servlet> <servlet-name>context</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet>
该Servlet用于提供“后台”服务,主要用于创建Spring容器,无须响应客户请求,因此无须配置
servlet-mapping。
如果有多个配置文件,一样使用<context-param>元素来确定多个配置文件。
事实上,不管是ContextLoaderServlet,还是ContextLoaderListener,都依赖于ContextLoader创建
ApplicationContext实例。
在ContextLoader代码的第240行,有如下代码:
String configLocation = servletContext.getInitParameter (CONFIG_LOCATION_PARAM); if (configLocation != null) { wac.setConfigLocations(StringUtils.tokenizeToStringArray (configLocation, ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS)); }
其中,CONFIG_LOCATION_PARAM是该类的常量,其值为contextConfigLocation。可以看出,
ContextLoader首先检查servletContext中是否有contextConfigLocation的参数,如果有该参数,则
加载该参数指定的配置文件。
ContextLoaderServlet与ContextLoaderListener底层都依赖于ContextLoader。因此,二者的效果几
乎没有区别。之间的区别不是它们本身引起的,而是由于Servlet规范,Listener比Servlet优先加载。因此,采用ContextLoaderListener创建ApplicationContext的时机更早。
当然,也可以通过ServletContext的getAttribute方法获取ApplicationContext。但使用
WebApplicationContextUtils类更便捷,因为无须记住ApplicationContext的属性名。即使
ServletContext的WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRI- BUTE属性没有对应对象,WebApplicationContextUtils的getWebApplicationContext()方法将会返回空,而不会引起异常。到底需要使用Listener,还是使用load-on-startup Servlet来创建Spring容器呢?通常推荐使用Listener来创建Spring容器。但Listerner是Servlet 2.3以上才支持的标准,因此,必须Web容器支持Listener才可使用Listerner。
注意:使用Listener创建Spring容器之前,应先评估Web容器是否支持Listener标准。
还有一种情况,利用第三方MVC框架的扩展点来创建Spring容器,比如Struts。在第2章介绍Strust框
架时,知道Struts有一个扩展点PlugIn。
实际上,Spring正是利用了PlugIn这个扩展点,从而提供与Struts的整合。Spring提供了PlugIn接口
的实现类org.springframework.web.struts.ContextLoaderPlugIn。这个实现类可作为Struts的
PlugIn配置,Struts框架启动时,将自动创建Spring容器。
为了利用Struts的PlugIn创建Spring容器,只需在Struts配置文件中增加如下片段 即可:
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/action-servlet.xml,/WEB-INF/applicationContext. xml"/> </plug-in>
其中,指定contextConfigLocation属性值时,即可以指定一个Spring配置文件的位置,可以指定多
个Spring配置文件的位置。
6.4.2 MVC框架与Spring整合的思考
对于一个基于B/S架构的J2EE应用而言,用户请求总是向MVC框架的控制器请求,而当控制器拦截到用
户请求后,必须调用业务逻辑组件来处理用户请求。此时有一个问题,控制器应该如何获得业务逻辑
组件?
最容易想到的策略是,直接通过new关键字创建业务逻辑组件,然后调用业务逻辑组件的方法,根据
业务逻辑方法的返回值确定结果。
实际的应用中,很少见到采用上面的访问策略,因为这是一种非常差的策略。不这样做至少有如下3
个原因:
● 控制器直接创建业务逻辑组件,导致控制器和业务逻辑组件的耦合降低到代码层次,不利于高
层次解耦。
● 控制器不应该负责业务逻辑组件的创建,控制器只是业务逻辑组件的使用者。无须关心业务逻
辑组件的实现。
● 每次创建新的业务逻辑组件将导致性能下降。
答案是采用工厂模式或服务定位器。采用服务定位器的模式,是远程访问的场景。在这种场景下,业
务逻辑组件已经在某个容器中运行,并对外提供某种服务。控制器无须理会该业务逻辑组件的创建,
直接调用即可,但在调用之前,必须先找到该服务——这就是服务定位器的概念。经典J2EE应用就是
这种结构的应用。
对于轻量级的J2EE应用,工厂模式则是更实际的策略。因为轻量级的J2EE应用里,业务逻辑组件不是
EJB,通常就是一个POJO,业务逻辑组件的生成通常由工厂负责,而且工厂可以保证该组件的实例只
需一个就够了,可以避免重复实例化造成的系统开销。
如图6.2就是采用工厂模式的顺序图。
采用工厂模式,将控制器与业务逻辑组件的实现分离,从而提供更好的解耦。
在采用工厂模式的访问策略中,所有的业务逻辑组件的创建由工厂负责,业务逻辑组件的运行也由工
厂负责。而控制器只需定位工厂实例即可。
如果系统采用Spring框架,则Spring成为最大的工厂。Spring负责业务逻辑组件的创建和生成,并可
管理业务逻辑组件的生命周期。可以如此理解,Spring是一个性能非常优秀的工厂,可以生产出所有
的实例,从业务逻辑组件,到持久层组件,甚至控制器。
现在的问题是,控制器如何访问到Spring容器中的业务逻辑组件?为了让Action访 问Spring的业务
逻辑组件,有两种策略:
● Spring管理控制器,并利用依赖注入为控制器注入业务逻辑组件。
● 控制器显式定位Spring工厂,也就是Spring的容器ApplicationContext实例,并从工厂中获取
业务逻辑组件实例的引用。
第一种策略,充分利用Spring的IoC特性,是最优秀的解耦策略。但不可避免带来一些不足之处,归
纳起来主要有如下不足之处:
● Spring管理Action,必须将所有的Action配置在Spring容器中,而struts-config.xml文件中的
配置也不会减少,导致配置文件大量增加。
● Action的业务逻辑组件接收容器注入,将导致代码的可读性降低。
总体而言,这种整合策略是利大于弊。
第二种策略,与前面介绍的工厂模式并没有太大的不同。区别是Spring容器充当了业务逻辑组件的工
厂。控制器负责定位Spring容器,通常Spring容器访问容器中的业务逻辑组件。这种策略是一种折衷
,降低了解耦,但提高了程序的可读性。
Spring完全支持这两种策略,既可以让Spring容器管理控制器,也可以让控制器显式定位Spring容器
中的业务逻辑组件。
6.4.3 使用DelegatingRequestProcessor
这里介绍的是第一种整合策略:让Spring管理Struts的Action。那么同样有一个问题,让Spring管理Struts的Action时,客户端的HTTP 请求如何转向Spring容器中的Action?当使用Struts作为MVC框架时,客户端的HTTP请求都是直接向ActionServlet请求的,因此关键就是让ActionServlet将请求转发给Spring容器中的Action。这很明显可以利用Spring的另一个扩展点:通
过扩展RequestProcessor完成,使用扩展的RequestProcessor替换Struts的RequestProcessor。Spring完成了这种扩展,Spring提供的DelegatingRequestProcessor继承Request- Processor。为了让Struts使用DelegatingRequestProcessor,还需要在struts-config.xml文件中增加如下一行:
//使用spring的RequestProcessor替换struts原有的RequestProcessor
<controller processorClass="org.springframework.web.struts.
DelegatingRequestProcessor"/>
完成这个设置后,Struts会将截获到的用户请求转发到Spring context下的bean,根据bean的name属性来匹配。而Struts中的action配置则无须配置class属性,即使配置了class属性也没有任何用处,即下面两行配置是完全一样的:
//配置struts action时,指定了实现类 <action path="/user" type="lee.UserAction"/> //配置struts action时,没有指定实现类 <action path="/user"/> 下面的示例程序在上一个示例程序的基础上稍作修改,增加了客户端验证和程序国际化部分。也调用 了Spring的业务bean来验证登录。先看修改后的struts-config.xml文件: <!-- XML文件版本,编码集 --> <?xml version="1.0" encoding="gb2312"?> <!-- Struts配置文件的文件头,包括DTD等信息 --> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd"> <!-- struts配置文件的根元素 --> <struts-config> <!-- 配置formbean,所有的formbean都放在form-beans元素里定义 --> <form-beans> <!-- 定义了一个formbean,确定formbean名和实现类 --> <form-bean name="loginForm" type="lee.LoginForm"/> </form-beans> <!-- 定义action部分,所有的action都放在action-mapping元素里定义 --> <action-mappings> <!-- 这里只定义了一个action。而且没有指定该action的type元素 --> <action path="/login" name="loginForm" scope="request" validate="true" input="/login.jsp" > <!-- 定义action内的两个局部forward元素 --> <forward name="input" path="/login.jsp"/> <forward name="welcome" path="/welcome.html"/> </action> </action-mappings> <!-- 使用DelegatingRequestProcessor替换RequestProcessor --> <controller processorClass="org.springframework.web.struts. DelegatingRequestProcessor"/> <!-- 加载国际化的资源包 --> <message-resources parameter="mess"/> <!-- 装载验证的资源文件 --> <plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/WEB-INF/validator- rules.xml,/WEB-INF/validation.xml" /> <set-property property="stopOnFirstError" value="true"/> </plug-in> <!-- 装载Spring配置文件,随应用的启动创建ApplicationContext实例 --> <plug-in className="org.springframework.web.struts. ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml, /WEB-INF/action-servlet.xml"/> </plug-in> </struts-config>
修改后的struts-config.xml文件,增加加载国际化资源文件。配置Struts的action不需要class属性
,完成了ApplicationContext的创建。
然后考虑web.xml文件的配置,在web.xml文件中必须配置Struts框架的加载。除此之外,因为使用了
Spring管理Struts的Action,而Action是随HTTP请求启动的,因此,应将Action的作用域配置成
Request,为了使用Request作用域,必须在web.xml文件中增加适当的配置。
下面是web.xml文件的代码:
<?xml version="1.0" encoding="GBK"?> <!-- 指定Web配置文件的根元素,以及对应的Schema信息 --> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <!-- 定义一个Filter,该Filter是使用Request作用域的基础 --> <filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter. RequestContextFilter </filter-class> </filter> <!-- 定义filter-mapping,让上面的Filter过滤所有的用户请求 --> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 定义Struts的核心Servlet --> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet </servlet-class> <load-on-startup>2</load-on-startup> </servlet> <!-- 定义Struts的核心Servlet拦截所有*.do请求 --> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!-- 关于Struts标签库的配置 --> <jsp-config> <!-- 配置bean标签 --> <taglib> <taglib-uri>/tags/struts-bean</taglib-uri> <taglib-location>/WEB-INF/struts-bean.tld</taglib-location> </taglib> <!-- 配置html标签 --> <taglib> <taglib-uri>/tags/struts-html</taglib-uri> <taglib-location>/WEB-INF/struts-html.tld</taglib-location> </taglib> <!-- 配置logic标签 --> <taglib> <taglib-uri>/tags/struts-logic</taglib-uri> <taglib-location>/WEB-INF/struts-logic.tld</taglib-location> </taglib> </jsp-config> </web-app>
Struts的plug-in配置部分明确指出,Spring的配置文件有两个:applicationContext.xml和action
-servlet.xml。其实,完全可以使用一个配置文件。通常,习惯将Action Bean配置在控制器的
context内。action-servlet.xml用于配置表现层上下文,其详细配置信息如下:
<?xml version="1.0" encoding="gb2312"?> <!-- 指定Spring配置文件的根元素,以及对应的Schame信息 --> <beans xmlns="http://www.springframework.org/schema/beans" 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.xsd"> <!-- 每个request请求产生一个新实例,将所有该请求的作用域配置成request --> <bean name="/login" class="lee.LoginAction" scope="request"> <property name="vb" ref="vb"/> </bean> </beans>
因为每次请求都应该启动新的Action处理用户请求,因此,应将Action的作用域配置成Request。
注意:ActionServlet转发请求时,是根据Bean的name属性,而不是id属性。因此,此处确定的name
属性与Struts的action属性相同。
applicationContext.xml只有一个bean配置,即vb bean。其详细配置如下:
<?xml version="1.0" encoding="GBK"?> <!-- 指定Spring 配置文件的根元素,以及对应的Schema信息 --> <beans xmlns="http://www.springframework.org/schema/beans" 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.xsd"> <!-- 配置ValidBean实例 --> <bean id="vb" class="lee.ValidBeanImpl"/> </beans>
ValidBeanImpl是一个业务逻辑bean,本示例程序中仅作简单的判断,ValidBeanImpl的源代码如下:
//面向接口编程,实现ValidBean接口 public class ValidBeanImpl implements ValidBean { //根据输入的用户名和密码判断是否有效 public boolean valid(String username,String pass) { //有效,返回true if (username.equals("scott") && pass.equals("tiger")) { return true; } return false; } }
注意:上面的业务逻辑组件非常简单,它只是一个示意。如果是真实的应用,业务逻辑组件应该通过
DAO组件来实现业务逻辑方法。
应用的业务逻辑控制器,Action则负责调用业务逻辑组件的方法,并根据业务逻辑组件方法的返回值
,确定如何响应用户请求。下面是该示例应用控制器的代码:
//业务控制器继承Action public class LoginAction extends Action { //action控制器将调用的业务逻辑组件 private ValidBean vb; //依赖注入业务逻辑组件的setter方法 public void setVb(ValidBean vb) { this.vb = vb; } //必须重写该核心方法,该方法actionForm将表单的请求参数封装成值对象 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)throws Exception { //form由ActionServlet转发请求时创建,封装了所有的请求参数 LoginForm loginForm = (LoginForm)form; //获取username请求参数 String username = loginForm.getUsername(); //获取pass请求参数 String pass = loginForm.getPass(); //下面为服务器端的数据校验 String errMsg = ""; //判断用户名不能为空 if (username == null || username.equals("")) { errMsg += "您的用户名丢失或没有输入,请重新输入"; } //判断密码不能为空 else if(pass == null || pass.equals("")) { errMsg += "您的密码丢失或没有输入,请重新输入"; } //如果用户名和密码不为空,才调用业务逻辑组件 else { //vb是业务逻辑组件,由容器注入 if (vb.valid(username,pass)) { return mapping.findForward("welcome"); } else { errMsg = "您的用户名和密码不匹配"; } } //判断是否生成了错误信息 if (errMsg != null && !errMsg.equals("")) { //如果有错误信息,将错误信息保存在request里,并跳转到input对应的 forward对象 request.setAttribute("err" , errMsg); return mapping.findForward("input"); } else { //如果没有错误信息,跳转到welcome对应的forward对象 return mapping.findForward("welcome"); } } }
在本应用中,使用了Struts的客户端数据校验,让Action继承ValidatorActionForm即可。
ActionForm的代码非常简单,此处不再赘述。
为了完成数据校验,还应该编写数据校验规则文件。在struts-config.xml文件的尾部,另有一个
plug-in用来加载校验文件,其中validator-rules.xml文件位于struts压缩包的lib下,直接复制过
来即可使用,而validator.xml必须自己编写,validator.xml文件如下:
<?xml version="1.0" encoding="GBK"?> <!-- 验证规则文件的文件头,包括DTD等信息 --> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN" "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd"> <!-- 验证文件的根元素 --> <form-validation> <!-- 所有需要验证的form都放在formset里 --> <formset> <!-- 需要验证的form名,该名与struts里配置的名相同 --> <form name="loginForm"> <!-- 指定该form的username域必须满足的规则:必填、模式匹配 --> <field property="username" depends="required,mask"> <arg key="loginForm.username" position="0"/> <var> <!-- 确定匹配模式的正则表达式 --> <var-name>mask</var-name> <var-value>^[a-zA-Z]+$</var-value> </var> </field> <!-- 指定该form的pass域必须满足的规则:必填 --> <field property="pass" depends="required"> <msg name="required" key="pass.required"/> <arg key="loginForm.pass" position="0"/> </field> </form> </formset> </form-validation>
上面示例程序的结构非常清晰:表现层组件(Action)配置在action-servlet.xml文件中,而业务逻
辑层组件(vb)配置在applicationContext.xml文件中,如果应用中有DAO组件,将DAO组件配置在
dao-context.xml文件中。将3个文件放在plug-in元素里一起加载。
DelegatingRequestProcessor会将请求转发到Action,该Action已经处于IoC容器管理之下,因此,
可以方便地访问容器中的其他Bean。
通过配置文件可以看出,Action根本无须type属性,即struts-config.xml中Action根本没有实例化
过,DelegatingRequestProcessor将请求转发给Spring容器中的同名Bean。这种转发的时机非常早,
避免了创建struts-config.xml配置文件中的Action,因而性能非常好。
图6.3是采用这种整合策略的执行效果。
6.4.4 使用DelegatingActionProxy
使用DelegatingRequestProcessor简单方便,但有一个缺点,RequestProcessor是Struts的一个扩展
点,也许应用程序本身就需要扩展RequestProcessor,而DelegatingRequest- Processor已经使用了
这个扩展点。
为了重新利用Struts的RequestProcessor这个扩展点,有两个做法:
● 应用程序的RequestProcessor不再继承Struts的RequestProcessor,改为继承
DelegatingRequestProcessor。
● 使用DelegatingActionProxy。
前者常常有一些未知的风险,而后者是Spring推荐的整合策略。使用Delegating- ActionProxy与
DelegatingRequestProcessor的目的都只有一个,将请求转发给Spring管理的Bean。
DelegatingRequestProcessor直接替换了原有的RequestProcessor,在请求转发给action之前,转发
给Spring管理的Bean;而DelegatingActionProxy则被配置成Struts的Action,即所有的请求先被
ActionServlet截获,请求被转发到对应的Action,而action的实现类全都是DelegatingActionProxy
,DelegatingActionProxy再将请求转发给Spring容器的Action。
可以看出,使用DelegatingActionProxy比使用DelegatingRequestProcessor要晚一步转发到Spring的context。但通过这种方式可以避免占用扩展点。
与使用DelegatingRequestProcessor相比,使用DelegatingActionProxy仅需要去掉controller配置
元素,并将所有的action实现类改为DelegatingActionProxy即可。详细的配置文件如下:
<!-- XML文件的版本和编码集 --> <?xml version="1.0" encoding="gb2312"?> <!-- struts配置文件的文件头,包括DTD等信息 --> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd"> <!-- struts配置文件的根元素 --> <struts-config> <!-- 配置formbean,所有的formbean都放在form-beans元素里定义 --> <form-beans> <!-- 定义了一个formbean,确定formbean名和实现类 --> <form-bean name="loginForm" type="lee.LoginForm"/> </form-beans> <!-- 定义action部分,所有的action都放在action-mapping元素里定义 --> <action-mappings> <!-- 这里只定义了一个action。必须配置action的type元素为 DelegatingActionProxy --> <action path="/login" type="org.springframework.web.struts. DelegatingActionProxy" name="loginForm" scope="request" validate="true" input= "/login.jsp" > <!-- 定义action内的两个局部forward元素 --> <forward name="input" path="/login.jsp"/> <forward name="welcome" path="/welcome.html"/> </action> </action-mappings> <!-- 加载国际化的资源包 --> <message-resources parameter="mess"/> <!-- 装载验证的资源文件 --> <plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/WEB-INF/validator- rules.xml,/WEB-INF/validation.xml" /> <set-property property="stopOnFirstError" value="true"/> </plug-in> <!-- 装载Spring配置文件,随应用启动创建ApplicationContext实例 --> <plug-in className="org.springframework.web.struts. ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml, /WEB-INF/action-servlet.xml"/> </plug-in> </struts-config>
DelegatingActionProxy接收ActionServlet转发过来的请求,然后转发给Application- Context管理
的Bean,这是典型的链式处理。
通过配置文件可以看出,struts-config.xml文件中配置了大量DelegatingActionProxy实例,Spring
容器中也配置了同名的Action。即Struts的业务控制器分成了两个部分:第一个部分是Spring的
DelegatingActionProxy,这个部分没有实际意义,仅仅完成转发;第二个部分是用户的Action实现
类,该实现类负责真实的处理。
这种策略的性能比前一种策略的效果要差一些,因为需要多创建一个Delegating- ActionProxy实例
。而且,J2EE应用中Action非常多,这将导致大量创建DelegatingActionProxy实例,使用一次之后
,等待垃圾回收机制回收——这对性能的影响不可避免。
图6.4是DelegatingActionProxy的执行效果。
注意:使用DelegatingActionProxy的整合策略,可避免占用Struts的RequestProcessor扩展点,但
降低了整合性能。
6.4.5 使用ActionSupport代替Action
前面已经介绍了,Spring与Struts的整合还有一种策略,让Struts的Action显式获取Spring容器中的
Bean。在这种策略下,Struts的Action不接受IoC容器管理,Action的代码与Spring API部分耦合,
造成代码污染。这种策略也有其好处:代码的可读性非常强,Action的代码中显式调用业务逻辑组件
,而无须等待容器注入。
Action中访问ApplicationContext有两种方法:
● 利用WebApplicationContextUtils工具类。
● 利用ActionSupport支持类。
通过WebApplicationContextUtils,可以显式获得Spring容器的引用(请参阅6.4.1节的内容),而
ActionSupport类则提供了一个更简单的方法getWebApplicationContext(),该方法可直接获取
Spring容器的引用。
所谓ActionSupport类,是指Spring提供了系列扩展。Spring扩展了Struts的Action,在Struts的
Action后加上Support后缀,Spring扩展的Action有如下几个:
● ActionSupport。
● DispatchActionSupport。
● LookupDispatchActionSupport。
● MappingDispatchActionSupport。
下面的示例将展示这种整合策略,在这种整合策略下,Struts的Action改为继承Spring扩展后的
Action,下面是应用的Action代码:
//新的业务控制器,继承Spring的ActionSupport类 public class LoginAction extends ActionSupport { //依然将ValidBean作为成员变量 private ValidBean vb; //构造器,注意:不可在构造器中调用getWebApplicationContext()方法 public LoginAction() { } //完成ValidBean的初始化 public ValidBean getVb() { return(ValidBean)getWebApplicationContext().getBean("vb"); } //必须重写该核心方法,该方法actionForm将表单的请求参数封装成值对象 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)throws Exception { //form由ActionServlet转发请求时创建,封装了所有的请求参数 LoginForm loginForm = (LoginForm)form; //获取username请求参数 String username = loginForm.getUsername(); //获取pass请求参数 String pass = loginForm.getPass(); //下面为服务器端的数据校验 String errMsg = ""; //判断用户名不能为空 if (username == null || username.equals("")) { errMsg += "您的用户名丢失或没有输入,请重新输入"; } //判断密码不能为空 else if(pass == null || pass.equals("")) { errMsg += "您的密码丢失或没有输入,请重新输入"; } //如果用户名和密码不为空,才调用业务逻辑组件 else { //vb是业务逻辑组件,通过上面的初始化方法获得 if (getVb().valid(username,pass)) { return mapping.findForward("welcome"); } else { errMsg = "您的用户名和密码不匹配"; } } //判断是否生成了错误信息 if (errMsg != null && !errMsg.equals("")) { //如果有错误信息,将错误信息保存在request里,并跳转到input对应的 //forward对象 request.setAttribute("err" , errMsg); return mapping.findForward("input"); } else { //如果没有错误信息,跳转到welcome对应的forward对象 return mapping.findForward("welcome"); } } }
在上面的Action代码中,Action显式获取容器中的业务逻辑组件,而不是依靠Spring容器的依赖注入
。在这种整合策略下,表现层的控制器组件不再接受IoC容器管理。因此,没有控制器上下文,应将
原有的action-servlet.xml文件删除,并修改plug-in元素,不要加载该文件。还要修改Action配置
,将Action配置的type元素修改成实际的处理类。这 种整合策略也有一个好处:代码的可读性
更强,对传统Struts应用开发的改变很小,容易使用。
将该Action部署在struts-config.xml中,Struts将负责创建该Action。struts-config.xml文件的源
代码如下:
<!-- XML文件的版本和编码集 --> <?xml version="1.0" encoding="gb2312"?> <!-- Struts配置文件的文件头,包括DTD等信息 --> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd"> <!-- struts配置文件的根元素 --> <struts-config> <!-- 配置formbean,所有的formbean都放在form-beans元素里定义 --> <form-beans> <!-- 定义了一个formbean,确定formbean名和实现类 --> <form-bean name="loginForm" type="lee.LoginForm"/> </form-beans> <!-- 定义action部分,所有的action都放在action-mapping元素里定义 --> <action-mappings> <!-- 这里只定义了一个action。action的类型为ActionSupport的子类 --> <action path="/login" type="type="lee.LoginAction" name="loginForm" scope="request" validate="true" input= "/login.jsp" > <!-- 定义action内的两个局部forward元素 --> <forward name="input" path="/login.jsp"/> <forward name="welcome" path="/welcome.html"/> </action> </action-mappings> <!-- 加载国际化的资源包 --> <message-resources parameter="mess"/> <!-- 装载验证的资源文件 --> <plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/WEB-INF/validator- rules.xml,/WEB-INF/validation.xml" /> <set-property property="stopOnFirstError" value="true"/> </plug-in> </struts-config>
此时,Spring无须使用配置Action的配置文件,这种配置方式非常简单。只需要业务逻辑组件的配置
文件,业务逻辑组件的配置文件与前面的示例没有任何改变。
该配置文件中的业务逻辑组件由Spring容器负责实现,而ActionSupport能够先定位Spring容器,然后获得容器的业务逻辑组件。这种整合策略的执行效果与前面两种整合策略的执行效果完全相同。从代码中分析可见,在这种整合策略下,业务控制器再次退回到Struts起初的设计。仅由strutsconfig.xml中Action充当,从而避免了像DelegatingActionProxy整合策略的性能低下,因为可以只需要创建实际的Action实例。注意:在这种整合策略下,Struts开发者的改变最小,最接近传统Struts应用开发者的习惯。但这种整合策略会造成代码污染,因为Action类必须继承Spring的ActionSupport类。
发表评论
-
基于Spring AOP 注解缓存Demo [附源码]
2016-08-27 19:20 0一. 现在的缓存: 现在APP局部或多或少都使用了缓存, ... -
Ibatis+Spring整合实例Demo+源码
2011-12-02 21:03 81461. 单独整合ibatis ibatis和hibernate ... -
纯Struts2登录实例Demo+源码
2011-12-01 17:12 22946接触到别人的新的项目, 不得不研究下Struts2了. 用st ... -
Spring3+Hibernate3+Struts1流程总结
2011-05-14 17:27 1917SSH结束之后,NOVA团队就基于SSH实现了NOVA音乐视频 ... -
Spring3整合Hibernate3
2011-05-14 17:14 70536.5 Spring整合Hibernate 时至今日,可能极 ... -
Spring的AOP
2011-05-14 16:50 12026.2 Spring的AOP AOP(Aspe ... -
Spring中的事务
2011-05-14 16:42 12536.3 Spring的事务 Spring的事务管理不需与任何 ... -
<<Hibernate基础教程>>总结
2011-05-14 16:34 1532一.总体概述: Hibernate 的底层也是由JDBC 实现 ... -
<<深入浅出Struts>>总结
2011-05-14 16:28 1164一.纵观本书:基本原理是实现控制器的功能和展示层的标签.for ...
相关推荐
标题中的"Spring集成struts以及hibernate jar包"指的是在Java Web开发中,将Spring框架与Struts2和Hibernate框架进行整合的过程。这通常是为了构建一个完整的MVC(Model-View-Controller)架构,其中Spring负责依赖...
在IT行业中,SSH(Spring、Struts2、...总的来说,Spring整合Struts2是一种最佳实践,能够提升企业级应用的开发效率和质量。理解这一整合过程,对于任何想要深入理解和使用SSH框架的开发者来说,都是非常重要的。
通过上述三种不同的整合方式,我们可以根据项目的具体需求选择最合适的方法来实现Spring和Struts框架的有效集成。每种方法都有其特点和适用场景,理解它们的工作原理可以帮助我们更好地设计和开发出高效、灵活的Java...
下面我们将详细探讨Spring与Struts1.2的整合集成及其核心概念。 1. **Spring框架介绍** Spring是一个全面的后端开发框架,包括了数据访问、事务管理、远程调用、AOP等模块。它通过DI和AOP简化了对象的创建和管理,...
总的来说,整合Spring和Struts编写多页面用户注册模块涉及到的主要知识点有:Spring的DI和AOP,Struts的MVC架构,Action和Result的配置,以及JSP或模板引擎的使用。通过这样的整合,我们可以构建出一个灵活、可扩展...
Spring集成Struts与Hibernate入门详解 Spring框架是Java平台上一个开源的轻量级框架,它提供了许多功能强大且灵活的模块,以帮助开发者快速构建企业级应用程序。Struts是Apache软件基金会的一个开源项目,提供了一...
总的来说,Spring整合Struts是一个常见的Java Web开发实践,它能够帮助开发者构建出更灵活、可扩展的系统,同时也降低了代码的耦合度,提高了项目的可维护性。对于Java Web开发者来说,理解和掌握这种整合方式是非常...
Spring整合Struts2是Web开发领域中常见的技术组合,它结合了Spring的强大 IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)功能,以及Struts2的MVC(Model-View-...
spring框架整合struts框架时必需的类库文件
- Spring还提供了对其他库的集成,如JDBC、JMS、JTA等,以及对其他框架如Hibernate、Struts2的整合支持。 2. **Hibernate框架**: - Hibernate是一个对象关系映射(Object-Relational Mapping,ORM)框架,它简化...
8. **测试**:整合 Spring 和 Struts2 后,单元测试和集成测试变得更加方便。你可以利用 Spring 的 TestContext Framework 和 Struts2 的 Mock 测试工具进行测试。 9. **性能优化**:合理配置缓存策略、减少数据库...
### Spring与Struts整合的三种主要方式 在Java Web开发领域,Spring框架和Struts框架都是非常重要的技术。Spring框架以其强大的依赖注入(DI)和面向切面编程(AOP)功能,为Java应用提供了轻量级的解决方案。而...
此资源中包涵了spring整合struts和hibernate的所有资源,在做项目时只要在工程中引入该jar包就行,不用在eclipse或Myeclipse中加载strut与hibernate的资源了,挺有用的!
1. **Spring整合** - 在MyEclipse中添加Spring支持,选择相应的Spring版本和开发包,如Spring 1.2系列。 - 创建Spring配置文件(如`applicationContext.xml`),配置Bean定义,包括Service层、DAO层以及Action类等...
整合 Spring 和 Struts 可以利用 Struts 的 PlugIn 机制来启动 Spring 容器,这样可以在 Struts 框架运行时无缝集成 Spring 的功能。以下是整合步骤的详细说明: 1. **创建 Spring 容器**: - Spring 容器可以通过...
### Spring集成Struts #### 一、Spring与Struts整合背景及意义 Spring框架作为一款轻量级的Java EE开发框架,在企业级应用开发中占据了举足轻重的地位。它以其强大的依赖注入(DI)和面向切面编程(AOP)能力著称...