21 - Spring MVC Framework

21.1 Overview

MVC  stands for Model, View and Controller and it is a design pattern. This pattern divides the application into three components  to separate the internal representation of information from the way it is being presented to the user. The three components are:

  • Model (M): Models responsibility is to manage application's data, business logic and business rules.
  • View (V): A view is an output representation of information, such as displaying information or reports to the user either as a text form or as charts.
  • Controller(C): Controller responsibility is to invoke Models to perform business logic and then update the view based on the model’s output.

21.2 Spring MVC Architecture and Flow

The main component of Spring MVC is Dispatcher Servlet. Refer below diagram to understand the Spring MVC architecture 

                                    

 

                               Fig - Spring MVC architecture

  1. Dispatcher Servlet is configured in web.xml of the application and all the Request mapped to this servlet will be handled by Dispatcher servlet. Dispatcher Servlet delegates the request to the controller (class annotated with @Controller annotation)
  2. The controller class invokes appropriate handler method based on @RequestMapping annotation. The handler method returns the logical name of the view and the model.
  3. Dispatcher servlets resolve the actual view name using View Resolver (configured in the beans configuration file) and gets the actual view name.
  4. Passes the model object to view so can be used by view to display the result to the user.

21.3 MVC Configuration

a) Configure Dispatcher Servlet

To configure the dispatcher servlet we need to add below configuration in web.xml of our application      

 <web-app id="WebApp_ID" version="2.4"
      xmlns="http://java.sun.com/xml/ns/j2ee" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
      http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
      <servlet>
         <servlet-name>SpringWebMVC</servlet-name>
         <servlet-class>
             org.springframework.web.servlet.DispatcherServlet
         </servlet-class>
         <load-on-startup>1</load-on-startup>
      </servlet>

      <servlet-mapping>
         <servlet-name>SpringWebMVC</servlet-name>
         <url-pattern>/</url-pattern>
      </servlet-mapping>
</web-app>

 Above servlet configuration is similar to configuring custom servlets.

b) Application context files

By default Dispatcher Servlets loads the application context from file [servlet-name]-servlet.xml from  WEB-INF directory where [servlet-name] is the name of servlet with which dispatcher servlet is configured. For above configuration, dispatcher servlet will load SpringWebMVC-servlet. Xml file from WEB-INF. This application context will be specific to dispatcher servlet only.

c) Configure additional Application Context

Spring MVC allows us to configure additional application context files using ContextLoaderListener and a context param with name contextConfigLocation in web.xml file Configuring just ContextLoaderListener by default loads file name applicationContext.xml from WEB-INF directory.

For example 

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationcontext1.xml</param-value>
</context-param>
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

Above configuration will load /WEB-INF/applocationcontext1.xml file along with applicationConetxt.xml.

Files loaded by ContextLoaderListener are loaded at a Root level so available to all Dispatcher Servlets 

Note : ContextLoaderListener loads the specified beans configuration files in Root  application context hence available to all the dispatcher servlets where as the file loaded by dispatcher servlets is specific to Dispatcher servlet and will refer the ones as parent loaded by context loader listener. Files loaded by Dispatcher servlets  will not shared across dispatcher servlets. Files loaded by Context Loader Listener  
We can use <import> tag to import external configuration

21.4 Activate Spring MVC Annotation scanning

 We need to activate Spring MVC annotation scanning in web application so that classes marked with annotations gets scanned. To do so we need to add below statement in the beans configuration file.

       <context:component-scan base-package="com.spring.mvc.tutorial" />
Base-package attribute specifies the source package that will be scanned

21.5 Configure View Resolver

There are several implementations of view resolver available which actually maps the view names to actual view. Some of the implementations are InternalResourceViewResolver, XmlViewResolver, ResourceBundleViewResolver etc.

The InternalResourceViewResolver maps the jsp and html files in the WebContent/WEB-INF/ folder. We can configure prefix or suffix attributes to the view name to generate the final view page URL

To configure InternalResourceViewResolver, add the following to the beans configuration file

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
</bean>


21.6 MVC Annotations

a) @Controller  -

This annotation is used to define controllers. Any class annotated with @Controller annotation becomes controller and gets registered automatically once auto scan is enabled. 

b) @Request Mapping -

This annotation is used to map the Request URLl to the handler methods and can be applied at a class level or at a method level.

Defining @RequestMapping at a class level will map the URL pattern to controller class and can be defined to map different URLs to  handler methods.

@RequestMapping annotation allows to map the URL based on request method types as well. For example, below snippet will map the POST request coming for /indexed Url

@RequestMapping(value = "/index", method = RequestMethod.POST)

Default value of method attribute is GET.

c)  @ModelAttribute –  

