Enterprise Java

Configure multiple View Resolvers in Spring

1. Introduction

In Spring, the View Resolver is provided to resolve the view with the data available in the model, without tightly binding to a View technology, be it JSP, Velocity or Thymeleaf. Spring makes it easy and flexible to configure one or multiple View Resolvers, as per the need would be.

2. Spring MVC application flow

Before we proceed with understanding how multiple View Resolvers serve the purpose, lets take a quick recap of the Spring MVC application flow.

  1. Incoming request comes through web.xml, dispatcher servlet and hits the controller.
  2. Controller interacts with the application layers and prepares the model.
  3. Controller returns the ModelAndView, with model and the view name.
  4. The ViewResolver provides a mapping between view names and actual views.
  5. The View interface addresses the request of a view to respective View technology.
  6. The view is then rendered onto the browser along with the model data.

3. Implementation

Let’s start with the pom dependencies.

pom.xml

<!-- Spring 3 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>
 
<!-- Jackson JSON Mapper -->
<dependency>
	<groupId>org.codehaus.jackson</groupId>
	<artifactId>jackson-mapper-asl</artifactId>
	<version>${jackson.version}</version>
</dependency>
 
<!-- JSTL Dependency -->
<dependency>
	<groupId>jstl</groupId>
	<artifactId>jstl</artifactId>
	<version>${jstl.version}</version>
</dependency>

Not much change in the web.xml.

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
 
	<display-name>MultipleViewResolversExample</display-name>
 
	<servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
 
	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>/API/*</url-pattern>
	</servlet-mapping>
 
</web-app>

Here is the mvc-dispatcher-servlet, which has multiple View Resolvers defined.

mvc-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 
	<mvc:annotation-driven />
	<context:component-scan base-package="com.jcombat.controller" />
 
	<!-- Bean View Resolver -->
	<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
		<property name="order" value="0" />
	</bean>
 
	<!-- JSP View Resolver -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
		<property name="order" value="1" />
	</bean>
 
	<bean name="jsonView"
		class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
 
</beans>

Note that the two View Resolvers configured are InternalResourceViewResolver and BeanNameViewResolver. We have also set the priorities using the order property of the View Resolver. So BeanNameViewResolver has a higher priority. This means that when the ModelAndView object is returned, the BeanNameViewResolver checks for the available bean views with the view name that is returned. If the matching bean view is found, it is rendered. If not, the next View Resolver i.e. InternalResourceViewResolver, comes into the picture, and similarly checks for the JSPs with the view name that is returned with ModelAndView. If it is found, the view is rendered. But if not, and there is no more View Resolvers down the hierarchy, an appropriate exception is thrown.

Moving ahead with the implemetation, we have the same Employee entity class, as we have been using recently.

Employee.java

package com.jcombat.bean;
 
public class Employee {
	private String empId;
	private String name;
	
	public String getEmpId() {
		return empId;
	}
	public void setEmpId(String empId) {
		this.empId = empId;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

Let’s now write down the EmployeeController.

EmployeeController.java

package com.jcombat.controller;
 
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.jcombat.bean.Employee;
 
@Controller
@RequestMapping(value = "/Employee")
public class EmployeeController {
 
	@RequestMapping(value = "/{name}/{empId}", method = RequestMethod.GET)
	public ModelAndView process(
			@PathVariable("name") String name,
			@PathVariable("empId") String empId) {
		ModelAndView modelAndView = new ModelAndView();
		Employee employee = new Employee();
		employee.setEmpId(empId);
		employee.setName(name);
		modelAndView.setViewName("employeeDetails");
		modelAndView.addObject("employee", employee);
		return modelAndView;
	}
}

We now make sure the JSP with the view name – employeeDetails, exists.

employeeDetails.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!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>Via JSP View Resolver</title>
	</head>
	<body>
		<!-- Retrieve the model data through JSTL -->
		<p>${employee.empId}</p>
		<p>${employee.name}</p>
	</body>
</html>

4. Running the application

When we run the application, below is what we see.

Snap1

Note that we don’t have any bean view with name employeeDetails, but rather matches with the actual JSP view file employeeDetails.jsp. Hence, the view gets resolved as JSP.

Now let’s return the view name as jsonView, modifying the below statement in the controller method.

modelAndView.setViewName("jsonView");

BeanNameViewResolver being higher in priority, this time finds the bean view with the name jsonView, and instead of rendering the JSP view, the same URI now returns a JSON.

Snap2

5. Download the source code

Reference: Configure multiple View Resolvers in Spring from our JCG partner Abhimanyu Prasad at the jCombat blog.

Abhimanyu Prasad

Abhimanyu is a passionate tech blogger and senior programmer, who has an extensive end-to-end development experience with wide range of technologies. He is the founder and administrator at jCombat.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Gelin Luo
7 years ago

Hi Abhimanyu, I can get your attention to ActFramework (http://actframework.org)? Although I’ve just released the first version to maven central repository, it has been put into comercial usage for 1 years. I suppose most feature SpringBoot provided in a better and simpler way. Take for the Multiple view as an example, the developer doesn’t need to configure anything, just put the different resource folder root that matches the view engine id. Here is the sample app demonstrate using multiple view engine in an ACT application: https://github.com/actframework/act-demo-apps/tree/master/views There are some other links you might feel interesting: 1. TechEmpower(https://www.techempower.com/benchmarks/) ACT test bed… Read more »

Back to top button