Spring MVC 4 - @ModelAttribute annotation example

Posted on April 15, 2017


Technologies used:   JDK 1.8.0_121 | Spring 4.3.7.RELEASE | Maven 3.3.9 | Apache Tomcat 7.0.47 | Eclipse Neon.3

@ModelAttribute annotation is used to bind a method parameter or a method return value to a named model attribute. It can be used either on methods or on method parameters.

Spring invokes all methods that have @ModelAttribute annotation before handler methods (i.e. methods annotated with the @RequestMapping) in a same controller.

The following example demonstrates how the @ModelAttribute annotation is used in Spring MVC application.

Jar dependencies

Add the following jar dependencies in your pom.xml file.

<!-- Spring MVC Dependency -->
  <dependency>
	 <groupId>org.springframework</groupId>
	 <artifactId>spring-webmvc</artifactId>
	 <version>4.3.7.RELEASE</version>
  </dependency>

  <!-- JSTL Dependency -->
  <dependency>
	 <groupId>javax.servlet.jsp.jstl</groupId>
	 <artifactId>javax.servlet.jsp.jstl-api</artifactId>
	 <version>1.2.1</version>
  </dependency>
  <dependency>
	 <groupId>taglibs</groupId>
	 <artifactId>standard</artifactId>
	 <version>1.1.2</version>
  </dependency>

  <!-- Servlet Dependency -->
  <dependency>
	 <groupId>javax.servlet</groupId>
	 <artifactId>javax.servlet-api</artifactId>
	 <version>3.1.0</version>
	 <scope>provided</scope>
  </dependency>

 

Controller class

Create a @Controller class whose methods and method parameters are annotated with @ModelAttribute annotation as follows.

MyController.java

package com.boraji.tutorial.spring.controller;

import java.util.ArrayList;
import java.util.List;

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


/**
 * @author imssbora
 */
@Controller
public class MyController {

   /*
    ********Example of using @ModelAttribute on a method*******
    * 
    * The following handler adds a single attribute ( i.e. 'countries') to model
    *  implicitly by returning it
    */
   @ModelAttribute("countries")
   public List<String> populateCountries() {
      List<String> countries= new ArrayList<>();
      countries.add("India");
      countries.add("USA");
      countries.add("Japan");
      return countries;
   }

   /*
    * *******Example of using @ModelAttribute on a method*******
    * 
    * The following handler method accept a model and add multiple attribute to it
    */
   @ModelAttribute
   public void populateCitiesAndLanguages(Model model) {
      
      List<String> cities= new ArrayList<>();
      cities.add("Paris");
      cities.add("New York");
      cities.add("London");
      cities.add("Delhi");
      cities.add("Beijing");
      
      List<String> languages= new ArrayList<>();
      languages.add("English");
      languages.add("Hindi");
      languages.add("Urdu");
      
      
      model.addAttribute("cities", cities);
      model.addAttribute("languages", languages);
   }

   /*
    * *******Example of using @ModelAttribute on a method argument*******
    * 
    * A handler method can have more then one parameters with @ModelAttribute
    * The following handler method will retrieve the 'countries','cities' and 'languages'
    *  attribute from the model
    */
   @RequestMapping("/")
   public String intiView(@ModelAttribute("countries") List<String> countries,
         @ModelAttribute("cities") List<String> cities,
         @ModelAttribute("languages") List<String> languages,
         Model model) {
      
      //Add more countries
      countries.add("Australia");
      countries.add("Canada");
      
      //Add more cities
      cities.add("Cape Town");
      cities.add("Las Vegas");
      
      //Add more languages
      languages.add("Arabic");
      languages.add("Russian");
      
      model.addAttribute("msg", "This is an example of using @ModelAttribute.....");
      
      return "main";
   }
}

When URL http://localhost:8080/ is accessed from a web browser then Spring will invoke the @ModelAttribute methods (i.e. populateCountries() and populateCitiesAndLanguages()) before handler method and adds countries, cities and languages attributes to the model. This model is then passed to the handler method (i.e. intiView()).

Inside the initView() method, the @ModelAttribute method parameters retrieve the countries, cities and languages attributes  from the model. Finally the model is exposed for web views after adding more countries, cites and languages to attribute lists.

 

JSP View

Create a main.jsp file under src/main/webapp/WEB-INF/views folder to render the model data.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
   pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>BORAJI.COM</title>
</head>
<body>
   <h1>@ModelAtrribute example</h1>
   <hr />
   <table>
      <tr>
         <td>Countries: ${countries}</td>
      </tr>
      <tr>
         <td>Cities: ${cities}</td>
      </tr>
      <tr>
         <td>Languages: ${languages}</td>
      </tr>
   </table>
<br>

${msg}

</body>
</html>

Spring configuration

Create a web @Configuration class annotated with @EnableWebMvc and @ComponentScan as follows.

package com.boraji.tutorial.spring.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

/**
 * @author imssbora
 */

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.boraji.tutorial.spring.controller" })
public class WebConfig extends WebMvcConfigurerAdapter {

   @Bean
   public InternalResourceViewResolver resolver() {
      InternalResourceViewResolver resolver = new InternalResourceViewResolver();
      resolver.setViewClass(JstlView.class);
      resolver.setPrefix("/WEB-INF/views/");
      resolver.setSuffix(".jsp");
      return resolver;
   }
}

The @EnableWebMvc enables default Spring MVC configuration and provides the functionality equivalent to <mvc:annotation-driven/> element in XML based configuration.

The @ComponentScan scans the stereotype annotations (@Controller@Service etc...) in a package specified by basePackages attribute.

Servlet container initialization

Create a container initializer class by extending the AbstractAnnotationConfigDispatcherServletInitializer class as follows.

MyWebAppInitializer.java

package com.boraji.tutorial.spring.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * @author imssbora
 */
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

   @Override
   protected Class<?>[] getRootConfigClasses() {
      return new Class[] {};
   }

   @Override
   protected Class<?>[] getServletConfigClasses() {
      return new Class[] { WebConfig.class };
   }

   @Override
   protected String[] getServletMappings() {
      return new String[] { "/" };
   }
}

The AbstractAnnotationConfigDispatcherServletInitializer class, implements the WebApplicationInitializer, is implemented in Servlet 3.0+ environments in order to configure the ServletContext programmatically.

 

Build + Deploy + Run application

Use the following maven commands to build, deploy and run embedded Tomcat server.

mvn clean install  (This command triggers war packaging)

mvn tomcat7:run (This command run embedded tomcat and deploy war file automatically)

You can refer this link to learn how to run the above commands in Eclipse IDE.

 

Type the following URLs in browser's address bar and see output…

http://localhost:8080/

SpringMVC-ModelAttribute1.png