16.4.Struts
16.4. Struts
Struts 是 应用最广的 Java Web 开发框架,主要是因为它是最先发行的几个框架之一(2001年6月)。这个框架由 Craig McClanahan 开发完成,现在作为 Apache 软件基金会的一个开源项目。 当时,它极大地简化了 JSP/Servlet 编程范例并且赢得了 大多数正在使用私人框架的开发人员的亲睐。它简化了编程模型,它是开源的,它具有一个 庞大的社区,这些都使得这个项目快速成长,同时变得越来越流行。
要将 Struts 与 Spring 集成,你有两个选择:
配置 Spring 将 Action 作为 bean 托管,使用
ContextLoaderPlugin
, 并且在 Spring context中设置依赖关系。继承 Spring 的
ActionSupport
类并且 使用getWebApplicationContext() 方法获取 Spring 管理的 bean。
16.4.1. ContextLoaderPlugin
ContextLoaderPlugin
是 Struts 1.1+ 的插件,用来为 Struts 的 ActionServlet
加载 Spring context文件。 这个context引用 WebApplicationContext
(由 ContextLoaderListener
加载) 作为它的父类。默认的context文件是映射的 Servlet 的名字,加上 -servlet.xml后缀。 如果 ActionServlet
在 web.xml 里面的定义是 <servlet-name>action</servlet-name>
, 那么默认的文件就是 /WEB-INF/action-servlet.xml。
要配置这个插件,请把下面的 XML 贴到 struts-config.xml 文件中 plug-ins 部分的底端:
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"/>
context配置文件的位置可以通过 contextConfigLocation
属性来自定义。
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/action-servlet.xml.xml,/WEB-INF/applicationContext.xml"/> </plug-in>
你也可以使用这个插件加载所有的配置文件,这在使用测试工具(例如 StrutsTestCase)的时候特别有用。 StrutsTestCase 的 MockStrutsTestCase
不会在启动的时候初始化 Listener, 将你所有的配置文件放在plug-in里面是一种解决方案。(有个 已记录的 bug 就是针对这个问题的,但是已经被标记为“无须改正”)。
在 struts-config.xml 中配置好插件以后,你可以配置Sping来管理 Action
。Spring (1.1.3以后的版本) 提供下面两种方式:
用 Spring 的
DelegatingRequestProcessor
重载 Struts 默认的RequestProcessor
。将
<action-mapping>
的type
属性设为DelegatingActionProxy
。
这两种方法都允许你在 action-context.xml 文件中管理你的 Action 以及依赖关系。 连接 struts-config.xml 和 action-servlet.xml 中的 Action 的桥梁 是 action-mapping 的“path”和 bean 的“name”。如果你在 struts-config.xml 文件中有如下配置:
<action path="/users" .../>
你必须在 action-servlet.xml 中将 Action bean 的名字定义为 “/users”:
<bean name="/users" .../>
16.4.1.1. DelegatingRequestProcessor
为了在 struts-config.xml 文件中配置 DelegatingRequestProcessor
,你需要重载 <controller> 元素的 “processorClass” 属性。 下面的几行应该放在 <action-mapping> 元素的后面。
<controller> <set-property property="processorClass" value="org.springframework.web.struts.DelegatingRequestProcessor"/> </controller>
增加这些设置之后,不管你查询任何类型的 Action,Sping都自动在它的context配置文件中寻找。 实际上,你甚至不需要指定类型。下面两个代码片断都可以工作:
<action path="/user" type="com.whatever.struts.UserAction"/> <action path="/user"/>
如果你使用 Struts 的 modules 特性,你的 bean 命名必须含有 module 的前缀。 举个例子,如果一个 Action 的定义为 <action path="/user"/>
,而且它的 module 前缀为“admin”, 那么它应该对应名为 <bean name="/admin/user"/>
的 bean。
注意
如果你在 Struts 应用中使用了 Tiles,你需要配置 <controller> 为 DelegatingTilesRequestProcessor
。
16.4.1.2. DelegatingActionProxy
如果你有一个自定义的 RequestProcessor
并且不能够使用 DelegatingRequestProcessor
或者 DelegatingTilesRequestProcessor
,你可以使用 DelegatingActionProxy
作为你 action-mapping 中的类型。
<action path="/user" type="org.springframework.web.struts.DelegatingActionProxy" name="userForm" scope="request" validate="false" parameter="method"> <forward name="list" path="/userList.jsp"/> <forward name="edit" path="/userForm.jsp"/> </action>
action-servlet.xml 文件中的bean定义依然不变,不管你使用了自定义的 RequestProcessor
还是 DelegatingActionProxy
。
如果你把 Action
定义在Spring的context文件里,那么 Spring bean 容器的所有特性都可用了: 比如,依赖注入,再比如,为每个请求初始化一个新的 Action
实例。 如果要使用这个特性, Action bean 定义中需要声明singleton="false"。
<bean name="/user" singleton="false" autowire="byName" />
16.4.2. ActionSupport
类
正如前面提到的,你可以使用 WebApplicationContextUtils
类从 ServletContext 中获得 WebApplicationContext
。 另一个简单的办法是继承 Spring 的 Action
类。举个例子,除了继承 Struts 的 Action
之外,你也可以继承 Spring 的 ActionSupport
类。
ActionSupport
类提供了一些便利的方法,例如 getWebApplicationContext()。 下面的例子展示了如何在 Action 中使用它:
public class UserAction extends DispatchActionSupport { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { if (log.isDebugEnabled()) { log.debug("entering 'delete' method..."); } WebApplicationContext ctx = getWebApplicationContext(); UserManager mgr = (UserManager) ctx.getBean("userManager"); // talk to manager for business logic return mapping.findForward("success"); } }
Spring 包含了所有标准 Struts Action 的子类 - Spring 版本在类名末尾附加了 Support:
ActionSupport
,DispatchActionSupport
,LookupDispatchActionSupport
MappingDispatchActionSupport
你应该选择最适合你项目的集成方式。继承使得你的代码更可靠,并且你确切地知道依赖关系是如何被解析的。 另一方面,使用 ContextLoaderPlugin
允许你方便地在context XML 文件里面增加新的 依赖关系。这两种集成方法,不管哪一种 Spring 都提供了相当好用的选项。