Spring MVC - Auto translation of view name

[Updated: Jan 13, 2017, Created: Jan 12, 2017]

An explicit view name should normally be returned from a controller's handler method, but we can instead take advantage of auto name resolution provided by an implementation of RequestToViewNameTranslator.

java.lang.ObjectObjectorg.springframework.web.servlet.view.DefaultRequestToViewNameTranslatorDefaultRequestToViewNameTranslatororg.springframework.web.servlet.RequestToViewNameTranslatorRequestToViewNameTranslatorLogicBig

The strategy interface RequestToViewNameTranslator is capable of translating an incoming HttpServletRequest into a logical view name when no view name is explicitly returned from the controller. It has only one method

package org.springframework.web.servlet;
 ...
public interface RequestToViewNameTranslator {

   String getViewName(HttpServletRequest request) throws Exception;

}

Spring has only one implementation of this interface, DefaultRequestToViewNameTranslator, which transforms the request URI into a view name. It has following configurable properties:

prefix: A String which prepends to generated view name.

suffix: A String which appends to generated view name.

separator: A String which separates URI parts. By default "/" is left unmodified.

stripLeadingSlash: A boolean which specifies whether beginning slash should be removed, default is true

stripTrailingSlash: A boolean which specifies whether ending slash should be removed, default is true.

stripExtension: A boolean which specifies whether file extension should be removed, default is true.



To take advantage of this feature, we don't have to do any configuration, DispatcherServlet by default internally uses an instance of this class with following properties.

prefix = ""
suffix = ""
separator = "/"
stripLeadingSlash = true
stripTrailingSlash = true
stripExtension = true


Example

The Controller

Following handler methods don't return view name.

@Controller
public class ExampleController {
    @RequestMapping({"page1"})
    public void handle (Model model) {
        model.addAttribute("msg", "a msg from handler1");
    }

    @RequestMapping("data/page2")
    public void handle2 (Model model) {
        model.addAttribute("msg", "a msg from handler2");
    }
}

src/main/webapp/WEB-INF/views/page1.jsp

 ...
<html>
 <body>
   <h3>Page 1</h3>
   ${msg}
 </body>
</html>

src/main/webapp/WEB-INF/views/data/page2.jsp

...
<html>
 <body>
   <h3>Page 2</h3>
   ${msg}
 </body>
</html>

src/main/resources/application.properties

spring.mvc.view.prefix= /WEB-INF/views/
spring.mvc.view.suffix= .jsp

The main class:

@SpringBootApplication
public class Main {
    public static void main (String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

Run application

mvn spring-boot:run

Output




Using an extension with the url will also work:



Note that all extension will work except for .jsp



Why I can't access files with JSP extension?

The reason of the above 404 error is: the servlet container will map all requests ending with .jsp to an internal JSP Servlet (in case of tomcat: org.apache.jasper.servlet.JspServlet) and Spring's DispatcherServlet will not be invoked. This behavior is in compliance with Servlet specifications.

Servlet 3.1 specs:

12.2.1 Implicit Mappings

If the container has an internal JSP container, the *.jsp extension is mapped to it, allowing JSP pages to be executed on demand. This mapping is termed an implicit mapping. If a *.jsp mapping is defined by the Web application, its mapping takes precedence over the implicit mapping.



Specs allows application to do explicit mapping for .jsp, but it should be avoided.

According to the specs, default jsp servlet looks for a requested .jsp file directly in a public folders without routing through application defined servlets like DispatcherServlet.

From Servlet 3.1 specs 10.5:

Most of the WEB-INF node is not part of the public document tree of the application. Except for static resources and JSPs packaged in the META-INF/resources of a JAR file that resides in the WEB-INF/lib directory, no other files contained in the WEB-INF directory may be served directly to a client by the container. However, the contents of the WEB-INF directory are visible to servlet code ...


In our example, if we put a jsp file outside of WEB-INF, then we can access the page directly without 404 error, Spring's DispatcherServlet and hence our handlers will not be invoked.

src/main/webapp/page3.jsp

....
<html>
 <body>
   <h3>Page 3</h3>
   <p>This page is outside WEB-INF</p>
   ${msg}
 </body>
</html>

Note that ${msg} is not substituted with it's value because none of the handler methods invoked.



Customized use of DefaultRequestToViewNameTranslator

We can customize the default use of DefaultRequestToViewNameTranslator by registering it as a bean and set the desired properties:

@SpringBootApplication
public class Main {
  ....

    @Bean
    public RequestToViewNameTranslator viewNameTranslator () {
        DefaultRequestToViewNameTranslator translator =
                  new DefaultRequestToViewNameTranslator();
        translator.setPrefix("app-");
        translator.setSuffix("-data");
        return translator;
    }
}

src/main/webapp/WEB-INF/views/app-page1-data.jsp

.....
<html>
 <body>
   <h3>App Page 1 Data</h3>
   ${msg}
 </body>
</html>

There are no changes with the controller.

Run plugin:

mvn spring-boot:run

Output





Example Project

Dependencies and Technologies Used :

  • spring-boot-starter-web 1.4.3.RELEASE: Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container.
    Corresponding Spring version: 4.3.5.RELEASE
  • tomcat-embed-jasper 8.5.6: Core Tomcat implementation.
  • JDK 1.8
  • Maven 3.3.9

View Name Translation Example Select All Download
  • view-name-translator
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
        • webapp
          • WEB-INF
            • views
              • data

See Also