DEV Community

Salad Lam
Salad Lam

Posted on

Spring MVC support using more than 1 template engine

Notice

I wrote this article and was originally published on Qiita on 16 September 2019.


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>
Enter fullscreen mode Exit fullscreen mode

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

<html>
<head>
  <title>${title}</title>
</head>
<body>
  <div>${body}</div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

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";
    }
}
Enter fullscreen mode Exit fullscreen mode

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);
            }
        }
        // ...
Enter fullscreen mode Exit fullscreen mode

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.

AWS GenAI LIVE image

How is generative AI increasing efficiency?

Join AWS GenAI LIVE! to find out how gen AI is reshaping productivity, streamlining processes, and driving innovation.

Learn more

Top comments (0)

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay