Spring 4 MVC ContentNegotiatingViewResolver Example

By Yashwant Chavan, Views 40445, Date 19-Dec-2016

In this tutorial, You will learn about Spring 4 MVC ContentNegotiatingViewResolver, Here we have defined multiple views for different content-types which will be identified by ContentNegotiatingViewResolver and return a response in HTML, JSON, PDF and in XML format.

tags spring

How does the application know which ViewResolver needs to render whether to convert to JSON, XML or PDF? because of we have defined respected content negotiation configuration.

To enable content negotiation, Spring MVC uses Java configuration which defines content negotiation manager via it's configurer. Spring MVC provides facility to have multiple views for the same data using different ViewResolvers.

In this example, we have defined multiple views like XmlViewResolver, JsonViewResolver, PdfViewResolver, and default JspViewResolver.

Spring 4 Eclipse project set up

Spring 4 MVC ContentNegotiatingViewResolver - Eclipse project setup

Tools and Technologies

  1. Apache Maven 3.0.4
  2. JDK 1.8
  3. Spring core, Spring webmvc, spring oxm and Spring context (4.1.4.RELEASE)
  4. Mysql Client(5.1.31)
  5. Jackson Api (2.4.1)
  6. IText Api (4.2.1)
  7. Javax Servlet (3.1.0)

Database table

Use below SQL script to create "trn_person" table in the database and insert few records in the table.

CREATE TABLE  `technicalkeeda`.`trn_person` (
  `person_id` int(10) unsigned NOT NULL auto_increment,
  `first_name` varchar(45) collate latin1_general_ci NOT NULL,
  `last_name` varchar(45) collate latin1_general_ci NOT NULL,
  `age` int(10) unsigned NOT NULL,
  PRIMARY KEY  USING BTREE (`person_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
Insert few records in the table

pom.xml

As we are using Maven project. Let's define the spring 4 specific maven dependencies.

<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>com.technicalkeeda</groupId>
    <artifactId>Spring4Examples</artifactId>
    <packaging>war</packaging>
    <version>1.0</version>
    <name>Spring4Examples</name>
    <description></description>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <spring.version>4.1.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-context</artifactId>
            <version>${spring.version}</version>
        </dependency>


        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</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>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
        </dependency>


        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.4.1.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.4.1</version>
        </dependency>


        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${spring.version}</version>
        </dependency>


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.31</version>
        </dependency>


        <dependency>
            <groupId>com.lowagie</groupId>
            <artifactId>itext</artifactId>
            <version>4.2.1</version>
        </dependency>

    </dependencies>
</project>

Person Pojo

This is simple Person pojo class which contains different attributes like personId, firstName, lastName and age. Mark Person pojo with standard XML annotations like @XmlRootElement and @XmlElement.

package com.technicalkeeda.bean;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "person")
public class Person {

    private int personId;
    private String firstName;
    private String lastName;
    private int age;

    public Person() {

    }

    public Person(int personId, String firstName, String lastName, int age) {
        super();
        this.personId = personId;
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    public int getPersonId() {
        return personId;
    }

    @XmlElement
    public void setPersonId(int personId) {
        this.personId = personId;
    }

    public String getFirstName() {
        return firstName;
    }

    @XmlElement
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    @XmlElement
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    @XmlElement
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Person Id:- " + getPersonId() + " First Name:- " + getFirstName() + " Last Name:- " +
            getLastName() + " Age:- " + getAge());
        return builder.toString();
    }

}

application.properties

Create "application.properties" file under /resources folder. Define data source configuration properties like jdbc driverClassName, url, username and password.

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/technicalkeeda
jdbc.username=root
jdbc.password= 

Spring 4 Application Configuration

@Configuration annotation imports the Spring configuration. @Configuration objects are managed as Spring beans within the container, imported configurations are used to injected using @Autowired or @Inject.

@ComponentScan is equivalent to <context:component-scan base-package="..." used to lookup the beans and components classes in the spring context.

@EnableWebMvc annotation is used to enable Spring MVC.

@PropertySource annotation use to provide a convenient and declarative mechanism for adding a PropertySource to Spring's Environment.

To declare a bean, simply annotate a method with the @Bean annotation. When JavaConfig encounters such a method, it will execute that method and register the return value as a bean within a BeanFactory.

package com.technicalkeeda.configuration;

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

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

import com.technicalkeeda.bean.Person;
import com.technicalkeeda.resolvers.JsonViewResolver;
import com.technicalkeeda.resolvers.PdfViewResolver;
import com.technicalkeeda.resolvers.XmlViewResolver;

@Configuration
@ComponentScan(basePackages = "com.technicalkeeda")
@PropertySource(value = { "classpath:application.properties" })
@EnableWebMvc
public class ApplicationConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private Environment env;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(env.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(env.getRequiredProperty("jdbc.password"));
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.setResultsMapCaseInsensitive(true);
        return jdbcTemplate;
    }

    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.ignoreAcceptHeader(true).defaultContentType(MediaType.TEXT_HTML);
    }

    @Bean
    public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
        ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
        resolver.setContentNegotiationManager(manager);

        List < ViewResolver > resolvers = new ArrayList < ViewResolver > ();

        resolvers.add(xmlViewResolver());
        resolvers.add(jsonViewResolver());
        resolvers.add(pdfViewResolver());
        resolvers.add(jspViewResolver());

        resolver.setViewResolvers(resolvers);
        return resolver;
    }

    @Bean
    public ViewResolver xmlViewResolver() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setClassesToBeBound(Person.class);
        return new XmlViewResolver(marshaller);
    }

    @Bean
    public ViewResolver jsonViewResolver() {
        return new JsonViewResolver();
    }

    @Bean
    public ViewResolver pdfViewResolver() {
        return new PdfViewResolver();
    }

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

}

WebApplicationInitializer Configuration

Earlier we used to define web.xml to declare the dispatcher related configurations. Now we are using 100% code base (annotation and java config ) approach to doing the application configuration.

WebApplicationInitializer interface is implemented in Servlet 3.0+, which is used to configure the ServletContext programmatically rather than traditional web.xml-based approach.

package com.technicalkeeda.configuration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class ApplicationInitializer implements WebApplicationInitializer {

    public void onStartup(ServletContext container) throws ServletException {

        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(ApplicationConfig.class);
        ctx.setServletContext(container);

        ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx));

        servlet.setLoadOnStartup(1);
        servlet.addMapping("/");
    }

}

Controller

Let's create a simple controller class PersonController and annotate it with @Controller. The @Controller annotation indicates that a particular class serves the role of a controller.

Now add getPerson() method along with @RequestMapping annotation. The dispatcher will scan such annotated classes for mapped methods and detect the respected @RequestMapping annotation.

package com.technicalkeeda.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.servlet.ModelAndView;

import com.technicalkeeda.bean.Person;
import com.technicalkeeda.services.PersonService;

@Controller
public class PersonController {

    @Autowired
    PersonService personService;

    @RequestMapping(value = "/person/{id}", method = RequestMethod.GET)
    public ModelAndView getPerson(@PathVariable int id) {
        Person person = personService.find(id);
        return new ModelAndView("person").addObject("person", person);

    }

}

JsonViewResolver

JsonViewResolver is responsible for, to generate the output in JSON format. If A URL suffix (extension) with .json like (http://localhost:8080/Spring4Examples/person/1.json) it produce the output in JSON format.

Spring provides a MappingJackson2JsonView that supports the generation of JSON data from Java objects using the Jackson Object to JSON mapping library. The MappingJacksonJsonView automatically converts all attributes found in the Model to JSON.

package com.technicalkeeda.resolvers;

import java.util.Locale;

import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

public class JsonViewResolver implements ViewResolver {

    public View resolveViewName(String viewName, Locale locale) throws Exception {

        MappingJackson2JsonView view = new MappingJackson2JsonView();
        view.setPrettyPrint(true);
        return view;

    }

}

PdfViewResolver

PdfViewResolver is responsible for, to generate the output in PDF format. If A URL suffix (extension) with .pdf like (http://localhost:8080/Spring4Examples/person/3.pdf) it produce the output as PDF response.

package com.technicalkeeda.resolvers;

import java.util.Locale;

import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;

import com.technicalkeeda.views.PdfView;

public class PdfViewResolver implements ViewResolver {

    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {

        PdfView view = new PdfView();
        return view;

    }

}

PDF View

package com.technicalkeeda.views;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.view.document.AbstractPdfView;

import com.lowagie.text.Document;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import com.technicalkeeda.bean.Person;

public class PdfView extends AbstractPdfView {
    protected void buildPdfDocument(Map model, Document document, PdfWriter writer, HttpServletRequest req,
        HttpServletResponse resp) throws Exception {

        Person person = (Person) model.get("person");

        PdfPTable table = new PdfPTable(4);

        table.addCell("Person Id");
        table.addCell("First Name");
        table.addCell("Last Name");
        table.addCell("Age");

        table.addCell(String.valueOf(person.getPersonId()));
        table.addCell(person.getFirstName());
        table.addCell(person.getLastName());
        table.addCell(String.valueOf(person.getAge()));

        document.add(table);

    }

}

XmlViewResolver

XmlViewResolver is responsible for, to generate the output in XML format. If A URL suffix (extension) with .xml like (http://localhost:8080/Spring4Examples/person/2.xml) it produce the output as XML response.

package com.technicalkeeda.resolvers;

import java.util.Locale;

import org.springframework.oxm.Marshaller;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.xml.MarshallingView;

public class XmlViewResolver implements ViewResolver {

    private Marshaller marshaller;

    public XmlViewResolver(Marshaller marshaller) {
        this.marshaller = marshaller;
    }

    public View resolveViewName(String viewName, Locale locale) throws Exception {
        MarshallingView marshallingView = new MarshallingView();
        marshallingView.setMarshaller(marshaller);
        return marshallingView;
    }

}

PersonService Interface

Creates PersonService interface. find() method returns Person entity identified by the given id.

package com.technicalkeeda.services;

import com.technicalkeeda.bean.Person;

public interface PersonService {

    public Person find(int personId);

}

PersonService Implementation

Mark PersonServiceImpl class as "personService" using @Service annotation. Use @Autowired annotation to autowire PersonDao bean.

package com.technicalkeeda.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.technicalkeeda.bean.Person;
import com.technicalkeeda.dao.PersonDao;

@Service("personService")
public class PersonServiceImpl implements PersonService {

    @Autowired
    PersonDao personDao;

    public Person find(int personId) {
        return personDao.find(personId);
    }

}

PersonDao Interface

Creates PersonDao interface.

package com.technicalkeeda.dao;

import com.technicalkeeda.bean.Person;

public interface PersonDao {
    public Person find(int personId);
}

PersonDao implementation

PersonDaoImpl marked with @Repository annotation, It allows the component scanning to find and configure the respected DAO. @Autowired JdbcTemplate to access to a persistence resource.

package com.technicalkeeda.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.technicalkeeda.bean.Person;

@Repository
@Qualifier("personDao")
public class PersonDaoImpl implements PersonDao {

    @Autowired
    JdbcTemplate jdbcTemplate;

    public Person find(int personId) {
        Person person = (Person) jdbcTemplate.queryForObject("SELECT * FROM trn_person where person_id = ? ",
            new Object[] { personId }, new BeanPropertyRowMapper(Person.class));

        return person;
    }

}

Default View

Lets create "person.jsp" under /WEB-INF/jsp/ folder. If A URL suffix without any extension (http://localhost:8080/Spring4Examples/person/1) it produce the output as HTML response. As this is the default view!!!.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

        <html>

        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
            <title>Person JSP View!!!</title>
            <style>
            td,
            th {
                border: 1px solid #999;
                padding: 0.2rem;
            }
            </style>
        </head>

        <body>
            <h2>Person JSP View!!!</h2>
            <table>
                <tr>
                    <td>Person Id</td>
                    <td>First Name</td>
                    <td>Last Name</td>
                    <td>Age</td>
                </tr>
                <tr>
                    <td>${person.personId}</td>
                    <td>${person.firstName}</td>
                    <td>${person.lastName}</td>
                    <td>${person.age}</td>
                </tr>
            </table>
        </body>

        </html>

http://localhost:8080/Spring4Examples/person/1

Spring 4 MVC ContentNegotiatingViewResolver - Jsp View

http://localhost:8080/Spring4Examples/person/1.json

Spring 4 MVC ContentNegotiatingViewResolver - Json View

http://localhost:8080/Spring4Examples/person/2.xml

Spring 4 MVC ContentNegotiatingViewResolver - Xml View

http://localhost:8080/Spring4Examples/person/3.pdf

Spring 4 MVC ContentNegotiatingViewResolver - Pdf View
Yashwant Chavan

Yashwant Chavan

Hi there! I am founder of technicalkeeda.com and programming enthusiast. My skills includes Java,J2EE, Spring Framework, Nodejs, PHP and lot more. If you have any idea that you would want me to develop? Lets connect: yashwantchavan@gmail.com