DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Getting Started With Thymeleaf In Spring Boot
  • Introduction to Spring Boot and JDBCTemplate: JDBC Template
  • Running Spring Boot Application With Embedded Camunda Engine
  • JobRunr and Spring Data

Trending

  • Teradata Performance and Skew Prevention Tips
  • Java 23 Features: A Deep Dive Into the Newest Enhancements
  • How to Build Local LLM RAG Apps With Ollama, DeepSeek-R1, and SingleStore
  • Segmentation Violation and How Rust Helps Overcome It
  1. DZone
  2. Coding
  3. Frameworks
  4. A Review of Template Engines: What Next After Velocity?

A Review of Template Engines: What Next After Velocity?

With Velocity deprecated, let's take a walk through some other popular template engines to see what works best where.

By 
Miro Wengner user avatar
Miro Wengner
·
Nov. 28, 16 · Opinion
Likes (7)
Comment
Save
Tweet
Share
81.0K Views

Join the DZone community and get the full member experience.

Join For Free

Let’s dive into the Template engine problems of MVC based frameworks.

This post will shed light on the mystery of different templating possibilities supported by the Spring Boot framework.

Spring Boot has become very popular because of its configuration abilities and full support of Spring-based applications. Spring Boot follows the simple motto of “Just run” — wait a sec, no, it’s not Nike. In the age of microservices and dissecting monoliths, this motto has quite a nice impact on the desired prototyping application.

I don’t think there is any need to go much deeper into the Model View Controller (MVC) design pattern issue because there are many other articles that do just that. My main intent is to review the setups of different Java template engines for Spring-based applications. How can such a question even arise?

Well, the reason is that the Velocity Engine has been deprecated for a while, and a lot of developers around the world need to find well-fitting alternatives.

Let’s begin and define the set for our test. We will compare the following engines:

  1. Apache Velocity
  2. Apache FreeMarker
  3. Thymeleaf
  4. Pebble

I have not included JSP Engine because JSPs are mature technologies and have been around since the early days, which means that many articles have been already written about it. The fact that JSPs are really hard to beat in raw speed is true, but that's not in the focus here.

First, let's prepare a MvcConfiguration class, which extends WebMvcConfigurerAdapter:

