上一节介绍了struts单独植入系统的一种使用方式,以及WebApplicationContext在Servlet容器中初始化的原理,一般的Web应用就可以轻松的使用了。

         但是,随着Struts的广泛应用,把Struts和Spring整合起来,是一个需要面对的问题。Spring本身也提供了Struts的相关类,主要使用的有org.springframework.web.struts.ActionSupport,我们只要把自己的Action继承自ActionSupport,就是可以调用ActionSupport中getWebApplicationContext()的方法取出WebApplicationContext。

         但这样一来在Action中,跟上一节、一样,需要取得业务逻辑的地方都要getBean,代码看上去不够简洁。所以Spring又提供了另一个方法:用spring来管理struts的action,使用org.springframework.web.struts.ContextLoaderPlugIn插件,该插件在struts启动时加载,这样对于我们的action,就可以像管理bean一样来管理。

以下只展示改动的代码,原代码参考spring与hibernate的集成   spring与struts1集成方案(一)

struts-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">

<struts-config>
  <form-beans />
  <global-exceptions />
  <global-forwards />
  
  <action-mappings>
    <!-- 使用DelegatingActionProxy将strut的action全权委托给spring容器管理。
    	DelegatingActionProxy是Action的子类,它把调用请求转交给真正的Action实现
    	-->
  	<action path="/person/list" type="org.springframework.web.struts.DelegatingActionProxy"
  	 validate="false" parameter="method">
  	 	<!-- jsp部署在WEB-INF下,防止用户直接访问jsp -->
  		<forward name="list" path="/WEB-INF/person/list.jsp"></forward>
  	</action>
  </action-mappings>
  
  <!-- 国际化 -->
  <message-resources parameter="struts.ApplicationResources" />
  
  <!-- 将struts的action托管给spring容器管理
  	根据contextConfigLocation的配置文件加载ActionServlet -->
  <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
  	<set-property property="contextConfigLocation"
  		value="/WEB-INF/action-servlet-person.xml"/>
  </plug-in>
  
</struts-config>
action-servlet-person.xml

<?xml version="1.0" encoding="UTF-8"?>
<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-3.0.xsd" 
	default-lazy-init="true">
	<!--此处配置的class是真实Action类的路径 
		不能使用id命名,id不能包含特殊字符 
	 -->
	<bean name="/person/list" class="com.ch.action.PersonAction">
		<property name="personService" ref="personService" />
	</bean>
</beans>
PersonAction
package com.ch.action;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import org.springframework.orm.hibernate3.support.OpenSessionInViewFilter;
import org.springframework.web.context.ContextLoader;

import com.ch.dao.IPersonService;
import com.ch.entity.Person;
/**
 * 通常在设计中往往会要求同一个Action来处理客户端发出的不同请求,
 * 所以使用DispatchAction类很好的解决了这类问题,通过设置parameter来配置传递不同的请求方法 
 * @author ch
 *
 */
public class PersonAction extends DispatchAction {

	private IPersonService personService;
	
	@Override
	protected ActionForward unspecified(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// TODO Auto-generated method stub
		return list(mapping, form, request, response);
	}
	
	@SuppressWarnings("unchecked")
	public ActionForward list(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		// TODO Auto-generated method stub
		List<?> list = (List<Person>)personService.findAllPersons();
		request.setAttribute("list", list);
		return mapping.findForward("list");
	}

	public void setPersonService(IPersonService personService) {
		this.personService = personService;
	}
}
部署运行结果:


其他整合方式:

1、使用spring的org.springframework.web.struts.ActionSupport (或者DispatchActionSupport):

Spring 的ActionSupport 继承至 org.apache.struts.action.Action。 ActionSupport的子类可以获得 WebApplicationContext类型的全局变量。通过getWebApplicationContext()可以获得这个变量,继而获取bean对象。

public class PersonAction extends org.springframework.web.struts.ActionSupport {

	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		// TODO Auto-generated method stub
		WebApplicationContext wc = getWebApplicationContext();
		IPersonService personService = (IPersonService)wc.getBean("personService");
		List<?> list = (List<Person>)personService.findAllPersons();
		
		request.setAttribute("list", list);
		return mapping.findForward("list");
	}
}

2、采用 DelegatingRequestProcessor将处理转发给Spring容器中的bean:

struts-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">

<struts-config>
  <form-beans />
  <global-exceptions />
  <global-forwards />
  
  <action-mappings>
    <!-- 使用DelegatingActionProxy将strut的action全权委托给spring容器管理。
    	DelegatingActionProxy是Action的子类,它把调用请求转交给真正的Action实现
    	-->
  	<action path="/person/list"
  	 validate="false" parameter="method">
  	 	<!-- jsp部署在WEB-INF下,防止用户直接访问jsp -->
  		<forward name="list" path="/WEB-INF/person/list.jsp"></forward>
  	</action>
  </action-mappings>
  
  <controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor" />
  
  <!-- 国际化 -->
  <message-resources parameter="struts.ApplicationResources" />
  
  <!-- 将struts的action托管给spring容器管理
  	根据contextConfigLocation的配置文件加载ActionServlet -->
  <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
  	<set-property property="contextConfigLocation"
  		value="/WEB-INF/action-servlet-person.xml"/>
  </plug-in>
  
</struts-config>
        配置controller processorClass为DelegatingRequestProcessor( 继承自RequestProcessor)后,就是告诉 Struts用DelegatingRequestProcessor来代替原来的RequestProcessor,Struts会将拦截到的用户请求转发给spring Context下的相应bean,根据bean的name属性来匹配。而Struts的Action配置无需配置type属性(即使配置了type属性也无作用,除非在spring的配置文件中找不到对应的name属性bean)。
3、可以将action- servlet-person.xml中的配置bean移植到applicationContext.xml中,通过ContextLoaderListener来加载这些bean。这样配置的话可以将Struts配置文件中的下列代码去掉:

<!-- 将struts的action托管给spring容器管理
  	根据contextConfigLocation的配置文件加载ActionServlet -->
  <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
  	<set-property property="contextConfigLocation"
  		value="/WEB-INF/action-servlet-person.xml"/>
  </plug-in>
实际上ContextLoaderListener和ContextLoaderPlugIn的功能是重叠的,他们都是进行Spring配置的初始化工作的。区别是ContextLoaderListener与ContextLoaderPlugIn加载的bean不在同一个WebApplicationContext中,这在使用OpenSessionInView Filter模式时应注意这一点(具体内容会在下次介绍)。

总结

  • Struts与Spring的集成方式有三种:使用Spring 的 ActionSupport使用Spring 的 DelegatingRequestProcessor 类全权委托
  • 第一种方式ActionSupport集成了Struts的Action,使得struts和spring耦合在一起,并且编码量(每次都要getWebApplicationContext和getBean)比较多,代码不够简洁;第二种方式和第三种方式类似,Action 的创建和对象的依赖注入全部由IOC容器来完成。第二种方式RequestProcessor类已经被代理 如果要再实现自己的实现方式(如:编码处理)就比较麻烦;所以优先使用第三种方式。
  • Struts与Spring的集成的后两种应用了Spring IOC来管理Struts的Action,顾名思义,两者即是在代理某对象。熟释Struts的必然知晓RequestProcessor和Action,Spring就在这两处切入到页面层的请求链中(通过扩展Struts中的RequestProcessor、Action类),以便将截获的请求传入到Spring管理的Action实例中,从而实现页面层到服务层的有效衔接。


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