Model attribute annotation is used 
At a method argument level to grab submitted data in 
public void handle(@ModelAttribute(“/data” Student)
 {
  }
At method level to provide reference data to the form             

21.7 Spring Web Application Set up

In this section we will discuss how to create a web application using eclipse. We can create it manually as well

21.7.1 To create a new  project go to . 

File ->  New -> Project -> Web -> Dynamic Web Project ->Next (refer below)

              Fig - Create a new Project

Once you click Next, new window will open (refer below)

             Fig - give a project name

  •  Project Name –Give it a name. This will be the name of your web application. In above figure, web application with name “SpringWebMVC” will be created
  •  "Target Runtime", choose "Apache Tomcat v7.0"
  •  Leave rest all as default values .Click Finish

Once done , a new project with name “SpringWebMVC” will be created (refer below figure)

              

               

Details-

  1. All java code including comtrollers will be created under src folder
  2. All static contents and jsp will be created under WebContent

To create a War file,  Right Click on Project -> Export -> War File

                Fig create a WAR file

Clicking on War file, a new window will be opened (refer below). Choose a Destination as the webapps folder of your tomcat installation directory. 

              Fig - Choose folder destination

Note- You can select any destination folder and eclipse will create a SpringWebMVC.war file at the selected location. However, each server has its own directory from where it deploys the war file.

In case of tomcat “webapps” directory is the deployment directory and for any web application to be deployed on tomcat, it has to be placed in webapps.

21.7.2 Add Spring Jar files in build path.

Now is the time to add the jar files of Spring and commons-logging we downloaded in Chapter 3 (section 3.6) in the java project.

Copy the below jar files and paste in WebContent\WEB-INF\lib folder

  1. commons-logging-1.2.jar
  2. spring-beans-4.1.1.RELEASE.jar
  3. spring-context-4.1.1.RELEASE.jar
  4. spring-context-support-4.1.1.RELEASE.jar
  5. spring-core-4.1.1.RELEASE.jar
  6. spring-expression-4.1.1.RELEASE.jar   
  7. spring-web-4.1.1.RELEASE.jar
  8. spring-webmvc-4.1.1.RELEASE.jar
  9. spring-aop-4.1.1.RELEASE.jar

    

          Fig - SpringWebMVC created

21.7.3   Create web.xml       

<?xml version="1.0" encoding="UTF-8"?>
     <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xmlns="http://java.sun.com/xml/ns/javaee" 
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
              http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
              <display-name>Spring Web MVC Tutorial</display-name>
             <servlet>
                <servlet-name>SpringWebMVC</servlet-name>
                <servlet-class>
                      org.springframework.web.servlet.DispatcherServlet
                </servlet-class>
                    <load-on-startup>1</load-on-startup>
            </servlet>

           <servlet-mapping>
                 <servlet-name>SpringWebMVC</servlet-name>
                 <url-pattern>/</url-pattern>
           </servlet-mapping>
    </web-app> 

21.7.4   Create SpringWebMVC-servlet.xml to configure view resolver and activate auto scan .

Create a SpringWebMVC.xml with below content in WEB-INF directory. Below configuration will look for jsp files from WEB-INF/jsp directory
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="ttp://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.xsd">

      <context:component-scan base-package="com.spring.web.mvc.tutorial" />

      <bean    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
          <property name="prefix" value="/WEB-INF/jsp/" />
         <property name="suffix" value=".jsp" />
      </bean>
</beans>

21.8   Display Welcome Message MVC Example

Let's create our first MVC application which will display different Greeting message for different URL

Use the application created in section 21.7 ( refer Web application , web.xml and SpringWebMVC-servlet.xml)) 

a)  Create HelloWorldController.java file  annotated with @Controller annotation which will define two handler methods. sayHello() method will  be mapped to /hello URL and
     sayHi() method will be mapped to /greeting URL. 

b)  @RequestMapping annotation does not have any method attribute defined so these method will be executed for GET requests only

c)  Model argument is an optional argument and is required if we want to send some data back to JSP.  Model class defines one addAttribute() method which takes key value pair
     and can be used to send data to JSP

d)  Method return type can be String or void. In case the return type is String , a logical view name will be returned which will be resolved using InternalResourceViewResolver configured in                                    springWebMvC-servlet.xml file.

e)  If return type is void then URL will be considered as the logical view name. so if we mapped sayHi() method with “/greeting” URL and return type is void then it will consider “greeting” as logical name

f)   InternalResourveViewResolver defines prefix as WEB-INF/jsp and suffix as .jsp which means prefix and suffix will be applied to the logical view name to get actual view name . “welcome”  logical                     view name will be resolved as “WEB-INF/jsp/welcome.jsp”

g)  Returned data can be displayed on jsp using {<<model-key>>}

