"contextConfigLocation"value="/WEB-INF/beans.xml"/>
前面已经提到过,在下载部分,你能够找到这三个完全可使用的例子的完整源代码。
每个例子都为一个书籍搜索应用程序提供一种不同的Struts和Spring的整合方法。
你可以在这里看到例子的要点,但是你也可以下载应用程序以查看所有的细节。
窍门1.使用Spring的ActionSupport
手动创建一个Spring环境是一种整合Struts和Spring的最直观的方式。
为了使它变得更简单,Spring提供了一些帮助。
为了方便地获得Spring环境,org.springframework.web.struts.ActionSupport类提供了一个getWebApplicationContext()方法。
你所做的只是从Spring的ActionSupport而不是StrutsAction类扩展你的动作,如清单1所示:
清单1.使用ActionSupport整合Struts
packageca.nexcel.books.actions;
importjava.io.IOException;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.apache.struts.action.ActionError;
importorg.apache.struts.action.ActionErrors;
importorg.apache.struts.action.ActionForm;
importorg.apache.struts.action.ActionForward;
importorg.apache.struts.action.ActionMapping;
importorg.apache.struts.action.DynaActionForm;
importorg.springframework.context.ApplicationContext;
importorg.springframework.web.struts.ActionSupport;
importca.nexcel.books.beans.Book;
importca.nexcel.books.business.BookService;
publicclassSearchSubmitextendsActionSupport{|
(1)
publicActionForwardexecute(
ActionMappingmapping,
ActionFormform,
HttpServletRequestrequest,
HttpServletResponseresponse)
throwsIOException,ServletException{
DynaActionFormsearchForm=(DynaActionForm)form;
Stringisbn=(String)searchForm.get("isbn");
//theoldfashionway
//BookServicebookService=newBookServiceImpl();
ApplicationContextctx=
getWebApplicationContext();|
(2)
BookServicebookService=
(BookService)ctx.getBean("bookService");|(3)
Bookbook=bookService.read(isbn.trim());
if(null==book){
ActionErrorserrors=newActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,newActionError
("message.notfound"));
saveErrors(request,errors);
returnmapping.findForward("failure");
}
request.setAttribute("book",book);
returnmapping.findForward("success");
}
}
让我们快速思考一下这里到底发生了什么。
在
(1)处,我通过从Spring的ActionSupport类而不是Struts的Action类进行扩展,创建了一个新的Action。
在
(2)处,我使用getWebApplicationContext()方法获得一个ApplicationContext。
为了获得业务服务,我使用在
(2)处获得的环境在(3)处查找一个Springbean。
这种技术很简单并且易于理解。
不幸的是,它将Struts动作与Spring框架耦合在一起。
如果你想替换掉Spring,那么你必须重写代码。
并且,由于Struts动作不在Spring的控制之下,所以它不能获得SpringAOP的优势。
当使用多重独立的Spring环境时,这种技术可能有用,但是在大多数情况下,这种方法不如另外两种方法合适。
窍门2.覆盖RequestProcessor
将Spring从Struts动作中分离是一个更巧妙的设计选择。
分离的一种方法是使用org.springframework.web.struts.DelegatingRequestProcessor类来覆盖Struts的RequestProcessor处理程序,如清单2所示:
清单2.通过Spring的DelegatingRequestProcessor进行整合
xmlversion="1.0"encoding="ISO-8859-1"?
>
DOCTYPEstruts-configPUBLIC
"-//ApacheSoftwareFoundation//DTDStrutsConfiguration1.1//EN"
"http:
//jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
type="org.apache.struts.validator.DynaValidatorForm">
type="ca.nexcel.books.actions.SearchSubmit"
input="/searchEntry.do"
validate="true"
name="searchForm">
DelegatingRequestProcessor"/>|
(1)
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
我利用了标记来用DelegatingRequestProcessor覆盖默认的StrutsRequestProcessor。
下一步是在我的Spring配置文件中注册该动作,如清单3所示:
清单3.在Spring配置文件中注册一个动作
xmlversion="1.0"encoding="UTF-8"?
>
DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN"
"http:
//www.springframework.org/dtd/spring-beans.dtd">
class="ca.nexcel.books.actions.SearchSubmit">|
(1)
注意:
在
(1)处,我使用名称属性注册了一个bean,以匹配struts-config动作映射名称。
SearchSubmit动作揭示了一个JavaBean属性,允许Spring在运行时填充属性,如清单4所示:
清单4.具有JavaBean属性的Struts动作
packageca.nexcel.books.actions;
importjava.io.IOException;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.apache.struts.action.Action;
importorg.apache.struts.action.ActionError;
importorg.apache.struts.action.ActionErrors;
importorg.apache.struts.action.ActionForm;
importorg.apache.struts.action.ActionForward;
importorg.apache.struts.action.ActionMapping;
importorg.apache.struts.action.DynaActionForm;
importca.nexcel.books.beans.Book;
importca.nexcel.books.business.BookService;
publicclassSearchSubmitextendsAction{
privateBookServicebookService;
publicBookServicegetBookService(){
returnbookService;
}
publicvoidsetBookService(BookServicebookService){|
(1)
this.bookService=bookService;
}
publicActionForwardexecute(
ActionMappingmapping,
ActionFormform,
HttpServletRequestrequest,
HttpServletResponseresponse)
throwsIOException,ServletException{
DynaActionFormsearchForm=(DynaActionForm)form;
Stringisbn=(String)searchForm.get("isbn");
Bookbook=getBookService().read(isbn.trim());|
(2)
if(null==book){
ActionErrorserrors=newActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,newActionError("message.notfound"));
saveErrors(request,errors);
returnmapping.findForward("failure");
}
request.setAttribute("book",book);
returnmapping.findForward("success");
}
}
在清单4中,你可以了解到如何创建Struts动作。
在
(1)处,我创建了一个JavaBean属性。
DelegatingRequestProcessor自动地配置这种属性。
这种设计使Struts动作并不知道它正被Spring管理,并且使你能够利用Sping的动作管理框架的所有优点。
由于你的Struts动作注意不到Spring的存在,所以你不需要重写你的Struts代码就可以使用其他控制反转容器来替换掉Spring。
DelegatingRequestProcessor方法的确比第一种方法好,但是仍然存在一些问题。
如果你使用一个不同的RequestProcessor,则需要手动整合Spring的DelegatingRequestProcessor。
添加的代码会造成维护的麻烦并且将来会降低你的应用程序的灵活性。
此外,还有过一些使用一系列命令来代替StrutsRequestProcessor的传闻。
这种改变将会对这种解决方法的使用寿命造成负面的影响。
窍门3.将动作管理委托给Spring
一个更好的解决方法是将Struts动作管理委托给Spring。
你可以通过在struts-config动作映射中注册一个代理来实现。
代理负责在Spring环境中查找Struts动作。
由于动作在Spring的控制之下,所以它可以填充动作的JavaBean属性,并为应用诸如Spring的AOP拦截器之类的特性带来了可能。
清单5中的Action类与清单4中的相同。
但是struts-config有一些不同:
清单5.Spring整合的委托方法
xmlversion="1.0"encoding="ISO-8859-1"?
>
DOCTYPEstruts-configPUBLIC
"-//ApacheSoftwareFoundation//DTDStrutsConfiguration1.1//EN"
"http:
//jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
type="org.apache.struts.validator.DynaValidatorForm">