What is the purpose and usage of @ModelAttribute in Spring MVC?

@ModelAttribute refers to a property of the Model object (the M in MVC). The primary objective of this annotation is to bind the request parameters or form fields to a model object. Basically in Spring MVC web application the @ModelAttribute annotation can be used in following ways. It can be used to pass data to JSP before it loads. This ensures that the JSP has all the data which are required to display itself. The injection of data is achieved by binding an Object with the Model and pass it to the JSP. It can also be used to receive data in Controller from form fields.

To demonstrate the usages of @ModelAttribute annotation we are going to create an User Management System with option like create/update/view user.

Example 1 : Bind a method return value to a model. Here we will see how to automatically bind a method return value to a model. Consider we are developing the create user use case. And we need to provide a drop down list of cities in UI. The following is our City class.

public class City {

    private Integer id;
    private String name;
    
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Now we will get all the cites from data store (Which is a Caching layer) and bind it to the Model in the following way.

package com.tuturself.web.controller
@Controller
@RequestMapping("/user")
public class UserManagementController {

    private static final Logger LOGGER = LogManager.getLogger(UserManagementController.class);
    
    @Autowired
    private ICacheService iCacheService;
    
    @ModelAttribute("cityList")
    public List<City> populateCityList() {
        List<City> cityList = null;
        try {
            cityList = iCacheService.getCityList();
        } catch (Exception e) {
            LOGGER.error("Error while fetching the cityList in UserManagementController >>" + e.getMessage(), e);
        }
        return cityList;
    }
}

By @ModelAttribute("cityList") annotation the list of cities will be available in the model. Remember this automatic binding will only work if we provide the following configuration in our spring configuration file.

<context:component-scan base-package="com.tuturself.*" />

By this we are actually informing spring context to scan all the classes in com.tuturself.* package and read all annotation to perform the desired action. And we can use it to create a drop-down of all cities in the JSP by following way: 

<select name="cityId" class="form-control">
    <c:forEach var="city" items="${cityList}" varStatus="cl">
        <option value="${city.id}">${city.name}</option>
    </c:forEach>
</select>

The following is an example to manually achieve the @ModelAttribute("cityList") functionality. Here we are adding the cityList Object to Model and pass it to JSP.

@RequestMapping(method = RequestMethod.GET)
public String showCreateUserPage(Model model,HttpServletRequest request) {
    List<City> cityList = iCacheService.getCityList();
    model.addAttribute("cityList",cityList);
    return "create-user";
}

This cityList Object in model can be used in same c:forEach loop described earlier to create the drop-down.

Example 2 : Receive form fields through @ModelAttribute. The @ModelAttribute annotation can also be used to receive form fields in Controller. Consider the following example where we are going to develop the update user use case. We need to bind a User Object with Model and pass it to the JSP. The JSP will use the User Object and render the UI. And we can receive the updated user object by @ModelAttribute annotation.

Following is our User class.

public class User {

    private Long userId;
    private String name;
    private Integer cityId;
    private String email;
    public Long getUserId() {
        return userId;
    }
    public void setUserId(Long userId) {
        this.userId = userId;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getCityId() {
        return cityId;
    }
    public void setCityId(Integer cityId) {
        this.cityId = cityId;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
}

Following is the UserManagementController

@Controller
@RequestMapping("/user")
public class UserManagementController {

    private static final Logger LOGGER = LogManager.getLogger(UserManagementController.class);

    @Autowired
    private UserService iUserService;

    /**
     * Get the user by userId, and bind the same to model
     */
    @RequestMapping(method = RequestMethod.GET)
    public String showUpdateUserPage(Model model, HttpServletRequest request) {
        Long userId = ServletRequestUtils.getLongParameter(request, "userId");
        User user = iUserService.getUserByUserId(userId);
        model.addAttribute("user", user);
        return "view-user";
    }

    /**
     * Get the user object from UI
     */
    @RequestMapping(method = RequestMethod.POST)
    public String saveUser(@ModelAttribute("user") User user, HttpServletRequest request) {
        iUserService.saveUser(user);
        return "view-user";
    }
}

The showUpdateUserPage() receives a call by the following url:

   http://www.mysite.com/user?userId=1098

Now the showUpdateUserPage() method find the user by the userId and bind it with the Model. Following is the <form> in JSP which uses the User Object to render the UI.

<form action="${pageContext.request.contextPath}/user" modelAttribute="user" method="POST">
    <input type="hidden" name="userId" value="${userId}"/>
    <fieldset>
        <div class="row">
            <div class="form-group">
                <div class="col-md-6 col-sm-6">
                    <label>Name *</label>
                    <input name="name" value="${name}" class="form-control" type="text"/>
                </div>
                <div class="col-md-6 col-sm-6">
                    <label>Email *</label>
                    <input name="email" value="${email}" class="form-control" type="email"/>
                </div>
            </div>
        </div>
        
        <div class="row">
            <div class="form-group">
                <div class="col-md-6 col-sm-6">
                    <label>City</label> 
                    <select name="cityId" class="form-control">
                        <c:forEach var="city" items="${cityList}" varStatus="cl">
                            <option value="${city.id}">${city.name}</option>
                        </c:forEach>
                    </select>
                </div>
            </div>
        </div>
    </fieldset>
    <div class="divider"></div>
    <div class="margiv-top10">
        <button type="submit" class="btn btn-success">
            Update
        </button>
    </div>
</form>

Clicking on ‘Update’ button will call the saveUser() method. The saveUser() method needs a User object from the incoming model, so the updated user’s details can be saved to the database. The @ModelAttribute("user") annotation applied takes any matching object from the model with the “user” annotation and plugs it into the User user method argument.

    

spring 12

FOLLOW US ON LinkedIn



Explore Tutu'rself