Integration using ActionSupport
Integrating Struts with Spring doesn’t sound to be easy but if you follow this method you will find it quite simple and to add to this Spring provides you with org.springframework.web.struts.ActionSupport class. This class provides a method getWebApplicationContext() which you can use to obtain the Spring context. So you just have to extend Spring’s ActionSupport from your strut’s actions.
Using ActionSupport to integrate Struts
package net.champ.example1.actions;
Explanation:
The trick here is to extend your Action from the Spring ActionSupport and not from the Struts Action class. The Spring ActionSupport provides you with the method getWebApplicationContext() to obtain an ApplicationContext and from the ApplicationContext you can access the business service layer.
Disadvantages:
This method involves changes in the java files of your application, which is not desirable because if you want to move your application back to Struts framework you will have to redo the changes in the java files. And in this method the Struts actions are not in complete control of Spring.
Using ContextLoaderPlugin provided with Spring
ContextLoaderPlugin is provided with Spring's 1.0.1 release. This plug-in loads the Spring application context for Strut's applications ActionServlet.There are two methods of integrating Struts with Spring using this plug-in and these two methods are:
• A) Overriding the Struts RequestProcessor with Spring’s DelegatingRequestProcessor.
• B) Delegate Struts Action management to the Spring framework.
To use the ContextLoaderPlugin loads the Spring context file for the Struts ActionServlet. To use this plug-in you have to add following to your struts config file:
The default location for the Context config file is /WEB-INF/actionname-servlet.xml.
A) Overriding the Struts RequestProcessor with Spring’s DelegatingRequestProcessor.
One way of using ContextLoaderPlugIn is to override the Struts RequestProcessor with Spring’s DelegatingRequestProcessor class. The Spring's DelegatingRequestProcessor will lookup the Struts Actions defined in ContextLoaderPlugIn's WebApplicationContext. You can either use a single ContexLoaderPlugIn for all your Struts modules and then load the context in all your Struts modules or you can also define seperate ContextLoaderPlugIn for each of your Struts modules and then use the contextConfigLocation parameter to load the appropriate XML file.
Let us have a look at it.
Integration via Spring's DelegatingRequestProcessor
Explanation:
Here we have overridden the Struts RequestProcessor with Spring’s DelegatingRequestProcessor using the controller tag. Now our Spring's DelegatingRequestProcessor will lookup the Struts Actions so we need to register the action in our Spring config file as shown below:
Explanation:
This part is same as registering the Spring beans but here we register Struts actions as Spring's beans, the names of the beans must be same as in struts config file. This will allow Spring to populate our beans at the run time.
Explanation:
Now here we are using Struts action but the beans are managed by Spring. In the above code we create a javaBean which is populated by Spring and then use it to run our business logic.
Disadvantages:
This method is definitely better then the previous one but still here the Spring beans are dependent on the RequestProcessor, this reduces the flexibility of the application.
B) Delegate Struts Action management to the Spring framework.
A much better solution is to delegate Struts action management to the Spring framework. You can do this by registering a proxy in the struts-config action mapping. The proxy is responsible for looking up the Struts action in the Spring context. Because the action is under Spring's control, it populates the action's JavaBean properties and leaves the door open to applying features such as Spring's AOP interceptors.
The delegation method of Spring integration
Explaination:
This is simply a struts config file, but here we do not declare the action’s class name but we set the Spring’s DelegatingActionProxy. The DelegatingActionProxy will lookup context for the action name in the spring’s config and map it to its class. The context is declared in the ContextLoaderPlugIn.
Now just register the Struts action as a bean in the Spring config file. The properties for this action’s bean will be automatically populated just like any other Spring bean.
Register a Struts action in the Spring context
Disadvantages:
If you have the option to choose a method then this is the best method the only disadvantage here is this method leaves your code less readable because the dependencies are not clear.
Integrating Struts with Spring doesn’t sound to be easy but if you follow this method you will find it quite simple and to add to this Spring provides you with org.springframework.web.struts.ActionSupport class. This class provides a method getWebApplicationContext() which you can use to obtain the Spring context. So you just have to extend Spring’s ActionSupport from your strut’s actions.
Using ActionSupport to integrate Struts
package net.champ.example1.actions;
import java.io.IOException;
import javax.servlet.*;
import org.apache.struts.action.*;
import org.springframework.context.ApplicationContext;
import org.springframework.web.struts.ActionSupport;
import net.champ.example1.beans.Employee;
import net.champ.example1.business.EmpSearchService;
public class SubmitSearch extends ActionSupport {
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
DynaActionForm searchEmpForm = (DynaActionForm) form;
String empId = (String) searchEmpForm.get("empId");
ApplicationContext ctx = getWebApplicationContext();
EmpSearchService empSearchService = EmpSearchService) ctx.getBean("EmpSearchSercvice");
Employee employee = empSearchService.find(empId.trim());
if (null == employee) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.empnotfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}
request.setAttribute("employee", employee);
return mapping.findForward("success");
}
}
Explanation:
The trick here is to extend your Action from the Spring ActionSupport and not from the Struts Action class. The Spring ActionSupport provides you with the method getWebApplicationContext() to obtain an ApplicationContext and from the ApplicationContext you can access the business service layer.
ApplicationContext ctx = getWebApplicationContext();
//getWebApplicationContext provided by the Spring ActionSupport class
EmpSearchService empSearchService = (EmpSearchService) ctx.getBean("EmpSearchSercvice");
// From the ApplicationContext get the business service bean
Disadvantages:
This method involves changes in the java files of your application, which is not desirable because if you want to move your application back to Struts framework you will have to redo the changes in the java files. And in this method the Struts actions are not in complete control of Spring.
Using ContextLoaderPlugin provided with Spring
ContextLoaderPlugin is provided with Spring's 1.0.1 release. This plug-in loads the Spring application context for Strut's applications ActionServlet.There are two methods of integrating Struts with Spring using this plug-in and these two methods are:
• A) Overriding the Struts RequestProcessor with Spring’s DelegatingRequestProcessor.
• B) Delegate Struts Action management to the Spring framework.
To use the ContextLoaderPlugin loads the Spring context file for the Struts ActionServlet. To use this plug-in you have to add following to your struts config file:
<plug-in classname="org.springframework.web.struts.ContextLoaderPlugIn">
The location of the context config file can be set through contextConfigLocation property.
<plug-in classname="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/actionname-servlet.xml">
</set-property>
The default location for the Context config file is /WEB-INF/actionname-servlet.xml.
A) Overriding the Struts RequestProcessor with Spring’s DelegatingRequestProcessor.
One way of using ContextLoaderPlugIn is to override the Struts RequestProcessor with Spring’s DelegatingRequestProcessor class. The Spring's DelegatingRequestProcessor will lookup the Struts Actions defined in ContextLoaderPlugIn's WebApplicationContext. You can either use a single ContexLoaderPlugIn for all your Struts modules and then load the context in all your Struts modules or you can also define seperate ContextLoaderPlugIn for each of your Struts modules and then use the contextConfigLocation parameter to load the appropriate XML file.
Let us have a look at it.
Integration via Spring's DelegatingRequestProcessor
<struts-config>
<form-beans>
<form-bean name="searchEmpForm" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="empId" type="java.lang.String">
</form-property>
</form-bean>
<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome” path=">
<forward name="searchEmployee" path="/searchEmp.do">
<forward name="submitSearch" path="/submitSearch.do">
</forward>
<action-mappings>
<action path="/welcome" forward="/WEB-INF/views/welcome.htm">
<action path="/searchEmployee" forward="/WEB-INF/views/search.jsp">
<action path="/submitSearch" type="net.champ.example1.books.actions.SubmitSearch" input="/searchEmployee.do" validate="true" name="searchEmpForm">
<forward name="success" path="/WEB-INF/views/empDetail.jsp">
<forward name="failure" path="/WEB-INF/views/search.jsp">
</forward>
</forward>
<message-resources parameter="ApplicationResources">
<controller processorclass="org.springframework.web.struts.DelegatingRequestProcessor">
<plug-in classname="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml">
</set-property>
<plug-in classname="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="csntextConfigLocation" value="/WEB-INF/beans.xml">
</set-property>
</plug-in>
</struts-config>
Explanation:
Here we have overridden the Struts RequestProcessor with Spring’s DelegatingRequestProcessor using the controller tag. Now our Spring's DelegatingRequestProcessor will lookup the Struts Actions so we need to register the action in our Spring config file as shown below:
<beans>
<bean id="empSearchService" class="net.champ.example1.employee.business.EmpSearchImpl">
<bean name="/submitSearch" class="net.champ.example1.employee.actions.SubmitSearch">
<property name="empSearchService">
<ref bean="empSearchService">
</ref>
</property>
</bean>
</beans>
Explanation:
This part is same as registering the Spring beans but here we register Struts actions as Spring's beans, the names of the beans must be same as in struts config file. This will allow Spring to populate our beans at the run time.
Package net.champ.example1.employee.actions;
import java.io.IOException;
import javax.servlet.*;
import org.apache.struts.action.*;
import net.champ.example1.employee.beans.Employee;
import net.champ.example1.employee.business.EmpSearchService;
public class SubmitSearch extends Action {
private EmpSearchService empSearchService;
public EmpSearchService getEmpSearchService () {
return empSearchService;
}
public void setEmpSearchService(EmpSearchService empSearchService) {
this.empSearchService = empSearchService;
}
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
DynaActionForm searchEmpForm = (DynaActionForm) form;
String empId = (String) searchEmpForm.get("empId");
Employee employee = getEmpSearchService().find(empId.trim());
if (null == employee) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}
request.setAttribute("employee", employee);
return mapping.findForward("success");
}
}
Explanation:
Now here we are using Struts action but the beans are managed by Spring. In the above code we create a javaBean which is populated by Spring and then use it to run our business logic.
Disadvantages:
This method is definitely better then the previous one but still here the Spring beans are dependent on the RequestProcessor, this reduces the flexibility of the application.
B) Delegate Struts Action management to the Spring framework.
A much better solution is to delegate Struts action management to the Spring framework. You can do this by registering a proxy in the struts-config action mapping. The proxy is responsible for looking up the Struts action in the Spring context. Because the action is under Spring's control, it populates the action's JavaBean properties and leaves the door open to applying features such as Spring's AOP interceptors.
The delegation method of Spring integration
<struts-config>
<form-beans>
<form-bean name="searchEmpForm" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="empId" type="java.lang.String">
</form-property>
</form-bean>
<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome” path=">
<forward name="searchEmployee" path="/searchEmp.do">
<forward name="submitSearch" path="/submitSearch.do">
</forward>
<action-mappings>
<action path="/welcome" forward="/WEB-INF/views/welcome.htm">
<action path="/searchEmployee" forward="/WEB-INF/views/search.jsp">
<action path="/submitSearch" type="org.springframework.web.struts.DelegatingActionProxy" input="/searchEmployee.do" validate="true" name="searchEmpForm">
<forward name="success" path="/WEB-INF/views/empDetail.jsp">
<forward name="failure" path="/WEB-INF/views/search.jsp">
</forward>
</forward>
<message-resources parameter="ApplicationResources">
<plug-in classname="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml">
</set-property>
<plug-in classname="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/beans.xml">
</set-property>
</plug-in>
</struts-config>
Explaination:
This is simply a struts config file, but here we do not declare the action’s class name but we set the Spring’s DelegatingActionProxy. The DelegatingActionProxy will lookup context for the action name in the spring’s config and map it to its class. The context is declared in the ContextLoaderPlugIn.
Now just register the Struts action as a bean in the Spring config file. The properties for this action’s bean will be automatically populated just like any other Spring bean.
Register a Struts action in the Spring context
<beans>
<bean id="empSearchService" class="net.champ.example1.employee.business.EmpServiceImpl">
<bean name="/submitSearch" class="net.champ.example1.employee.actions.SubmitSearch">
<property name="empSearchService">
<ref bean="empSearchService">
</ref>
</property>
</bean>
</beans>
Disadvantages:
If you have the option to choose a method then this is the best method the only disadvantage here is this method leaves your code less readable because the dependencies are not clear.
Comments