I have taken what Paul described into a working example of my own using Content Negotiation with Spring MVC Rest support.
http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc
The project I created looks as follows
The complete code for this example exists on GitHub as follows
https://github.com/papicella/SpringMVCRest-ContentNegotiation
1. Create the required pom.xml dependancy elements as shown below.
pom.xml
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>springmvc-rest</groupId>
<artifactId>springmvc-rest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<spring.version>3.2.4.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.6</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
</project>
2. Create a Person class as follows
Person.java
package apples.au.pivotal;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Person implements Serializable
{
private int id;
private String firstName;
private String lastName;
public Person()
{
// TODO Auto-generated constructor stub
}
public Person(int id, String firstName, String lastName) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "Person [id=" + id + ", firstName=" + firstName + ", lastName="
+ lastName + "]";
}
}
3. Create a People class which provides a list of Person objects, we do this so we can return XML as a List doesn't work directly with JAXB
People.java
package apples.au.pivotal;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="people")
@SuppressWarnings("serial")
public class People
{
private List<Person> people;
protected People() {} // Keep JAXB happy
public People(List<Person> people)
{
this.people = people;
}
@XmlElement(name="person")
public List<Person> getPeople()
{
return people;
}
}
4. Create a controller as follows, there is a request mapping for HTML as well here with the same path, which is the default, in order not to duplicate code we call the JSON/XML method from the HTML method itself.
PersonController.java
package apples.au.pivotal.controllers;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import apples.au.pivotal.People;
import apples.au.pivotal.Person;
@Controller
public class PersonController
{
private static List<Person> personList;
static
{
personList =
Arrays.asList(new Person[]
{ new Person(1, "Pas", "Apicella"),
new Person(2, "Lucia", "Apicella"),
new Person(3, "Lucas", "Apicella"),
new Person(4, "Siena", "Apicella")
});
}
@RequestMapping(value="/people",
method = RequestMethod.GET,
produces={"application/xml", "application/json"})
@ResponseStatus(HttpStatus.OK)
public @ResponseBody People listWithJSON()
{
return new People(personList);
}
// View-based method
@RequestMapping(value = "/people", method = RequestMethod.GET)
public String listWithView(Model model, HttpServletResponse response, HttpServletRequest request)
{
// Call RESTful method to avoid repeating code
model.addAttribute("peopleList", listWithJSON().getPeople());
// Return the view to use for rendering the response
return "people";
}
}
5. Create a Spring XML file as follows
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- Activates various annotations to be detected in bean classes -->
<context:annotation-config />
<!-- Scans the classpath for annotated components that will be auto-registered as Spring beans.
For example @Controller and @Service. Make sure to set the correct base-package-->
<context:component-scan base-package="apples.au.pivotal.controllers" />
<!-- Configures the annotation-driven Spring MVC Controller programming model.
Note that, with Spring 3.0, this tag works in Servlet MVC only! -->
<bean id="cnManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true"/>
<property name="ignoreAcceptHeader" value="true" />
<property name="defaultContentType" value="text/html" />
<property name="useJaf" value="false"/>
<property name="mediaTypes">
<map>
<entry key="html" value="text/html" />
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
</bean>
<mvc:annotation-driven content-negotiation-manager="cnManager"/>
<bean class="apples.au.pivotal.MvcConfiguringPostProcessor" />
</beans>
6. Create a class to enable pretty print for JSON data
MvcConfiguringPostProcessor.java
package apples.au.pivotal;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
/**
* The HTTP Message converters are created automatically by Spring. To perform
* additional configuration we use a bean post-processor.
*/
public class MvcConfiguringPostProcessor implements BeanPostProcessor {
/**
* Enable pretty print on any bean of type
* {@link MappingJacksonHttpMessageConverter} or
* {@link MappingJackson2HttpMessageConverter}.
*/
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException
{
if (bean instanceof HttpMessageConverter<?>)
if (bean instanceof MappingJacksonHttpMessageConverter) {
((MappingJacksonHttpMessageConverter) bean).setPrettyPrint(true);
}
else if (bean instanceof MappingJackson2HttpMessageConverter) {
((MappingJackson2HttpMessageConverter) bean).setPrettyPrint(true);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
// Nothing to do
return bean;
}
}
7. Finally create a HTML view page
people.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!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=UTF-8">
<title>Spring MVC Rest Demo</title>
</head>
<body>
<h2>Spring MVC Rest Demo</h2>
<table border="1">
<tr>
<th>Id</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
<c:forEach var="row" varStatus="loop" items="${peopleList}">
<tr>
<td>${row.id}</td>
<td>${row.firstName}</td>
<td>${row.lastName}</td>
</tr>
</c:forEach>
</table>
<p />
Created by Pas Apicella
</body>
</html>
8. Run the application and access the 3 supported views with request mapping path of "/people"
HTML - http://localhost:8080/springmvc-rest/apples/people
JSON - http://localhost:8080/springmvc-rest/apples/people.json
XML - http://localhost:8080/springmvc-rest/apples/people.xml




3 comments:
Great....thanks
Thanks, nice instruction
Finally I understand this thanks to your post!
Post a Comment