Sunday, July 1, 2012

Spring : SimpleFormController Example

Before understanding SimpleFormController you must understand its Spring bean lifecycle. Below diagram tries to explain you the flow of SimpleFormController. 

  • Whenever a request comes from browser it checks in deployment descriptor (i.e Web.xml) for its servlet and url mapping. 
  • Then request goes to its corresponding dispatcher-servlet.xml, The DispatcherServlet consults the HandlerMapping and invokes the Controller associated with the request in our case its SimpleFormController.
  • The Controller process the request by calling the appropriate service methods i.e isFormSubmitted(). Here you can write your own logic of a form being submitted or not. Usually if a request object is empty its a first time request and it returns false. 
  • formBackingObject() method will be called regardless of form is submitted or not however formBackingObject() method will return FormBean Object to formView when form is not submitted and ModelAndView Object to successView when form is submitted. 
  • Then request goes to a ViewResolver to find the actual View to invoke. The View with the help of the FormBean or ModelAndView will render the result back to the user.



Lets create a webproject in My Eclipse (lets say SpringFormController). Now we will add spring Capabilities to it. Here we are using Spring 2.5


(Right click on project) -> My Eclipse -> Add Spring Capabilities..

Adding below libraries (as shown in below image)
  • Spring 2.5 Core Libraries
  • Spring 2.5 Web Libraries





Now lets modify Web.xml. Adding dispatcher servlet (lets say javaxp)


web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
      xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <servlet>
            <description>Spring MVC Dispatcher Servlet</description>
            <servlet-name>javaxp</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
      </servlet>
     
      <servlet-mapping>
            <servlet-name>javaxp</servlet-name>
            <url-pattern>*.do</url-pattern>
      </servlet-mapping>
     
</web-app>


Now creating dispatcher-servlet in our case (javaxp-servlet.xml) it will reside where the web.xml is present. It defines a view resolver, a FormBean and a FormController. Here FormBean will be used to do dependency injection in our FormController. Also note how the FormController is defined it requires Command Name and Command Class in our case Command Class is FormBean which we will define in next step. Also we need to define form view and success view as shown below.

javaxp-servlet.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"
      xmlns:p="http://www.springframework.org/schema/p"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

      <bean id="viewResolver" class=" org.springframework.web.servlet.view.InternalResourceViewResolver" >
      <property name="prefix">
            <value>/WEB-INF/jsp/</value>
      </property>
      <property name="suffix">
            <value>.jsp</value>
      </property>
      </bean>
     
      <bean id="fb" class="com.javaxp.bean.FormBean" autowire="byName">
      </bean>
     
      <bean name="/fc.do" class="com.javaxp.controller.FormController" autowire="byName">
            <property name="commandName" value="formBean"></property>
            <property name="commandClass" value="com.javaxp.bean.FormBean"></property>
            <property name="formView" value="formPage"></property>
            <property name="successView" value="submitPage"></property>
      </bean>
     
</beans>


Now lets create a FormBean.java and formPage.jsp. FormBean.java will contain all the corresponding elements from formPage.jsp. As FormBean is our Command class it will implicitly map all the corresponding elements from formPage.jsp

FormBean.java

/* com.javaxp.bean.FormBean.java  */


package com.javaxp.bean;

public class FormBean {
     
      private String userName;
      private String password;
      private String gender;
      private String city;
      private String aboutYou;
      private String[] community;
     
      public String getUserName() {
            return userName;
      }
      public void setUserName(String userName) {
            this.userName = userName;
      }
      public String getPassword() {
            return password;
      }
      public void setPassword(String password) {
            this.password = password;
      }
      public String getGender() {
            return gender;
      }
      public void setGender(String gender) {
            this.gender = gender;
      }
      public String getCity() {
            return city;
      }
      public void setCity(String city) {
            this.city = city;
      }
      public String getAboutYou() {
            return aboutYou;
      }
      public void setAboutYou(String aboutYou) {
            this.aboutYou = aboutYou;
      }
      public String[] getCommunity() {
            return community;
      }
      public void setCommunity(String[] community) {
            this.community = community;
      }
}


formPage.jsp, as the name suggest it is our Form which is rendered using JSTL form tag. Note you can do this without JSTL but as you are using Spring Controller its better to use all the feature which spring provides. JSTL is used to write less code and concentrate more on business logic.

