1. Overview
In this article, we’ll focus on using Mustache templates for producing HTML content in Spring Boot applications.
It’s a logic-less template engine for creating dynamic content, which is popular due to its simplicity.
If you want to discover the basics, check our introduction to Mustache article.
2. Maven Dependency
To be able to use Mustache along with Spring Boot, we need to add the dedicated Spring Boot starter to our pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mustache</artifactId> </dependency>
The latest version can be found here.
3. Creating Templates
Let’s show an example and create a simple MVC application using Spring-Boot that will serve articles on a web page.
Let’s write the first template for the article contents:
<div class="starter-template"> {{#articles}} <h1>{{title}}</h1> <h3>{{publishDate}}</h3> <h3>{{author}}</h3> <p>{{body}}</p> {{/articles}} </div>
We’ll save this HTML file, say article.html, and refer it in our index.html:
<div class="container"> {{>layout/article}} </div>
Here, the layout is a sub-directory, and the article is the file name for the template file.
4. Controller
Now let’s write the controller for serving articles:
@GetMapping("/article") public ModelAndView displayArticle(Map<String, Object> model) { List<Article> articles = IntStream.range(0, 10) .mapToObj(i -> generateArticle("Article Title " + i)) .collect(Collectors.toList()); model.put("articles", articles); return new ModelAndView("index", model); }
The controller returns a list of articles to be rendered on the page. In the article template, the tag articles starting with # and ending in /, takes care of the list.
This will iterate over the model passed and render each element separately just like in an HTML table:
{{#articles}}...{{/articles}}
The generateArticle() method creates an Article instance with some random data.
Note that the keys in the Article Model, returned by the controller, should be same as that of the article template tags.
Now, let’s test our application:
@Test public void givenIndexPage_whenContainsArticle_thenTrue() { ResponseEntity<String> entity = this.restTemplate.getForEntity("/article", String.class); assertTrue(entity.getStatusCode() .equals(HttpStatus.OK)); assertTrue(entity.getBody() .contains("Article Title 0")); }
We can also test the application by deploying it with:
mvn spring-boot:run
Once deployed, we can hit localhost:8080/article, and we’ll get our articles listed:
5. Handling Default Values
In a Mustache environment, if we do not provide a value for a placeholder, the MustacheException will be thrown with a message “No method or field with name ”variable-name …”.
In order to avoid such errors it’s better to provide a default global value to all placeholders:
@Bean public Mustache.Compiler mustacheCompiler( Mustache.TemplateLoader templateLoader, Environment environment) { MustacheEnvironmentCollector collector = new MustacheEnvironmentCollector(); collector.setEnvironment(environment); return Mustache.compiler() .defaultValue("Some Default Value") .withLoader(templateLoader) .withCollector(collector); }
6. Mustache with Spring MVC
Now, let’s discuss how to integrate with Spring MVC if we decide not to use Spring Boot. First, let’s add the dependency:
<dependency> <groupId>com.github.sps.mustache</groupId> <artifactId>mustache-spring-view</artifactId> <version>1.4</version> </dependency>
The latest could be found here.
Next, we need to configure MustacheViewResolver instead of Spring’s InternalResourceViewResolver:
@Bean public ViewResolver getViewResolver(ResourceLoader resourceLoader) { MustacheViewResolver mustacheViewResolver = new MustacheViewResolver(); mustacheViewResolver.setPrefix("/WEB-INF/views/"); mustacheViewResolver.setSuffix("..mustache"); mustacheViewResolver.setCache(false); MustacheTemplateLoader mustacheTemplateLoader = new MustacheTemplateLoader(); mustacheTemplateLoader.setResourceLoader(resourceLoader); mustacheViewResolver.setTemplateLoader(mustacheTemplateLoader); return mustacheViewResolver; }
We just need to configure the suffix, where our templates are stored, prefix the extension of our templates, and the templateLoader, which will be responsible for loading templates.
7. Conclusion
In this quick tutorial, we looked at using Mustache templates with Spring Boot, rendering a collection of elements in the UI and also providing default values to variables to avoid errors.
Finally, we discussed how to integrate it with Spring, using MustacheViewResolver.
As always the source code is available over on GitHub.