Monday, 5 August 2013

Struts to Spring mvc migration

Hi Friends,

Now I will share you step by step approach to migrate application from Struts 1.2 to Spring 3 using annotations.In struts to spring migration libraries, action classes, config files and jsp's will get changed as explained below :


STEP 1 : Replace struts libraries with spring libraries.


First step while migrating from struts to spring is replace your struts related libraries with spring libraries in lib folder. I have mentioned basic libraries of both stuts and spring for your clarification.

Struts basic libraries :
     1. struts.jar
     2. struts-legacy.jar
     etc.. 

Spring basic libraries :
     1. standard.jar
     2. org.springframework.asm-3.0.1.RELEASE-A.jar
     3. org.springframework.beans-3.0.1.RELEASE-A.jar
     4. org.springframework.context-3.0.1.RELEASE-A.jar
     5. org.springframework.core-3.0.1.RELEASE-A.jar
     6. org.springframework.expression-3.0.1.RELEASE-A.jar
     7. org.springframework.web.servlet-3.0.1.RELEASE-A.jar
     8. org.springframework.web-3.0.1.RELEASE-A.jar
     etc..

About *.tld's used in struts application, many tutorials on web says that it will remain same. Which makes me little unconfortable, as we are having some tld's which are solely used by struts. So we need to replace those struts tlds also. Following are the possible tld's which are need to be removed :

 <taglib>

<taglib-uri>tiles</taglib-uri>
<taglib-location>/WEB-INF/taglib/struts-tiles-1.1.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>nested</taglib-uri>
<taglib-location>/WEB-INF/taglib/struts-nested-1.1.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>logic</taglib-uri>
<taglib-location>/WEB-INF/taglib/struts-logic-1.1.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>html</taglib-uri>
<taglib-location>/WEB-INF/taglib/struts-html-1.1.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>bean</taglib-uri>
<taglib-location>/WEB-INF/taglib/struts-bean-1.1.tld</taglib-location>
</taglib>

We need to change tld's with spring tags, which I will explain in upcoming step for jsp.


STEP 2 : Change in web.xml file for struts to spring migration


In this step, we are going to change intializing of struts config file with spring's confing file.

In Struts :
  We initialize config for struts in following way, which need to be replace :

<servlet>
        <servlet-name>action</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>
        <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>


In Spring :
   We initialize config for spring in following way :

   <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

 

STEP 3 : Replace config files for struts to spring migration


Now it comes the replacement of config files from struts to spring.
In Struts :
   We use struts-confing.xml as config file for dispatching request.
<struts-config>
    <form-beans>
        <form-bean name="LoginForm"
            type="xyz.struts.helloworld.form.LoginForm" />
    </form-beans>
  
    <global-exceptions>
    </global-exceptions>
    <global-forwards></global-forwards>
  
    <action-mappings>
        <action path="/login" name="LoginForm" validate="true" input="/index.jsp" 
            type="xyz.struts.helloworld.action.LoginAction">
            <forward name="success" path="/welcome.jsp" />
            <forward name="failure" path="/index.jsp" />
        </action>
    </action-mappings>
    <message-resources parameter="resource.MessageResource"></message-resources>
</struts-config>
In Spring :
   We will use spring-servlet.xml. Here name for confign is generated as [servlet-name]-servlet.xml. And servlet-name is mentioned in web.xm, here we have used spring.
 <context:component-scan
        base-package="xyz.spring3.controller" />
          
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>
 Here, <context:component-scan> tag is used, so that spring will load all the components from given package i.e. "xyz.spring3.controller"
We can use different view resolvers, here I have used UrlBasedViewResolver. In which prefix and suffix are used to resolve the view by prefixing and suffixing values to the object returned by ModelAndView in action class.

 

STEP 4 : JSP changes for struts to spring migration


While migrating application from struts to spring, we need many changes in Jsp's. Which include tags replacement, tld's replacement and some other things as explained below :

1. tld replacement :

As I said earlier in step 1, we need to remove tld's of struts. So following entries in jsp's will be removed :

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %>

Replace these with following spring taglib's :

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>

We have removed taglib declarations. Now it's time for replacing its tags according to spring or normal html standards, as below :
                        STRUTS
                   SPRING (corresponding tag)
 <html:html>
<html> 
 <html:form>
<form:form> 
 <html:error>
<form:errors> 
 <html:text property="abc">
 <form:input path="abc">