package com.spring.web.mvc.tutorial;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloWorldController {

    @RequestMapping("/hello")
    public String sayHello(Model model)
    {
        model.addAttribute("welcomeMessage", "Hello user  !!");
        return "welcome";
    }

    @RequestMapping("/greeting")
    public void sayHi(Model model)
    {
       model.addAttribute("welcomeMessage", "Hi User !!");
    }
}

h.  Create welcome.jsp 

<html>
 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title> </title>
 </head>
 <body>
   <strong>
      ${welcomeMessage}
   </strong>
 </body>
</html>

i. Create greeting.jsp

<html>
  <head>
     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
     <title> </title>
  </head>
  <body>
    <strong>
      ${welcomeMessage}
    </strong>
  </body>
</html>

j.  Hit the Url http://localhost:8080/SpringWebMVC/hello

                Figure - Hello User

k. Create greeting.jsp

            Fig - Hi User

 

21.9  Form Processing

Form processing is used in almost every web application. In this section we will discuss how to develop a form based application with the help of a user registration example.

Use the application created in section 21.7 ( refer Web application , web.xml and SpringWebMVC-servlet.xml)

a)  Reference data may be needed to display the form . For example, in a user registration from we need to display the list of countries in the dropdown. To do so we can  create     a list of countries and set in model object and send it back to the input form jsp file. This is similar to what we did in section 21.8.  b)  We would need to create a model object (User class) in our case and send it back to jsp using model attribute  c)  Define a method to handle the Post request using @RequestMapping(method=  RequestMethod.POST). To grab the input data, define an argument @ModelAttributr of type User .Also     to display the data on confirmation screen, we will use the same approach and will set the data in model so we will add another argument of type Model

d)  User.java

package com.spring.web.mvc.tutorial;

public class User {

       private String name;
       private String contactNumber;
       private String  country;
       public String getName() {
            return name;
       }
       public void setName(String name){
        this.name = name;
       }
       public String getContactNumber(){
        return contactNumber;
       }
       public void setContactNumber(String contactNumber){
           this.contactNumber = contactNumber;
       }
       public String getCountry(){
           return country;
       }
       public void setCountry(String country){
           this.country = country;
       }
}

e.  UserRegistrationController.java

package com.spring.web.mvc.tutorial;

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class UserRegistrationController {
   @RequestMapping("/register")
    public String setForm(Model model)
    {
        Map<String,String> country = new HashMap<String,String>();
        country.put("India","India");
        country.put("United States","United States");
        country.put("United Kingdom","United Kingdom");

        model.addAttribute("country", country);

        User user = new User();
        model.addAttribute("user", user);
        return "inputForm";
    }

    @RequestMapping(value = "/register" ,method = RequestMethod.POST)
    public String submit(@ModelAttribute("user") User user , Model model)
    {

         String name = user.getName();
         String contactNumber = user.getContactNumber();
         String country = user.getCountry();

         model.addAttribute("name",name);
         model.addAttribute("contactNumber",contactNumber);

         model.addAttribute("country",country);

        return "confirmationScreen";  
    }
}

f. inputForm.jsp

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
    <title>Form Handling</title>
</head>
 <body>
     <h2>Enter Your Information</h2>
   <form:form method="POST" action="register" modelAttribute="user"> 
     <table>
       <tr>
          <td><form:label path="name">Name</form:label></td>
          <td><form:input path="name" /></td>
       </tr>
       <tr>
          <td><form:label path="contactNumber">Contact Number</form:label></td>
          <td><form:input path="contactNumber" /></td>
       </tr>
       <tr>
          <td><form:label path="name">Name</form:label></td>
          <td><form:select path = "country" items="${country}" /></td>
        </tr>
        <tr>
           <td colspan="2">
              <input type="submit" value="Submit"/>
           </td>
        </tr>
     </table>  
  </form:form>
 </body>
</html>

g.  confrmationScreen.jsp

<html>
<head>
    <title> Form Handling</title>
</head>
 <body>
    <h2>Submitted Data </h2>
   <table>
      <tr>
         <td>Name</td>
         <td>${name}</td>
      </tr>
      <tr>
         <td>Contact Number</td>
         <td>${contactNumber}</td>
      </tr>
      <tr>
        <td>Country</td>
        <td>${country}</td>
      </tr>
   </table>  
  </body>
</html>

h.  Access Application using http://localhost:8080/SpringWebMVC/register

                          Fig - form to enter information

      

      Enter data and submit

                    Fig - Enter your data

 

                     Fig - submitted Data

   

21.10  Interceptors

In this section we will discuss how to intercept the request using Spring Interceptor. Spring provides a interface “HandleInterceptor’ with three methods

    a)  preHandle() – this method gets executed before the request is handled by handler method.

    b)  postHandle()this method gets executed after the request is handled by handler method.

    c)  afterCompletion() – this method getes executed after the view has been rendered.

