1.
窍门 1. 使用 Spring 的 ActionSupport
手动创建一个 Spring 环境是一种整合 Struts 和 Spring 的最直观的方式。为了使它变得更简单,Spring 提供了一些帮助。为了方便地获得 Spring 环境,
org.springframework.web.struts.ActionSupport
类提供了一个
getWebApplicationContext()
方法。您所做的只是从 Spring 的
ActionSupport
而不是 Struts
Action
类扩展您的动作,如清单 1 所示:
清单 1. 使用 ActionSupport 整合 Struts
package ca.nexcel.books.actions; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.DynaActionForm; import org.springframework.context.ApplicationContext; import org.springframework.web.struts.ActionSupport; import ca.nexcel.books.beans.Book; import ca.nexcel.books.business.BookService; public class SearchSubmit extends ActionSupport { |(1) public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { DynaActionForm searchForm = (DynaActionForm) form; String isbn = (String) searchForm.get("isbn"); //the old fashion way //BookService bookService = new BookServiceImpl(); ApplicationContext ctx = getWebApplicationContext(); |(2) BookService bookService = (BookService) ctx.getBean("bookService"); |(3)
Book book = bookService.read(isbn.trim()); if (null == book) { ActionErrors errors = new ActionErrors(); errors.add(ActionErrors.GLOBAL_ERROR,new ActionError ("message.notfound")); saveErrors(request, errors); return mapping.findForward("failure") ; } request.setAttribute("book", book); return mapping.findForward("success"); } }
|
让我们快速思考一下这里到底发生了什么。在 (1) 处,我通过从 Spring 的
ActionSupport
类而不是 Struts 的
Action
类进行扩展,创建了一个新的
Action
。在 (2) 处,我使用
getWebApplicationContext()
方法获得一个
ApplicationContext
。为了获得业务服务,我使用在 (2) 处获得的环境在 (3) 处查找一个 Spring bean。
这种技术很简单并且易于理解。不幸的是,它将 Struts 动作与 Spring 框架耦合在一起。如果您想替换掉 Spring,那么您必须重写代码。并且,由于 Struts 动作不在 Spring 的控制之下,所以它不能获得 Spring AOP 的优势。当使用多重独立的 Spring 环境时,这种技术可能有用,但是在大多数情况下,这种方法不如另外两种方法合适。
2.
窍门 2. 覆盖 RequestProcessor
将 Spring 从 Struts 动作中分离是一个更巧妙的设计选择。分离的一种方法是使用
org.springframework.web.struts.DelegatingRequestProcessor
类来覆盖 Struts 的
RequestProcessor
处理程序,如清单 2 所示:
清单 2. 通过 Spring 的 DelegatingRequestProcessor 进行整合
<?xml version="1.0" encoding="ISO-8859-1" ?> |
我利用了
<controller>
标记来用
DelegatingRequestProcessor
覆盖默认的 Struts
RequestProcessor
。下一步是在我的 Spring 配置文件中注册该动作,如清单 3 所示:
清单 3. 在 Spring 配置文件中注册一个动作
<?xml version="1.0" encoding="UTF-8"?> |
注意:在 (1) 处,我使用名称属性注册了一个 bean,以匹配 struts-config 动作映射名称。
SearchSubmit
动作揭示了一个 JavaBean 属性,允许 Spring 在运行时填充属性,如清单 4 所示:
清单 4. 具有 JavaBean 属性的 Struts 动作
package ca.nexcel.books.actions; |
在清单 4 中,您可以了解到如何创建 Struts 动作。在 (1) 处,我创建了一个 JavaBean 属性。
DelegatingRequestProcessor
自动地配置这种属性。这种设计使 Struts 动作并不知道它正被 Spring 管理,并且使您能够利用 Sping 的动作管理框架的所有优点。由于您的 Struts 动作注意不到 Spring 的存在,所以您不需要重写您的 Struts 代码就可以使用其他控制反转容器来替换掉 Spring。
DelegatingRequestProcessor
方法的确比第一种方法好,但是仍然存在一些问题。如果您使用一个不同的
RequestProcessor
,则需要手动整合 Spring 的
DelegatingRequestProcessor
。添加的代码会造成维护的麻烦并且将来会降低您的应用程序的灵活性。此外,还有过一些使用一系列命令来代替 Struts
RequestProcessor
的传闻。 这种改变将会对这种解决方法的使用寿命造成负面的影响。
3.
<!-- 载入applicationContext上下文-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/*applicationContext*.xml</param-value>
</context-param>
第一种:使用 Spring 的 ActionSupport 类整合 Structs
继承spring的ActionSupport类
public class ShowDeptListAction extends ActionSupport {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
DeptManager deptManager = (DeptManager) getWebApplicationContext()
.getBean("deptManager");
List<Dept> list = deptManager.getAllDept();
request.setAttribute("list", list);
return mapping.findForward("ok");
}
}
这种方式看上去很直观,但有不利的一面,你的action类将直接使用spring特定的类(ActionSupport),这使Struts action 代码与spring紧密耦合!action也负责查找由spring管理的bean,违反了Ioc原则.
第二种:使用 Spring 的 DelegatingRequestProcessor 覆盖 Struts 的 RequestProcessor
在struts-config.xml 文件加入:
<controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor" />
在spring上下文配置文件中作为bean注册:
<beans>
<bean name="/showDeptList"
class="cn.com.thinkbank.struts.action.ShowDeptListAction">
<property name="deptManager" ref="deptManager" >
</property>
</bean>
</beans>
servlet代码类如下:
public class ShowDeptListAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
List<Dept> list = deptManager.getAllDept();
request.setAttribute("list", list);
return mapping.findForward("ok");
}
private DeptManager deptManager;
public void setDeptManager(DeptManager deptManager) {
this.deptManager = deptManager;
}
}
个人认为,此种方式好用些。
第三种:将 Struts Action 管理委托给 Spring 框架
在struts-config.xml 文件加入:
<action-mappings>
<action path="/showDeptList"
type="org.springframework.web.struts.DelegatingActionProxy">
<forward name="ok" path="/form/showDeptList.jsp"></forward>
</action>
</action-mappings>
在spring上下文配置文件中作为bean注册:
<bean name="/showDeptList"
class="cn.com.thinkbank.struts.action.ShowDeptListAction">
<property name="deptManager" ref="deptManager" >
</property>
</bean>
servlet代码类如下:
public class ShowDeptListAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
List<Dept> list = deptManager.getAllDept();
request.setAttribute("list", list);
return mapping.findForward("ok");
}
private DeptManager deptManager;
public void setDeptManager(DeptManager deptManager) {
this.deptManager = deptManager;
}
}
这种方式看上去不直观,因为struts所有的ation都映射到了同一个动作类(org.springframework.web.struts.DelegatingActionProxy)!
窍门 3. 将动作管理委托给 Spring 一个更好的解决方法是将 Strut 动作管理委托给 Spring。您可以通过在 清单 5 中的 清单 5. Spring 整合的委托方法
清单 5 是一个典型的 struts-config.xml 文件,只有一个小小的差别。它注册 Spring 代理类的名称,而不是声明动作的类名,如(1)处所示。DelegatingActionProxy 类使用动作映射名称查找 Spring 环境中的动作。这就是我们使用 将一个 Struts 动作注册为一个 Spring bean 是非常直观的,如清单 6 所示。我利用动作映射使用
动作委托的优点 动作委托解决方法是这三种方法中最好的。Struts 动作不了解 Spring,不对代码作任何改变就可用于非 Spring 应用程序中。 动作委托的优点不止如此。一旦让 Spring 控制您的 Struts 动作,您就可以使用 Spring 给动作补充更强的活力。例如,没有 Spring 的话,所有的 Struts 动作都必须是线程安全的。如果您设置 |