@Configuration
@EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter {
...

The mentioned MvcConfiguration class must define @BeanViewResolver, which can negotiate about the proper request ViewResolver.

@Bean(name = "viewResolver")
public ViewResolver contentNegotiatingViewResolver( ContentNegotiationManager manager) {
        List resolvers = ...

Each of the mentioned template engines have, under the folder webapp, its own directory dedicated only to it. Such a directory (velocity, freemarker, thymeleaf, and pebble) contains only engine-related files.

And here is the deprecated engine that has been widely used over last several years.

Apache Velocity

The Apache Velocity Template Engine is used for comparison and to make testing other the other three alternatives (FreeMarker, Thymeleaf, and Pebble) a little bit simpler. Apache Velocity is one of the Jakarta projects. Each of the Velocity templates is processed, but not compiled to Java, which supports better code separation.

The following code snippets configure Spring Boot ViewResolver and enable Velocity usage:

@Bean(name = "velocityViewResolver")
public ViewResolver getVelocityViewResolver() {
   VelocityViewResolver resolver = new VelocityViewResolver();
   resolver.setSuffix(".vm");
   resolver.setCache(true);
   return resolver;
}

Having configured ViewResolver, we need to add it to the contentNegotiatingViewResolver@Bean, which gives us the access to the ContentNegotiationManager. The ContentNegotiationManager provides look-up methods to the file extensions based on MediaType. In our example case, it will be used for a specific engine file suffix search:

@Bean(name = "viewResolver")
public ViewResolver contentNegotiatingViewResolver( ContentNegotiationManager manager) {
   List resolvers =
      Arrays.asList(getVelocityViewResolver(),
      ...

Inside the directory webapp, we create the directory velocity and a simple velocity template. We call the file test.vm and it contains the following content:

<html lang="en">
<head>
   <title>Test Velocity</title>
</head>
<body>
<h2>This is $test</h2>
</body>
</html>

We are almost done. There is only one more important thing. For setting up specific Spring Boot application properties, we'll need to use a configuration file called application.properties — located inside the project's resources folder. For Velocity, it will contain the loader path setup (You can customize it).

spring.velocity.resourceLoaderPath=/velocity/

Congratulations!

The deprecated template engine Velocity is up and running, but this is not all what we want to achieve, so we'll continue with the next alternative.

Apache FreeMarker

Our first candidate is FreeMarker. FreeMarker is currently coming from the Apache project's incubator, supported by the Apache Software Foundation (ASF). ASF puts its effort to support FreeMarker development, which is a very good sign for a long life. One more reason may be that FreeMarker is widely used across Apache projects — a good example is the newly accepted NetBeans!

Let’s add FM support to our sample project by configuring ViewResolver in the following way:

@Bean(name = "freeMarkerViewResolver")
public ViewResolver getFreeMakerViewResolver() {
   FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
   resolver.setSuffix(".ftl");
   resolver.setCache(true);
   return resolver;
}

We also need to properly add FreeMarker ViewResolver to the ContentNegotiationManager inside the MvcConfiguration@Bean:

@Bean(name = "viewResolver")
public ViewResolver contentNegotiatingViewResolver( ContentNegotiationManager manager) {
   List resolvers =
      Arrays.asList(getVelocityViewResolver(),
                    getFreeMakerViewResolver(),
                    ...

Now the sample application is ready for the simple FreeMarker templates. Inside the webapp folder, we a create new folder called freemarker and add the following two files: First...

Index.ftl

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test applicaiton</title>
</head>
<body>
<h2>This is test application Main sample site</h2>
</body>
</html>

... and magic.ftl, which will contain simple FM tags:

Magic.ftl

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Magic Spell: ${word}!</title>
</head>
<body>
<h2>MagicHappens by word: ${word}!</h2>
</body>
</html>

But hold on, that's not all. We cannot forget to properly add a configuration inside the application.properties file:

spring.freemarker.templateLoaderPath=/freemarker/

Now we have FreeMarker up and running inside our sample project! Well done, and we can move to the next one.

Pebble Template Engine

It’s a new player on the market. It promises useful inheritance features and "easy-to-read" syntax, but those are beyond the scope of this article. This article is focused on ViewResolver's configuration and having it up and running. First, we again need to configure ViewResolver properly. With Pebble, it's slightly more complicated because the result of the configuration is extremely closely connected to the Servlet config itself. So, we go back into @BeanMvcConfiguration and add:

@Bean(name="pebbleViewResolver")
public ViewResolver getPebbleViewResolver(){
   PebbleViewResolver resolver = new PebbleViewResolver();
   resolver.setPrefix("/pebble/");
   resolver.setSuffix(".html");
   resolver.setPebbleEngine(pebbleEngine());
   return resolver;
}

As previously mentioned, that template may support configuration by application.properties. Unfortunately, this is currently not the case of Pebble. We need to configure it all manually, and we need to define more Pebble-related @Beans

@Bean
public PebbleEngine pebbleEngine() {
  return new PebbleEngine.Builder()
                .loader(this.templatePebbleLoader())
                .extension(pebbleSpringExtension())
                .build();
}

@Bean
public Loader templatePebbleLoader(){
   return new ServletLoader(servletContext);
}

@Bean
public SpringExtension pebbleSpringExtension() {
  return new SpringExtension();
}

As you can see, the templatePebbleLoader @Bean requires direct access to the ServletContext, which needs to be injected into the configuration @Bean.

@Autowired
private ServletContext servletContext;
...


It also means that by doing this, Pebble takes over the created servlet and will play your default choice when any other exists. This may not be bad, but when you want to use Pebble and, for example, Thymeleaf together, you need to do slightly more Spring hacking.

Now we have prepared the Pebble configuration, so let’s create a new Pebble folder under the webapp and add a new template file — pebble.html

<html>
<head>
    <title>{{ pebble }}</title>
</head>
<body>
{{ pebble }}
</body>
</html>

Now we are finished! Pebble is up and running and we can go directly to the last option.

Thymeleaf Template Engine

Thymeleaf presents itself as the ideal choice for HTML5 JVM web development. It might be true, but again, that's beyond the scope of this article, though you can examine this claim by using my example project over at my GitHub account. Thymeleaf has better Spring support than Pebble. This allows us to use the application.properties file for its configuration and add Thymeleaf setup options there:

spring.thymeleaf.prefix=/thymeleaf/
spring.thymeleaf.suffix=.html

But the rest is very similar to Pebble.

@Bean(name = "thymeleafViewResolver")
public ViewResolver getThymeleafViewResolver() {
  ThymeleafViewResolver resolver = new ThymeleafViewResolver();
  resolver.setTemplateEngine(getThymeleafTemplateEngine());
  resolver.setCache(true);
  return resolver;
}

Thymeleaf similarly takes control over any new Servlet, as you can see in MvcConfiguration@Bean.

@Bean(name ="thymeleafTemplateEngine")
public SpringTemplateEngine getThymeleafTemplateEngine() {
  SpringTemplateEngine templateEngine = new SpringTemplateEngine();
  templateEngine.setTemplateResolver(getThymeleafTemplateResolver());
  return templateEngine;
}

@Bean(name ="thymeleafTemplateResolver")
public ServletContextTemplateResolver getThymeleafTemplateResolver() {
  ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
  templateResolver.setPrefix("/thymeleaf/");
  templateResolver.setSuffix(".htm");
  return templateResolver;
}

Now it’s time to add ViewResolver to the content negotiation configuration:

@Bean(name = "viewResolver")
public ViewResolver contentNegotiatingViewResolver( ContentNegotiationManager manager) {
   List resolvers =
      Arrays.asList(getVelocityViewResolver(),
                    getFreeMakerViewResolver(),
//                  getPebbleViewResolver()
                    getThymeleafViewResolver()
                );
      ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
      resolver.setViewResolvers(resolvers);
      resolver.setContentNegotiationManager(manager);
      return resolver;
}
...

As our last step, we will create, under the webapp folder, a new folder called thymeleaf and add the thyme.html file there:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Getting Started: Thymeleaf</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'HERE IS, ' + ${thyme} + '!'" />
</body>
</htm>

Congratulations! You have successfully configured all four Spring Boot supported template engines.

At the end of the configuration section, it is important to point out that each of the engines has assigned its own @Controller, which is responsible for proper output generation:

Velocity Controller

@Controller
public class VelocityHelloController {

    @RequestMapping(value = "/velocity")
    public String test(Model model){
        System.out.println("Test");
        model.addAttribute("test", "Here is Velocity");
        return "test";
    }
}

FrameMarker

@Controller
public class FMHelloController {


    @RequestMapping("/")
    public String index(){
        System.out.println("INDEX");
        return "index";
    }

    @RequestMapping("/magic")
    public String magic(Model model, @RequestParam(value = "word", required=false, defaultValue="MagicHappens") String word) {
        System.out.println("MAGIC");
        model.addAttribute("word", word);
        return "magic";
    }
}

Pebble

@Controller
public class PebbleHelloController {

    @RequestMapping(value = "/pebble")
    public String something(Model model){
        System.out.println("Pebble");
        model.addAttribute("pebble", "The Pebble");
        return "pebble";
    }
}

Thymeleaf

@Controller
public class TLHelloController {
    @RequestMapping(value = "/thyme")
    public String something(Model model){
        System.out.println("Thymeleaf");
        model.addAttribute("thyme", "The Thymeleaf");
        return "thyme";
    }
}

Experiences and Summary

Now is the right time to write a few final words about the possibilities we covered today. I don’t want to highlight any of those tested choices as the best replacement to the deprecated Velocity template engine, but from my configuration experiences and Spring framework support, I’d choose FrameMarker. By Choosing FreeMarker I won’t be limited to using Velocity and any other options in parallel, but as has been mentioned before, making the right choice is beyond the scope of this article.

I have created a sample gradle project that imports all the temple engine starters. This setup can be found inside the configuration file build.gradle

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-freemarker:$springBootVersion")
    compile("org.springframework.boot:spring-boot-starter-velocity:$springBootVersion")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion")
    compile("com.mitchellbosecke:pebble-spring-boot-starter:$pebbleVersion")
    testCompile "junit:junit:${junitVersion}"
}

Enjoy the sample project in testing your choice!

GitHub

used versions:
Java JDK: 1.8.111
Spring-Boot:  1.4.1.RELEASE
Pebble: 2.2.3

GitHub Sample Project

Engine Template Velocity (JavaScript library) Spring Framework Spring Boot FreeMarker Apache Velocity Thymeleaf application

Published at DZone with permission of Miro Wengner. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Getting Started With Thymeleaf In Spring Boot
  • Introduction to Spring Boot and JDBCTemplate: JDBC Template
  • Running Spring Boot Application With Embedded Camunda Engine
  • JobRunr and Spring Data

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!