We need to configure the Interceptor implementation in beans configuration file and need to enable it the list of interceptors of      

     org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

In this application we will add message in  preHandle() method  ,postHandle() method  and in controller and will display all three at the jsp.

Use the application created in section 21.7 ( refer Web application and web.xml)

a) SayHelloController.java

package com.spring.web.mvc.tutorial;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class SayHelloController {
     @RequestMapping("/hello")
     public String sayHello(HttpServletRequest requst , Model model)
     {
        String messageFromInterceptor= (String)requst.getAttribute("preHandleMessage");
 
        model.addAttribute("preHandleMessage", messageFromInterceptor);
        model.addAttribute("controllerMessage", "Message From Controller");

        return "welcome";
     }
}

b) MessageInterceptor.java

package com.spring.web.mvc.tutorial;

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

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MessageInterceptor implements HandlerInterceptor {
 
      @Override
      public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response , Object handler, Exception exception )
            throws Exception {
      }
      @Override
      public void postHandle(HttpServletRequest request, HttpServletResponse response,
         Object handler, ModelAndView modelAndView) throws Exception 
      {
        modelAndView.addObject("postHandleMessage", "Message From Post Handle Method");
      }
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) 
                throws Exception 
      {
           String message = "Message from Pre Handle Method";
           request.setAttribute("preHandleMessage", message);
           return true;
      }
}

c. SpringWebMVC-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.spring.web.mvc.tutorial" />
    <bean id="messageInterceptor"
        class="com.spring.web.mvc.tutorial.MessageInterceptor" />
        <bean
           class="org.springframework.web.servlet.view.InternalResourceViewResolver">
           <property name="prefix" value="/WEB-INF/jsp/" />
           <property name="suffix" value=".jsp" />
        </bean>
        <bean
            class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
            <property name="order" value="1"/>
               <property name="interceptors">
              <list>
                <ref bean="messageInterceptor" />
              </list>
           </property>
       </bean>
   </beans>

d) welcome.jsp

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title> </title>
  </head>
  <body>
    <strong>
        Pre Handler message :: ${preHandleMessage}
       <br/>
       <strong>
           Controller message :: ${controllerMessage}
       </strong>
       <br/>
       <strong>
         Post Handler message :: ${postHandleMessage}
        </strong>
     </strong>
  </body>
</html>

e.  Access URL with  http://localhost:8080/SpringWebMVC/hello

             

     

21.11 SpringExceptionResolver - Mapping Exception to Views

Whenever we get an exception in our application we usually gets stack trace and it gets displayed to the end users as well which is actually a very bad experience for the users using our application.
To overcome this , Spring comes with SpringExceptionResolver  mechanism which provides a way to configure the pages which get displayed based on the type of exceptions 

We need to define the SpringExceptionResolver  in beans configuration file similar to below snippet.

<bean class="org.springframework.web.servlet.handler.
  SimpleMappingExceptionResolver">
  <property name="exceptionMappings">
     <props>
        <prop key= "NoDataException">
          dataNotAvailable
        </prop>
     </props>
  </property>
  <property name="defaultErrorView" value="error"/>
</bean>

We can define multiple error pages configuration as a key value pair where the qualified class path of exception is the key and value is the page name which will be resolved by ViewResolver.

In the above example, when NoDataException occurs, dataNotAvailable view will be displayed. For all other exceptions, view with name “error” will be displayed. 

We will can get the exception details using {exception} tag as it gets populated by Spring 

Use the application created in section 21.7 ( refer Web application , web.xml )

Let's create an example.

a) NoDataException.java

package com.spring.web.mvc.tutorial;
public class NoDataException extends RuntimeException {

    private String message;

    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

b. GetDataController

package com.spring.web.mvc.tutorial;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class GetDataController {
    @RequestMapping("/getData")
    public String getData(HttpServletRequest requst , Model model)
    {        
        NoDataException exception = new NoDataException(); 
        exception.setMessage("Error Occured while Fetching Data !!");
        throw exception;
    }    
}

c. SpringWebMVC-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.spring.web.mvc.tutorial" />

    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
           <property name="exceptionMappings">
              <props>
                 <prop key="com.spring.web.mvc.tutorial.NoDataException">
                     dataNotAvailable
                  </prop>
              </props>
          </property>
          <property name="defaultErrorView" value="error"/>
        </bean>
</beans>

d.  dataNotAvailable.jsp

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
      <title> </title>
   </head>
  <body>
    <strong>
      ${exception.message}
    </strong>
  </body>
</html>

 

e.  Access application using http://localhost:8080/SpringWebMVC/getData

         Fig - Error while fetching data

Like us on Facebook