1. Overview
All MVC frameworks provide a way of working with views.
Spring does that via the view resolvers, which enable you to render models in the browser without tying the implementation to a specific view technology.
The ViewResolver maps view names to actual views.
And the Spring framework comes with quite a few view resolvers e.g. InternalResourceViewResolver, BeanNameViewResolver, and a few others.
This is a simple tutorial showing how to set up the most common view resolvers and how to use multiple ViewResolver in the same configuration.
2. The Spring Web Configuration
Let’s start with the web configuration; we’ll annotate it with @EnableWebMvc, @Configuration and @ComponentScan:
@EnableWebMvc
@Configuration
@ComponentScan("com.baeldung.web")
public class WebConfig implements WebMvcConfigurer {
// All web configuration will go here
}
It’s here that we’ll set up our view resolver in the configuration.
3. Add an InternalResourceViewResolver
This ViewResolver allows us to set properties such as prefix or suffix to the view name to generate the final view page URL:
@Bean
public ViewResolver internalResourceViewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setViewClass(JstlView.class);
bean.setPrefix("/WEB-INF/view/");
bean.setSuffix(".jsp");
return bean;
}
For such simplicity of the example, we don’t need a controller to process the request.
We only need a simple jsp page, placed in the /WEB-INF/view folder as defined in the configuration:
<html>
<head></head>
<body>
<h1>This is the body of the sample view</h1>
</body>
</html>
4. Add a BeanNameViewResolver
This is an implementation of ViewResovler that interprets a view name as a bean name in the current application context. Each such View
can be defined as a bean in XML or Java configurations.
First, we add the BeanNameViewResolver to the previous configuration:
@Bean
public BeanNameViewResolver beanNameViewResolver(){
return new BeanNameViewResolver();
}
Once the ViewResolver is defined we need to define beans of the type View so that it can be executed by DispatcherServlet to render the view:
@Bean
public View sample() {
return new JstlView("/WEB-INF/view/sample.jsp");
}
Here is the corresponding handler method from the controller class:
@GetMapping("/sample")
public String showForm() {
return "sample";
}
From the controller method, the view name is returned as “sample” which means the view from this handler method resolves to JstlView class with /WEB-INF/view/sample.jsp
URL.
5. Chaining ViewResolvers and Define an Order Priority
Spring MVC also supports multiple view resolvers.
This allow you to override specific views in some circumstances. We can simply chain view resolvers by adding more than one resolver to the configuration.
Once we’ve done that, we’ll need to define an order for these resolvers. The order property is used to define which is the order of invocations in the chain. The higher the order property (largest order number), the later the view resolver is positioned in the chain.
To define the order we can add the follow line of code to the configuration of the our view resolvers:
bean.setOrder(0);
Be careful on the order priority as the InternalResourceViewResolver should have a higher order – because it’s intended to represent a very explicit mapping. And if other resolvers have a higher order, then the InternalResourceViewResolver might never be invoked.
6. Using Spring Boot
When working with Spring Boot, the WebMvcAutoConfiguration automatically configures InternalResourceViewResolver and BeanNameViewResolver beans in our application context*.*
Also, adding the corresponding starter for the templating engine takes away much of the manual configuration we have to do otherwise.
For example, by adding spring-boot-starter-thymeleaf dependency to our pom.xml, Thymeleaf gets enabled, and no extra configuration is necessary:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>${spring-boot-starter-thymeleaf.version}</version>
</dependency>
This starter dependency configures ThymeleafViewResolver bean with the name thymeleafViewResolver in our application context. We can override the auto-configured ThymeleafViewResolver by providing a bean of the same name.
Thymeleaf view resolver works by surrounding the view name with a prefix and suffix. The default values of prefix and suffix are ‘classpath:/templates/’ and ‘.html’, respectively.
Spring Boot also provides an option to change the default value of prefix and suffix by setting spring.thymeleaf.prefix
and spring.thymeleaf.suffix
properties respectively.
Similarly, we have starter dependencies for groovy-templates, freemarker, and mustache template engines which we can use to get the corresponding view resolvers auto-configured using Spring Boot.
DispatcherServlet uses all the view resolvers it finds in the application context and tries each one until it gets a result and hence the ordering of these view resolvers becomes very important if we plan to add our own.
7. Conclusion
In this tutorial we configured a chain of view resolvers using Java configuration. By playing with the order priority we can set the order of their invocation.
The implementation of this simple tutorial can be found in the github project.