Help us understand the problem. What is going on with this article?

Spring MVC support using more than 1 template engine

Example

In this example, extra FreeMarker template engine is added into Spring MVC project using Thymeleaf template engine. A 'hello world' page is displayed using this new added engine.

First get a copy of my notice board example application. Add following line into pom.xml to include FreeMarker template engine into project.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

Add a FreeMarker template, as 'resources/templates/public/freemarker_test.ftl'.

<html>
<head>
  <title>${title}</title>
</head>
<body>
  <div>${body}</div>
</body>
</html>

Add a new function into info.saladlam.example.spring.noticeboard.controller.PublicController controller.

public class PublicController {
    // ...
    @GetMapping("/freemarker_test")

    public String freemarkerTest(Model model) {
        model.addAttribute("title", "FreeMarker test page");
        model.addAttribute("body", "Hello world!");

        return "public/freemarker_test";
    }
}

Start application and in browser to open http://localhost:8080/freemarker_test. As result 'Hello world!' is show.

# What happen behind?

When application started. Following org.springframework.web.servlet.ViewResolver bean is created by Spring Boot.
- org.thymeleaf.spring5.view.ThymeleafViewResolver
- org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver

org.springframework.web.servlet.DispatcherServlet instance is created. During initialization, method initViewResolvers() is called.

        if (this.detectAllViewResolvers) {
            // Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
            Map<String, ViewResolver> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.viewResolvers = new ArrayList<>(matchingBeans.values());
                // We keep ViewResolvers in sorted order.
                AnnotationAwareOrderComparator.sort(this.viewResolvers);
            }
        }
        // ...

Code listed above shows that all bean with ViewResolver interface is provided by BeanFactory.

When method freemarkerTest() in PublicController being called, string 'public/freemarker_test' is return. This string will pass into org.thymeleaf.spring5.view.ThymeleafViewResolver. Since no Thymeleaf template withi this name is defined, so null is returned. Then pass into org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver and instance with org.springframework.web.servlet.View interface is returned.

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away