Spring MVC

java

Articles
Videos

Basic setup
Web JARs
Init Binder

REST
AOP
i18n
Form, Form Validation, and View
Expression Language

Exception handling
Testing
JDBC
Session
Annotations
Hibernate

Caching
Security

Basic concepts
Dependency Injection
Services
Batch

Boot
Tutorial
Other
Spring Technologies

http://www.journaldev.com/2610/spring-mvc-internationalization-i18n-and-localization-l10n-example

How can we debug our Spring-related XML files?

// Add Dispatcher Servlet to src/main/webapp/WEB-INF/web.xml:
<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>springDispatcher</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/GWL.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springDispatcher</servlet-name>
        <url-pattern>/spring-mvc/*</url-pattern>
    </servlet-mapping>
</web-app>

In the above code, we gave the dispatcher servlet a name "springDispatcher", 
and we map the URL pattern /spring-mvc/* to be handled by this springDispatcher 
servlet.  We also specified the name of the "application context" configuration
file as /WEB-INF/GWL.xml

// Create the "application context" configuration file src/main/webapp/WEB-INF/GWL.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="com.companyName" />
    <mvc:annotation-driven />
</beans>

// Add the view resolver to the "application context" configuration file:
<bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/WEB-INF/views/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

This should be added to the "application context" configuration file, just above
the context:component-scan directive.

What are the major features in different version of Spring?

  1. Spring 2.5 made annotation-driven configuration possible
  2. Spring 3.0 made great use of the Java 5 improvements
  3. Spring 4.0 is the first version to fully support Java 8 features. Spring 4.0 support Java EE 7 specification. To use Spring 4.0, you need at least Java 6.

What are the major features in Spring 4?

  1. @RestController annotation is introduced

How is Spring's Singleton bean different from Gang of Four Singleton pattern?

GoF defines Singleton as having one and only one instance per ClassLoader. However, Spring singleton is defined as one instance of bean definition per container.

How can we represent stateful bean in Spring?

Stateful beans are represented in Spring with a prototype scope. A new instance is created every time a request for the bean is made. For example:

<bean id="state" class="com.foo.SomeState" scope="prototype"/>

What are the core components of Spring MVC?

Spring MVC uses Front Controller Pattern -> Dispatcher Servlet. The Dispatcher Servlet direct the request to the appropriate other controllers based on the URL, and the annotation specified in the controllers. These other controllers will decide whether to return the response body for the request or route it to a JSP (view) or another servlet to handle the request / response. Other components:

  1. Component scan
  2. @Service and @Autowired for dependency injection
  3. ModelMap: Spring MVC also has something call a "model map", which is a way for controller to pass data to the view.
  4. The "application context" configuration file.
  5. Form and data binding using the command / model object.
  6. InitBinder: consistently format a field or a class
  7. Internationalization
  8. @RestController
  9. Web JARs
  10. View Resolver: ( org.springframework.web.servlet.view.InternalResourceViewResolver ), configured inside the application context configuration file, with the prefix of /WEB-INF/views/ and the suffix of jsp. This allows the controller method to return just a short string containing just the name of the JSP file, and omitting the prefix and suffix.

What are the overall steps to create a project that use Spring MVC?

  1. Install Eclipse
  2. Install Maven
  3. Use the m2eclipse plugin to create a project using the webapp archetype
    1. Launch Eclipse
    2. Click on File -> New -> Project
    3. Type "maven" into the "type to filter" text box
    4. Click on "Maven Project"
    5. Click Next
    6. Select or unselect appropriate check box
    7. Click Next
    8. Select the "webapp" archetype
    9. Click Next
  4. Add Spring MVC as a dependency (see below)
  5. Add the Dispatcher Servlet to web.xml file (see below)
  6. Create the Spring Application Context by adding the “application context” xml file (see below)

How can we add Spring MVC as a dependency?

  1. Double click on the pom.xml in Eclipse
  2. Click on the pom.xml tab
  3. Edit the pom.xml file to look like:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>testspringmvc</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>testspringmvc Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
          <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
  <groupId>org.apache.tomcat.maven</groupId>
  <artifactId>tomcat7-maven-plugin</artifactId>
  <version>2.2</version>
  <type>maven-plugin</type>
</dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.2.2.RELEASE</version>
        </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>testspringmvc</finalName>
  </build>
</project>

How can we add the Dispatcher Servlet to web.xml file?

When we create the maven project using the webapp archetype, it creates the web.xml under src/main/webapp/WEB-INF. Open this file and modify it like:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>springDispatcher</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/todo-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>springDispatcher</servlet-name>
    <url-pattern>/spring-mvc/*</url-pattern>
</servlet-mapping>
</web-app>

In the above code, we gave the dispatcher servlet a name "springDispatcher", and we map the URL pattern /spring-mvc/* to be handled by this springDispatcher servlet. This servlet also require additional configuration via a "application context" configuration file. See below.

How can we create the Spring "Application Context" configuration file?

From the step above, we gave the "application context" configuration file a name "todo-servlet.xml". To add this file:

  1. Go to src/main/webapp in Eclipse
  2. Right click on the WEB-INF folder
  3. Select New -> File -> Other
  4. Type xml into the "type to filter" text box
  5. Click Next
  6. Give it a name (todo-servlet.xml)
  7. Click Finish
  8. Modify the todo-servlet.xml to look like:
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="com.companyName" />
    <mvc:annotation-driven />
</beans>

How can we add a new server to Eclipse?

We can right click anywhere in the Servers view and select "New -> Server", or we can do it from "File -> New -> Other" and type "server" into the "type to filter" text box.

How can we deploy our application to the Tomcat server running inside Eclipse?

Just right click on the project and select "Run As -> Run on Server"

How can we add a new controller?

  1. Add a class
  2. Add the @Controller annotation to the class

This will automatically add the following line:

import org.springframework.stereotype.Controller

to your code. With the @Controller annotation, our class does not need to extend the Spring MVC Controller class. It is done automatically.

package com.companyName.springmvc.login;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class LoginController {
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String showLoginPage() {
        return "login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String handleUserLogin(ModelMap model, @RequestParam String name,
            @RequestParam String password) {
        model.put("name", name);
        model.put("password", password);
        return "welcome";
    }
}

What is the purpose of the @ResponseBody annotation?

When we add the @ResponseBody annotation to a method in our controller, this annotation indicates that the return value of our method should be treated as the body of the response. If we do not add this annotation, the Spring MVC dispatcher servlet will treat the return value as the name of a class, or something else, and it will try to look up that thing but it cannot be found, so it end up with a "404 Not Found" error.

When we do not add the @ResponseBody annotation to a controller method, and if the controller method returns a string, the View Resolver is used to determine the location of JSP (view) file.

Where should we keep the JSP (view) files?

/src/main/webapp/WEB-INF/views

What is the purpose of the View Resolver?

We need to add:

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

to the "application context" configuration file. This allows our controller method to return a short string representing the view. For example, our controller method can return a string "login" and it would get resolved to /WEB-INF/views/login.jsp.

What logging framework is used by Spring Framework by default?

Common Logging.

How can we cause Spring Framework to use log4j instead of Common Logging?

  1. Add log4j as a dependency using Maven
  2. Add a log4j.properties file in the resources folder.

To add log4j as a dependency using Maven, add the following:

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

to the pom.xml file.

The content of the resources/log4j.properties file:

log4j.rootLogger=TRACE, Appender1, Appender2

log4j.appender.Appender1=org.apache.log4j.ConsoleAppender
log4j.appender.Appender1.layout=org.apache.log4j.PatternLayout
log4j.appender.Appender1.layout.ConversionPattern=%-7p %d [%t] %c %x - %m%n

How can we specify that a particular controller method should only handle a particular HTTP method?

Specify the HTTP method as part of the @RequestMapping annotation:

package com.companyName.springmvc.login;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class LoginController {
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String showLoginPage() {
        return "login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String handleUserLogin(ModelMap model, @RequestParam String name,
            @RequestParam String password) {
        model.put("name", name);
        model.put("password", password);
        return "welcome";
    }
}

How can a controller method get access to a form field?

Use the @RequestParam annotation like:

package com.companyName.springmvc.login;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class LoginController {
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String showLoginPage() {
        return "login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String handleUserLogin(ModelMap model, @RequestParam String name,
            @RequestParam String password) {
        model.put("name", name);
        model.put("password", password);
        return "welcome";
    }
}

The second controller method, handleUserLogin get access to the form field 'name' via the @RequestParam annotation. Notice that the name of the parameter is the same as the name of the form field.

How can our controller method pass parameter to our view?

Use the ModelMap object like:

package com.companyName.springmvc.login;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class LoginController {
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String showLoginPage() {
        return "login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String handleUserLogin(ModelMap model, @RequestParam String name,
            @RequestParam String password) {
        model.put("name", name);
        model.put("password", password);
        return "welcome";
    }
}

Notice the model.put statements. Inside, the view, we access the parameters:

<html>
<head>
<title>Yahoo!!</title>
</head>
<body>
Welcome ${name}. You entered ${password}
</body>
</html>

using the ${name} construct as we did previously.

How can we create a service?

In our Java class, add a @Service annotation:

package com.companyName.login;

import org.springframework.stereotype.Service;

@Service
public class LoginService {
    public boolean validateUser(String user, String password) {
        return user.equalsIgnoreCase("whatever") && password.equals("dummy");
    }

}

The import statement is automatically added. Spring MVC is now aware of this service. Spring MVC would automatically create an instance of this bean and have it ready.

How can we use service?

We use the @Autowired annotation:

package com.companyName.login;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class LoginController {

    @Autowired
    private LoginService loginService;

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String showLoginPage() {
        return "login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String handleUserLogin(ModelMap model, @RequestParam String name,
            @RequestParam String password) {

        if (!loginService.validateUser(name, password)) {
            model.put("errorMessage", "Invalid Credentials");
            return "login";
        }

        model.put("name", name);
        return "welcome";
    }
}

What is the point of using the @Autowired and the @Service annotations?

This is something we called "dependency injection". Previously, in our controller class, we explicitly create an instance of the LoginService class. Now we do not do that anymore. We just declare that we are using the LoginService class. The actual creation of the class is done by Spring MVC. This probably make it easier for us to later on replace the LoginService class, perhaps using a configuration file.

How can we get Eclipse or Spring MVC to automatically add the import statement after we type @Autowired?

Hit CTRL+Spacebar

Todo class:

package com.companyName.model;

import java.util.Date;

public class Todo {
    private int id;
    private String user;
    private String desc;
    private Date targetDate;
    private boolean isDone;

    public Todo(int id, String user, String desc, Date targetDate, boolean isDone) {
        super();
        this.id = id;
        this.user = user;
        this.desc = desc;
        this.targetDate = targetDate;
        this.isDone = isDone;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public Date getTargetDate() {
        return targetDate;
    }

    public void setTargetDate(Date targetDate) {
        this.targetDate = targetDate;
    }

    public boolean isDone() {
        return isDone;
    }

    public void setDone(boolean isDone) {
        this.isDone = isDone;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Todo other = (Todo) obj;
        if (id != other.id)
            return false;
        return true;
    }

    @Override
    public String toString() {
        return String.format(
                "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id,
                user, desc, targetDate, isDone);
    }

}

TodoService:

package com.companyName.todo.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.springframework.stereotype.Service;

import com.companyName.model.Todo;

@Service
public class TodoService {
    private static List<Todo> todos = new ArrayList<Todo>();
    private static int todoCount = 3;

    static {
        todos.add(new Todo(1, "whatever", "Learn Spring MVC", new Date(),
                false));
        todos.add(new Todo(2, "whatever", "Learn Struts", new Date(), false));
        todos.add(new Todo(3, "whatever", "Learn Hibernate", new Date(),
                false));
    }

    public List<Todo> retrieveTodos(String user) {
        List<Todo> filteredTodos = new ArrayList<Todo>();
        for (Todo todo : todos) {
            if (todo.getUser().equals(user))
                filteredTodos.add(todo);
        }
        return filteredTodos;
    }

    public void addTodo(String name, String desc, Date targetDate, boolean isDone) {
        todos.add(new Todo(++todoCount, name, desc, targetDate, isDone));
    }

    public void deleteTodo(int id) {
        Iterator<Todo> iterator = todos.iterator();
        while (iterator.hasNext()) {
            Todo todo = iterator.next();
            if (todo.getId() == id) {
                iterator.remove();
            }
        }
    }
}

How can we do a redirect with Spring MVC?

Our controller method should return something like:

return "redirect:list-todos"

In other words, prefix the name of the view with "redirect:"

What is the purpose of model.clear()?

When we do a redirect using "redirect:", Spring MVC automatically serialize all the attribute values in the model map and append that to the URL. To prevent that, we need to invoke model.clear(). Magically, it does not seem to delete the corresponding attribute from the session though.

How can we use JSTL?

Add to pom.xml file:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

Import into our JSP:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

The prefix is the name that we will use to refer to this tag library, and then, in use it in our JSP file:

<c:forEach items="${todos}" var="todo">
    <tr>
        <td>${todo.desc}</td>
        <td>${todo.targetDate}</td>
        <td>${todo.done}</td>
    </tr>
</c:forEach>

What is a web JAR?

Web JARs are JAR files that contains CSS and JavaScripts libraries.

How can we use web JARs?

Add it as a dependency using Maven pom.xml:

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>bootstrap</artifactId>
    <version>3.3.6</version>
</dependency>
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>1.9.1</version>
</dependency>

Then add the CSS files in the head section of the JSP file:

<link href="webjars/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">

And add the JavaScript files just before the closing body tag:

<script src="webjars/jquery/1.9.1/jquery.min.js"></script>
<script src="webjars/bootstrap/3.3.6/js/bootstrap.min.js"></script>

Notices that the URLs starts with webjars. And we need to add:

<mvc:resources mapping="/webjars/**" location="/webjars/"/>

to the "application context" configuration file mentioned above.

What is the purpose of the initBinder?

It tells Spring MVC to consistently use a particular format:

@InitBinder
protected void initBinder(WebDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
    binder.registerCustomEditor(Date.class, new CustomDateEditor(
            dateFormat, false));
}

We added the above method to our controller. Notice that we register the custom editor for the Date.class.

How can we format a date?

<fmt:formatDate pattern="dd/MM/yyyy" value="${todo.targetDate}" />

We can specify the format in each individual places, or we can use InitBinder to consistently format it across the application.

How can we implement a REST service that returns JSON?

First, we need to add to our Maven pom.xml:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.3</version>
</dependency>

/src/main/java/com/companyName/todo/rest/TodoRestController.java:

package com.companyName.todo.rest;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.companyName.model.Todo;
import com.companyName.todo.service.TodoService;

@RestController
public class TodoRestController {
    @Autowired
    private TodoService service;

    @RequestMapping(value = "/todo/", method = RequestMethod.GET)
    public List<Todo> listAllTodos() {
        List<Todo> todos = service.retrieveTodos("username");
        return todos;
    }
}

All we have to do is to add the dependency to our Maven pom.xml file, add a new class TodoRestController, and the URL mapping inside the same class. We also have to add the @RestController annotation. And then we just have to visit the URL mentioned in the @RequestMapping annotation and the server will send us the JSON.

What do we have to do in order to support URL of the form /something/id?

Use the URL mapping: /todo/{id} and the @PathVariable annotation. See the last block of code below:

package com.companyName.todo.rest;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.companyName.model.Todo;
import com.companyName.todo.service.TodoService;

@RestController
public class TodoRestController {
    @Autowired
    private TodoService service;

    @RequestMapping(value = "/todo/", method = RequestMethod.GET)
    public List<Todo> listAllTodos() {
        List<Todo> users = service.retrieveTodos("username");
        return users;
    }

    @RequestMapping(value = "/todo/{id}", method = RequestMethod.GET)
    public Todo retrieveTodo(@PathVariable("id") int id) {
        return service.retrieveTodo(id);
    }
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License