formPage.jsp

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
 <head>
  <title> Form Page </title>
 </head>
 <body>
      <h2> Form Page </h2>
      <form:form commandName="formBean">
            <table border="1" width="100%">
            <tr>
                  <td>User name : </td>
                  <td><form:input path="userName"/></td>
            </tr>
            <tr>
                  <td>Password : </td>
                  <td><form:password path="password"/></td>
            </tr>
            <tr>
                  <td>Gender : </td>
                  <td>
                        <form:radiobutton path="gender" value="M" label="M"/>
                        <form:radiobutton path="gender" value="F" label="F"/>
                  </td>
            </tr>
            <tr>
                  <td>City : </td>
                  <td>
                        <form:select path="city">
                              <form:option value="CHENNAI" label="Chennai"/>
                              <form:option value="DELHI" label="Delhi"/>
                              <form:option value="KOLKATA" label="Kolkata"/>
                              <form:option value="MUMBAI" label="Mumbai"/>                                                        
                        </form:select>
                  </td>
            </tr>
            <tr>
                  <td>About you : </td>
                  <td><form:textarea path="aboutYou"/></td>
            </tr>
            <tr>
                  <td>Community : </td>
                  <td>
                        <form:checkbox path="community" value="C" label="C"/>
                        <form:checkbox path="community" value="CPLUS" label="C++"/>
                        <form:checkbox path="community" value="JAVA" label="Java"/>
                        <form:checkbox path="community" value="DOTNET" label=".Net"/>
                  </td>
            </tr>
            <tr>
                  <td colspan="2" align="center"><input type="submit" value="Submit Form"/></td>
            </tr>
            </table>   
      </form:form>
 </body>
</html>


Now we will create the FormController.java. It will contains all the methods which we discussed in Spring bean life-cycles.

FormController.java

/* com.javaxp.controller.FormController.java */


package com.javaxp.controller;

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

import org.springframework.ui.ModelMap;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

import com.javaxp.bean.FormBean;

public class FormController extends SimpleFormController {
     
      private FormBean fb;
     
      public void setFb(FormBean fb) {
            this.fb = fb;
      }
     
      protected boolean isFormSubmission(HttpServletRequest request) {
           
            boolean isFormSubmitted = !request.getParameterMap().isEmpty();
           
            System.out.println("Inside FormController >> isFormSubmission() >> "+isFormSubmitted);
           
            return isFormSubmitted;
      }
     
      protected Object formBackingObject(HttpServletRequest request) throws Exception {
           
            System.out.println("Inside FormController >> formBackingObject()");
           
            return fb;
      }
     
      protected ModelAndView onSubmit(HttpServletRequest request,
                  HttpServletResponse response, Object command, BindException errors)
                  throws Exception {
           
            System.out.println("Inside FormController >> onSubmit()");
           
            System.out.println(fb.getUserName());
            System.out.println(fb.getPassword());
            System.out.println(fb.getGender());
            System.out.println(fb.getCity());
            System.out.println(fb.getAboutYou());
            System.out.println(fb.getCommunity());
           
           
            ModelMap map = new ModelMap();
            map.put("fb", fb);
           
            return new ModelAndView(this.getSuccessView(),map);
      }
}


Also creating a submitPage.jsp. Its just used to create successView which will render the results.

submitPage.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Success Page</title>
</head>
<body>
<h2> User Details </h2>
  <table  border="1" width="100%">
  <tr>
      <td>User Name : </td>
      <td>${fb.userName}</td>
  </tr>
  <tr>
      <td>Gender : </td>
      <td>${fb.gender}</td>
  </tr>
  <tr>
      <td>City : </td>
      <td>${fb.city}</td>
  </tr>
  <tr>
      <td>About You : </td>
      <td>${fb.aboutYou}</td>
  </tr>
  <tr>
      <td>Community : </td>
      <td>
            <c:forEach items="${fb.community}" var="communityList">
                  ${communityList},
            </c:forEach>
      </td>
  </tr>
  </table>
</body>
</html>


Lets see the files structure created so far


Output

Now got to http://localhost:8080/SpringFormController/fc.do and you should see below screen. Note /fc.do which is your controller mapping in dispatcher-servlet.


Fill in the form and submit it.