Spring 3 MVC Annotations tutorial


This post will give brief idea about creating views, controller in Spring.

Note: The code can be downloaded. URL for download is present at the end.

A simple example : Store the information of a person. The property of a person is Name and City with a unique id.
The model class will be


public class PersonForm {

	private String name;
	private String city;
	private int id = -1;
	
	public PersonForm(int id,String name, String city ) {
		this.name = name;
		this.city = city;
		this.id = id;
	}
	public PersonForm() {
		// TODO Auto-generated constructor stub
	}
	// include getters and setters
}

Following functionalities can be defined:

  • Create a user
  • Edit a user
  • Delete a user
  • Show all users

The url mappings can be defined

URL Function jsp page
/person , Request Type = GET Show all users show.jsp
/person , Request Type = POST Save a user user.jsp
/person/newuser , Request Type = GET/td>

Show a blank form to enter user details user.jsp
/person/delete/{id} , Request Type = POST Delete a user show.jsp
/person/update/{id} , Request Type = POST Update a user user.jsp

Note: The user is stored simply using a HashMap ( for simplicity) . Ideally all calls should go to DB.
Lets create the Controller where all the actions happen.

@RequestMapping("/person")
@Controller
/** Displaying CRUD functionality. **/
public class PersonController {
	
	Map<Integer, PersonForm> personList = new HashMap<Integer, PersonForm>();
	static int  id = 0;
	
	/**
	 * Save a user and return back to display all users
	 */
	@RequestMapping(method=RequestMethod.POST)
	public ModelAndView save(PersonForm form,BindingResult errors, HttpServletRequest request, HttpServletResponse response){
		if(form.getId() == -1){
		id++;
		form.setId(id);
		personList.put(id,form);
		}else{
			personList.put(form.getId(), form);
		};
		ModelMap map = new ModelMap();
		Iterator iter = personList.keySet().iterator();
		List<PersonForm> newMap = new ArrayList<PersonForm>();
		while(iter.hasNext()){
			Object key = iter.next();
			if(key != null)
				newMap.add(personList.get(key));
		}
		map.put("persons",newMap);
		return new ModelAndView("show",map);
	}
	
	@RequestMapping(value="/newuser",method=RequestMethod.GET)
	public ModelAndView newUser(){
		PersonForm form = new PersonForm();
		ModelMap map = new ModelMap();
		map.put("person", form);
		return new ModelAndView("user",map);
	}
	
	/**
	 * 
	 * Display all users
	 */
	@RequestMapping(method=RequestMethod.GET)
	public String displayAll( HttpServletRequest request){
		ModelMap map = new ModelMap();
		Iterator iter = personList.keySet().iterator();
		List<PersonForm> newMap = new ArrayList<PersonForm>();
		while(iter.hasNext()){
			Object key = iter.next();
			if(key != null)
				newMap.add(personList.get(key));
		}
		map.put("persons",newMap);
		request.setAttribute("persons", newMap);
		return "show";
	}
	/** Delete a user and return back to all list **/
	@RequestMapping(value="/delete/{id}")
	public String delete(@PathVariable String id, HttpServletRequest request){
		personList.remove(Integer.parseInt(id));
		Iterator iter = personList.keySet().iterator();
		List<PersonForm> newMap = new ArrayList<PersonForm>();
		while(iter.hasNext()){
			Object key = iter.next();
			if(key != null)
				newMap.add(personList.get(key));
		}
		request.setAttribute("persons", newMap);
		return "show";
	}
	/** Update a user and return back to all list **/
	@RequestMapping(value="/update/{id}")
	public ModelAndView update(@PathVariable String id){
		ModelMap map = new ModelMap();
		map.put("person", personList.get(Integer.parseInt(id)));
		return new ModelAndView("user",map);
	}
}

Here all the actions happen:

  • @Controller: is used to tell Spring that PersonController is a controller
  • @RequestMapping(class-level): Annotation for mapping web requests onto specific handler classes and/or handler methods.All urls inside this controller should precede with the url mentioned as the value.
  • @RequestMapping(method-level): The function will be called if the url maps the given value. Other attributes can be set as RequestType(GET or POST etc) .
  • ModelAndView: This class merely holds both(Model and view) to make it possible for a controller to return both model and view in a single return value. The object tell which view to resolve and what model object should be passed.
  • ModelMap: Implementation of Map(LinkedHashMap),building model data for use with UI tools.Basically replacement of setting values as request attribute.
  • Method such as delete and displayAll returns the String. The return value is mapped to view name. The view name is resolved using InternalResourceViewResolver configured in mvc-dispatcher-servlet.xml.
  • The update or delete url are mapped as /update/{id}.. Any parameter defined in {} can be accessed using @PathVariable
  • Note: I have defined controller to view mapping in couple of ways. There are more ways to define.

Now its the turn of views:
user.jsp

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form:form commandName="person" method="post" action="/SpringMVC/person">
<form:hidden path="id" id="id" />
<table>
	<tr>
		<td><label>Name</label></td>
		<td><form:input path="name" id="name"/></td>
	</tr>
	<tr>
		<td><label>City</label></td>
		<td><form:input path="city" id="city"/></td>
	</tr>
	<tr>
		<td><input type="submit" name="save" value="save"/></td>
	</tr>
</table>	
</form:form>
</body>
</html>

This view is used to save and update the users.

index.jsp

<%@ page language="java" errorPage="/error.jsp" pageEncoding="UTF-8" contentType="text/html;charset=utf-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<body>
	<h1>List Of People</h1>
	<table>
	<tr>
		<th>Name</th>
		<th>City</th>
	</tr>
	<c:forEach items="${persons}" var="person">
	<tr>
		<td>${person.name}</td>
		<td>${person.city}</td>
		<td>
			<a href="/SpringMVC/person/delete/${person.id}">DELETE</a>
		</td>
		<td>
			<a href="/SpringMVC/person/update/${person.id}">EDIT</a>
		</td>
	</tr>
	</c:forEach>
	</table>	
</body>
</html>

Now the configuration:
The web.xml is pretty basic .. Declaring the org.springframework.web.servlet.DispatcherServlet and loading the spring servlet.xml. The code can be downloaded at the end.

mvn-dispatcher-servlet.xml is very basic for this example

<context:component-scan base-package="com.common.controller" />
	<context:annotation-config />
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/pages/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>

This <context:annotation-config /> tells that spring in annotation enabled.
This <context:component-scan base-package> tells where beans are configured.
And InternalResourceViewResolver resolve view names to jsp pages present in WEB-INF/pages.

Download Code