Friday 10 October 2014

Spring MVC Tutorial

Preface

If you are reading this post you probably know already what is the Spring Framework - A pluggable software infrastructure that other software frameworks can be plugged to it, in order to extend the software services that your application includes.




What is Spring MVC?

It is a software framework for developing web applications, that can be plugged into the core Spring framework. It is based on the popular MVC design pattern:
  • Model - Represents the data model of an application (database, web-service, csv file, etc...)
  • View - Represents the UI of an application (JSPVelocityCSVHTML, XMLetc...)
  • Controller - Mainly controls the flow of the application:
    • Which view/page to display
    • How to display it
    • Prepare the model to display
    • Do some pre-rendering activities in order for the view/page to render correctly in the rendering engine (e.g. web-browser).
    • Etc... But actually, it can do much more. We will go over it in the following sections.






Leading example


We will display a list of articles to the user. Our view component will render the list as an HTML document, that can be viewed also as an XML document.






Spring MVC Application Components

A Spring MVC application is built from the following components:
  • Model - A data model that represents the business model
  • View - One or more View components (such as a JSP)
  • Controller - One or more Controllers
  • Configuration File - A Configuration File that wires different components of an application together, using XML or Java annotations.


Lets see a simple example on how to wire these components together.




Spring MVC Model


A Model is a collection of Java Objects that represents the data model of an application. in our example these are the objects that represent a list of articles. In Spring MVC we attach these java objects to a view by a controller. In the "Spring MVC Controller" section we explain how to do it.




Spring MVC View Component


We need to render an XML document the is created dynamically. So for our view component we choose to a JSP file (but we could choose any other view technology that can display dynamic content).

Lets see the code of the View element. We will than go over each line:

<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"   import="com.geekcap.geeknews.core.*,java.util.List"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html PUBLIC 
      "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Geek News</title>
    <link type="text/css" rel="stylesheet" href="css/geeknews.css" />
  </head>

  <body>
    <div id="mainContent">
      <p><a href="post.htm">Post</a></p>
      <c:forEach items="${articles}" var="article">
        <div class="article">
          <p>
            <a href="article.htm?id=<c:out value="${article.id}"/>">
              <c:out value="${article.title}" />
            </a> by 
            <span class="articleAuthor">
              <c:out value="${article.author}" />
            </span> on 
            <span class="articleDate">
              <fmt:formatDate value="${article.date}" type="both" />
            </span>
          </p>
          <p class="articleSummary">
            <c:out value="${article.summary}" />
          </p>
        </div>
      </c:forEach>
    </div>
  </body>
</html>





XML Header


<?xml version="1.0" encoding="UTF-8" ?>