<html:select property="abc">
      <option value="one">
<form:select path="abc">
     <option value="one">
<html:submit>
<input type="submit"> 
 <bean:message bundle="resource" key="abc">
<spring:message code="abc"> 
<html:checkbox property="abc">
<form:checkbox path="abc">
These are the mostly used tags. The list will go on...

Now next is the calling action from jsp. For this, we need to change form tag as below :

In Struts :

<html:form action="/addStudent" method="post">

In Spring :

<form:form method="POST" commandName="studentForm" name="studentForm" action="addStudent.do">


Here commandName is going to map with corresponding formbean for that jsp. Next we will see, how action is getting called with spring 3 annotations.  (Remeber that we have removed struts-config.xml, so we don't have any mapping against action mention here)



STEP 5 : Action class changes for struts to spring migration


 Now following changes need to be done in action classes for struts to spring migration using annotations :


Struts action
Spring action
(corresponding replacement)
extends Action
@controller annotation above class declaration
public ActionForward execute(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
               throws Exception {
@RequestMapping("/addStudent.do")
@RequestMapping(method = { RequestMethod.GET, RequestMethod.POST })

public ModelAndView execute (HttpServletRequest request,
  HttpServletResponse response,
 @Valid @ModelAttribute("studentForm")        studentForm studentForm,
  BindingResult bindingResult)
throws Exception {

Here, in @RequestMapping annotation, action is getting mapped to corresponding action mentioned in jsp.
And in @ModelAttribute annotation, form is getting mapped which should be same as that of mentioned in commandName in jsp.
forward = mapping.findForward(“success”);
modelMap.put("studentForm",   studentForm);
return (new ModelAndView(“success”, modelMap));



Imports tobe added in Spring application :

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

 

STEP 6 : Validation changes for struts to spring migration

Step 6-1 : Changes in jsp

In Struts :
We add following line for instantiating actionErrors :
<%
 ActionErrors actionErrors = (ActionErrors)request.getAttribute("org.apache.struts.action.ERROR");
%>
This line will get removed in Spring application.
In Struts we use following tag for displaying error message :
<html:errors bundle="resource"/>
In Spring :
In Spring we use following tag for displaying error message :

<form:errors path="*" cssClass="error" />  
Here, in cssClass 'error', you can define css properties for error messages to display.

 Step 6-1 : Changes in Action class

In Struts :
Method signature as :
public ActionForward execute(
  ActionMapping mapping,
  ActionForm form,
  HttpServletRequest request,
  HttpServletResponse response)
  throws Exception {
For capturing errors :
   ActionErrors errors = new ActionErrors();
  ActionForward forward = new ActionForward();
   errors.add("name", new ActionMessage("id"));
In Spring :
Add following imports :
        import javax.validation.Valid; 
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.validation.BindingResult;
Create one instance of your formbean and aurowire it, as follow:
  public StudentForm studentFormValidator;
 @Autowired
 public void setStudentFormValidator(
   StudentForm studentFormValidator) {
  this.studentFormValidator = studentFormValidator;
 }
Method signature :
public ModelAndView execute(
   HttpServletRequest request,
   HttpServletResponse response,
   @Valid @ModelAttribute("StudentForm") StudentForm studentForm,
   BindingResult result) throws Exception {
For capturing errors, call a validate method at the start of business logic as :
 studentFormValidator.validate(studentForm, result, request);
Here, we need to create one validate method in form bean :
public void validate(Object object, Errors errors, HttpServletRequest request) {
--
if(condition){
 ---
}else{
errors.reject("error.fail"); 
}
Note : considering messages are stoared in applicationResources.properties
Here, we will get result of validation in 'result' parameter.
Now, you can proceed for business logic as :
if (!result.hasErrors()) {
--
//business logic goes here
--
}else{
forward = "failure";
modelMap.put("studentForm", studentForm);
return (new ModelAndView(“failure”, modelMap));
}
And and here we done with basic migration. Hope it will help you.

8 comments:

  1. Thanks for sharing such useful information :)
    We will surely use this approach... !!!

    ReplyDelete
  2. Helpful post, please post your thoughts on a replacement for Structs ActionMessage when used to display success messages.

    ReplyDelete
  3. can anybody tell how to convert the bean tags and html:link tags to spring

    ReplyDelete
  4. It’s a nice blog posted by you. I was seeking for this type of blog that have a fresh and interesting content.

    Java spring developers

    ReplyDelete