关于Spring , Struts结合学习。


一、前言


刚刚接触了日本一个项目,用的框架名称是Northland Framework,主要用到以下部分


iBATIS 、 Velocity 。 Struts 、 Spring 如何结合在一起?


二、 Spring 提供了三种整合 Struts 的方法:


使用 Spring 的 ActionSupport 类整合 Structs


使用 Spring 的 DelegatingRequestProcessor 覆盖 Struts 的 RequestProcessor


将 Struts Action 管理委托给 Spring 框架


( 参见 Get a better handle on Struts actions, with Spring

http://www-128.ibm.com/developerworks/java/library/j-sr2.html?ca=drs-tp4105

对应还有译文:

http:///modules/techresource/article504.htm?utm_campaign=searchengine&utm_source=baidu&utm_medium=jjpm&utm_term=Spring+Struts )

三、我只关心第三种整合方法:


这种方法通过 Spring 提供的两个和 Struts 相关类来实现: org.springframework.web.struts. DelegatingActionProxy , org.springframework.web.struts. ContextLoaderPlugIn 。


ContextLoaderPlugIn 实现 Struts 的 PlugIn 接口,只要在 struts-config.xml 中有如下配置:


 


<      action                path      =      "/searchSubmit"      >


type      =      "ca.nexcel.books.actions.DelegatingActionProxy"


                   input      =      "/"


                     validate      =      "true"


                     name      =      "searchForm"      >


                    <      forward       name      =      "success"       path      =      "/WEB-INF/pages/detail.jsp"      />


                    <      forward       name      =      "failure"       path      =      "/WEB-INF/pages/search.jsp"      />


</      action      >


<      plug-in       className      =      "org.springframework.web.struts.ContextLoaderPlugIn"      >


          <      set-property       property      =      "contextConfigLocation"       value      =      "/WEB-INF/beans.xml"      />


       </      plug-in      >

ActionServlet 装载的时候就可以顺便装载和 Spring 相关的 beans.xml ,和 beans.xml 中相关的一个东西叫做 WebApplicationContext , ( 在 Spring 里关键就是取得 WebApplicationContext ,取得这个也就可以用 Spring 管理业务 ) ,在 ContextLoaderPlugIn 中是这样保存 WebApplicationContext :


String attrName = getServletContextAttributeName();


getServletContext().setAttribute(attrName, wac);


再看 DelegatingActionProxy ,它继承于 Struts 的 Action ,以后 struts-config.xml 中所有的


Action-mapping 都要指向它,只是每个 Action-mapping 的 path 不同,将来也是用这个 path 来区分究竟需要执行 beans.xml 中的那个类。如下代码:


public ActionForward execute(){


                Action delegateAction = getDelegateAction(mapping);


                return delegateAction.execute(mapping, form, request, response);


        }

这里的 delegateAction 就是 beans.xml 中一个相关的类 (beans.xml 也要求类继承于 Struts 的 Action) 去看看怎么得到 delegateAction :


protected Action getDelegateAction(ActionMapping mapping) throws BeansException {


WebApplicationContext wac = getWebApplicationContext(getServlet(),


    mapping.getModuleConfig());


String beanName = determineActionBeanName(mapping);


return (Action) wac.getBean(beanName, Action.class);


}

 

是如何取得 WebApplicationContext 呢:


wac=(WebApplicationContext)actionServlet.getServletContext().getAttribute(        ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX);

 


SERVLET_CONTEXT_PREFIX 正是 前边提到的 ContextLoaderPlugIn 中 的 attrName 。


现在这个原理一目了然, ContextLoaderPlugIn 在 actionServlet 初始化过程中保存


起来留到后面供 DelegatingActionProxy 用。


 


四、在另一篇文章中提到在上面的方法中 OpenSessionInView Filter 不能用


 ( 参照 http://wyyhzc.itpub.net/) ,这个东西我也不熟悉,是不是有不少 Spring 的东西在这种方式中都不能用呢? 这就说到另一种取得 Spring WebApplicationContext 的方法:


在 web.xml 中配置 ContextLoaderListener :


<      context-param      >


          <      param-name      >      contextConfigLocation      </      param-name      >


          <      param-value      >


      /WEB-INF/beans.xml


          </      param-value      >


       </      context-param      >


       <      listener      >


<      listener-class      >      org.springframework.web.util.Log4jConfigListener      </      listener-class      >


       </      listener      >


       <      listener      >


<      listener-class      >      org.springframework.web.context.ContextLoaderListener      </      listener-class      >


       </      listener      >

对应的 beans.xml 和前边那个一样, Log4jConfigListener 先不用管,去查看相关文档。


Web 服务启动的时候,我们去看看 ContextLoaderListener 作了什么:


WebApplicationContext = createWebApplicationContext(servletContext, parent);


servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

同样是保存 WebApplicationContext ,但是 key 是 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE


 


怎么才能不用 ContextLoaderPlugIn 而只用 ContextLoaderListener ? 下面我修改


org.springframework.web.struts. DelegatingActionProxy 把它修改成


ca.nexcel.books.actions. DelegatingActionProxy 并且修改一下代码:


修改 getWebApplicationContext 方法


Return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet,


 moduleConfig);       换成下边方法

 

ServletContext sc = actionServlet.getServletContext();


WebApplicationContext wac = null;


wac = WebApplicationContextUtils.getWebApplicationContext(sc);


return wac;

并且在 struts-config.xml 中将 action 的 type 指向自己的


ca.nexcel.books.actions. DelegatingActionProxy , PlugIn 删除 web.xml 加上刚才提到的 Listener ,启动 tomcat 运行一切正常。


 


五、我把 northland 的配置文件贴出来。


Struts-config.xml      :


<      action-mappings      >


          <      action


              path      =      "/list"


              input      =      "/list.jsp"


              name      =      "_list"


              scope      =      "request"


              type      =      "jp.co.nec.hnes.northland.web.struts.FlowAction"


              >


            <      display-name      >      一覧画面      </      display-name      >


          </      action      >


          <      action


              path      =      "/register"


              input      =      "/register.jsp"


              name      =      "_register"


              scope      =      "request"


              type      =      "jp.co.nec.hnes.northland.web.struts.FlowAction"


              >


            <      display-name      >      登録画面      </      display-name      >


          </      action      >

 

Web.xml:


       <      context-param      >


          <      param-name      >      contextConfigLocation      </      param-name      >


          <      param-value      >


      classpath:flowConfig.xml,


      classpath:viewConfig.xml,


      classpath:applicationContext.xml,


     classpath:applicationContext-extra.xml


          </      param-value      >


       </      context-param      >       


<      listener      >


<      listener-class      >      org.springframework.web.util.Log4jConfigListener      </      listener-class      >


       </      listener      >


       <      listener      >


<      listener-class      >      org.springframework.web.context.ContextLoaderListener      </      listener-class      >


       </      listener      >


       <      servlet      >


          <      servlet-name      >      ActionServlet      </      servlet-name      >


<      servlet-class      >      org.apache.struts.action.ActionServlet      </      servlet-class      >


          <      init-param      >


            <      param-name      >      config      </      param-name      >


            <      param-value      >      /WEB-INF/struts-config.xml      </      param-value      >


          </      init-param      >


       </      servlet      >

 


从中可以看到


其中的 jp.co.nec.hnes.northland.web.struts.FlowAction 和


ca.nexcel.books.actions. DelegatingActionProxy 的功能差不多。