Basic JSP Tags


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"   import="com.geekcap.geeknews.core.*,java.util.List"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>


    We start by declaring some basic JSP tags:
      • language
      • mime-type, charset (contentType)
      • imports
      • tag libraries




    Basic HTML Tags


    <!DOCTYPE html PUBLIC 
          "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Geek News</title>
        <link type="text/css" rel="stylesheet" href="css/geeknews.css" />
      </head>

      <body>
        <div id="mainContent">
          <p><a href="post.htm">Post</a></p>
          [...]
          [...]
          [...]
        </div>
      </body>
    </html>





    JSP Iteration Over the Articles


    We iterate over the articles that we get from the server and display each article:

        <c:forEach items="${articles}" var="article">
          <div class="article">
            <p>
              <a href="article.htm?id=<c:out value="${article.id}"/>">
                <c:out value="${article.title}" />
              </a> by 
              <span class="articleAuthor">
                <c:out value="${article.author}" />
              </span> on 
              <span class="articleDate">
                <fmt:formatDate value="${article.date}" type="both" />
              </span>
            </p>
            <p class="articleSummary">
              <c:out value="${article.summary}" />
            </p>
          </div>
        </c:forEach>



    • ${articles} - List of articles that we add to the View via the Controller





    Spring MVC Controller


    The Controller, as mentioned above, is responsible for the flow of the application. This means it is responsible for the:

    • Navigation - It is responsible to forward (See URL Forwarding) the clients to the View page (JSP in our example)
    • View components - It is responsible to prepare the components and variables that the view needs in order to be rendered correctly
    • Model - Preparation of the model as viewed by View component.

    Lets see the code of the Controller element:


    package com.geekcap.geeknews.web;

    import java.util.List;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.AbstractController;
    import com.geekcap.geeknews.core.GeekNewsService;
    import com.geekcap.geeknews.core.NewsArticle;

    /**
    * Prepare the model to display on the home page.
    */
    public class HomePageController extends AbstractController {

      // Provides access to the model business methods
      private GeekNewsService service;


      /**
      * Responsible for translating a web request into a ModelAndView object for presentation
      */
      @Override
      protected ModelAndView   handleRequestInternal(HttpServletRequest req, HttpServletResponse res) throws Exception {
        // load the articles list
        List<NewsArticle> articles = service.getArticleOverviews();
        // Send the articles to the "home" view
        return new ModelAndView( "home", "articles", articles );
      }

      /**
      * Injected by Spring
      * @param service
      */
      public void setGeekNewsService(GeekNewsService service) {
        this.service = service;
      }
    }







    Hook the class to the MVC Workflow


    We declare our Controller class. In order for our controller to participate in the Spring MVC Workflow, it has to implement the base controller interface: org.springframework.web.servlet.mvc.Controller.

    We choose to extend the org.springframework.web.servlet.mvc.AbstractController class, which is convenient superclass for controller implementations. This superclass uses the Template Method design pattern:

    /**
    * Prepare the model to display on the home page.
    */
    public class HomePageController extends AbstractController {






    Declare the Service


    We declare a service for the Model :

      // Provides access to the model business methods
      private GeekNewsService service;



    One of the responsibilities of the Controller is to prepare the Model data to be rendered in the View. In order to do so it needs access to the Model data. This is achieved by declaring a service which gives us access to the Model data. In our example we inject the service instance on the Spring configuration XML file. We will see that later on.




    Prepare the Model to be rendered on the View


    We prepare the Model data to be rendered on the View:

      /**
      * Responsible for translating a web request into a ModelAndView object for presentation
      */
      @Override
      protected ModelAndView   handleRequestInternal(HttpServletRequest req, HttpServletResponse res) throws Exception {
        // load the articles list
        List<NewsArticle> articles = service.getArticleOverviews();
        // Send the articles to the "home" view
        return new ModelAndView( "home", "articles", articles );
      }



    The AbstractController superclass  has a method that we need to override in order to define the work that our controller does. This method provides a simple servlet-like functionality.

    We override the handleRequestInternal() method, and on that method we:

    • load a list of articles from the Model

        // load the articles list
        List<NewsArticle> articles = service.getArticleOverviews();

    • Set  the list of articles in the "home" View

        // Send the articles to the "home" view
        return new ModelAndView( "home", "articles", articles );

    The handleRequestInternal() overridden method returns a ModelAndView instance that represent the View that should be rendered, and the Model that will be accessible from the View. We create a new ModelAndView instance with three parameters:
      • viewName - Tells the view resolver to show the page identified by "viewName" 
      • modelName - An identifier for the model that will be accessed from the view
      • modelObject - The model itself.




    Set the Service Instance


    We declare a bean-style method to set the service instance by a Spring XML configuration:

      /**
      * Injected by Spring
      * @param service
      */
      public void setGeekNewsService(GeekNewsService service) {
        this.service = service;
      }






    Binding MVC Components to Spring MVC Framework


    In order for the Spring MVC framework to go into action, we need to configure the servers and the components together. We show how to do it on a seperate to level section "Configuring the Spring MVC Components"




    Configuring the Spring MVC Components

    In order for the Spring MVC framework to go into action, we need to wire client URLs to a general purpose Spring Servlet (DispatcherServlet). We wire the Spring MVC Configuration by attaching the org.springframework.web.servlet.DispatcherServlet to URL requests coming from the client-side.




    Binding URLs to the Dispatcher Servlet


    All requests that match the specified URLs will be forwarded (see "URL Forwarding") by the DispatcherServlet to the Controller defined by the Spring Configuration. We wire it in the "web.xml" file:


    <servlet>
      <servlet-name>news</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
    </servlet>


    In the above code we declared the DispatcherServlet servlet, and gave it the name "news". Now lets map the "news" servlet to client URLs:


    <servlet-mapping>
      <servlet-name>news</servlet-name>
      <url-pattern>*.htm</url-pattern>
    </servlet-mapping> 

    Each request with the extension "htm" will  be handled by the DispatcherServlet.




    Spring MVC Configuration File


    Now we need to create a Configuration for the "newsservlet, so that the DispatcherServlet will know how to handle the request, or in other words, we need to define to the "newsservlet how to locate its Model, its View and its Controller




    Locating the configuration file


    By default, Spring MVC looks for an XML configuration file whose name starts with the servlet name followed by "-servlet.xml", and that is located in the "WEB-INF" directory (A special folder in the Java Deployment Archive for web applications [war file]). So, in our example the configuration file is "news-servlet.xml".




    Defining the MVC Mappings


    The XML configuration file contains:

    • Controller Mapping - Wiring the Controller to the Spring Framework and injecting to it the service that we use for retrieving the data model.
    • Handler Mapping - Maps the controller bean id to Spring MVC Framework. Spring MVC has several Handler Mappings. The mapping to our controller depends on the Handler Mapping implementation that we use. For example, we can use different handler mappings to map a controller to a request URL, to bean names, etcetera. We chose here to use SimpleUrlHandlerMapping.
    • View Resolver Mapping - Define how the handler mapping will locate the view that will render the response. Spring MVC has several View Resolvers. Locating the view depends on the View Resolver implementation that we use. For example, we can use different view resolver to map a handler mapping to a request URL, to bean names, etcetera. We chose here to use InternalResourceViewResolver


    Listing 2. news-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"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

      <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
          <props>
            <prop key="/home.htm">homePageController</prop>
          </props>
        </property>
      </bean>

      <bean id="homePageController" class="com.cap.news.web.HomePageController">
        <property name="newsService" ref="newsService" />
      </bean>

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




    Summary Workflow

    After a DispatcherServlet has received a request and has done its work to resolve localesthemes and suchlike, it then tries to resolve a Controller, using a HandlerMapping. When a Controller has been found to handle the request, the handleRequest method of the located Controller will be invoked; the located Controller is then responsible for handling the actual request and - if applicable - returning an appropriate ModelAndView. So actually, this method is the main entry-point for the DispatcherServlet which delegates requests to controllers. This method - and also this interface - should preferably not be implemented by custom controllers directly, since abstract controller also provided by this package already provide a lot of functionality for typical use cases in web applications. A few examples of those controllers: AbstractControllerAbstractCommandControllerSimpleFormController.

    So basically any direct implementation of the Controller interface just handles HttpServletRequests and should return a ModelAndView, to be further interpreted by the DispatcherServlet. Any additional functionality such as optional validation, form handling, etc should be obtained through extending one of the abstract controller classes mentioned above.