This example shows how to use the Mustache template engine as a view technology in Spring MVC (versions before 6.0). Mustache is a logic-less template language: templates contain only tags that are filled in from the model, and no embedded code.
Why Spring 6 and Later Needs a Different Approach
Spring Framework itself has no Mustache support, so this example relies on the third-party library mustache-spring-view, which provides a MustacheViewResolver and a view class for Spring MVC. That library has been a convenient fit for Spring 5 and earlier, but it cannot be used with newer Spring versions:
- Spring Framework 6.0 moved from the
javax.* namespace to jakarta.* (Jakarta EE 9+), and Spring Framework 7 builds on Jakarta EE 11 (Servlet 6.1).
mustache-spring-view extends Spring's view classes and uses the servlet API in their method signatures, so it is compiled against javax.servlet. It has not been migrated to the Jakarta namespace, and its last release was 1.4 in November 2016.
- On Spring 6 or later, the old
javax.servlet classes are not on the classpath and the Jakarta types do not match, so the library fails at runtime (for example with ClassNotFoundException: javax.servlet.http.HttpServletRequest). Because the library is no longer maintained, it is not officially supported on these versions, and there is no compatible release to upgrade to.
With Spring 6 and later, use the Mustache engine directly and write a small view class on top of it (a subclass of AbstractTemplateView), or use Spring Boot's Mustache starter. Check out this Spring MVC tutorial and this Spring Boot tutorial.
Example
pom.xml<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.9.5</version>
</dependency>
<dependency>
<groupId>com.github.sps.mustache</groupId>
<artifactId>mustache-spring-view</artifactId>
<version>1.4</version>
</dependency>
CurrencyRate
package com.logicbig.example;
import java.math.BigDecimal;
import java.time.LocalDateTime;
public class CurrencyRate {
private String currencyPair;
private LocalDateTime dateTime;
private BigDecimal askPrice;
private BigDecimal bidPrice;
.............
}
CurrencyRateController
package com.logicbig.example;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Currency;
import java.util.List;
@Controller
@RequestMapping("/")
public class CurrencyRateController {
@RequestMapping
public String handleRequest(Model model) {
model.addAttribute("todayCurrencyRates", getTodayForexRates());
return "forex-view";
}
private List<CurrencyRate> getTodayForexRates() {
// dummy rates
List<CurrencyRate> currencyRates = new ArrayList<>();
LocalDateTime today = LocalDateTime.of(2026, 2, 1, 0, 0, 0);
List<Currency> currencies = new ArrayList<>(Currency.getAvailableCurrencies());
int size = currencies.size();
size = Math.min(size, 10);
for (int i = 0; i + 1 < size; i += 2) {
String currencyPair = currencies.get(i) + "/" + currencies.get(i + 1);
CurrencyRate cr = new CurrencyRate();
cr.setCurrencyPair(currencyPair);
cr.setDateTime(today);
BigDecimal bidPrice = new BigDecimal((i + 1) * 2);
bidPrice = bidPrice.setScale(3, RoundingMode.CEILING);
cr.setBidPrice(bidPrice);
BigDecimal askPrice = new BigDecimal((i + 1) * 3);
askPrice = askPrice.setScale(3, RoundingMode.CEILING);
cr.setAskPrice(askPrice);
currencyRates.add(cr);
}
return currencyRates;
}
}
MyWebConfig
package com.logicbig.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.mustache.MustacheViewResolver;
import org.springframework.web.servlet.view.mustache.java.MustacheJTemplateFactory;
@EnableWebMvc
@Configuration
@ComponentScan
public class MyWebConfig implements WebMvcConfigurer {
@Autowired
ResourceLoader resourceLoader;
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
MustacheViewResolver mustacheViewResolver = new MustacheViewResolver();
mustacheViewResolver.setPrefix("/WEB-INF/views/");
mustacheViewResolver.setSuffix(".html");
mustacheViewResolver.setCache(false);
MustacheJTemplateFactory templateFactory = new MustacheJTemplateFactory();
templateFactory.setResourceLoader(resourceLoader);
mustacheViewResolver.setTemplateFactory(templateFactory);
registry.viewResolver(mustacheViewResolver);
}
}
Running the example
To try examples, run embedded Jetty (configured in pom.xml of example project below):
mvn jetty:run
 $ curl -s "http://localhost:8080" <html> <head> <style> table { border-collapse: collapse; width:100%; } table, td, th { border: 1px solid #999; padding: 5px; } </style> </head> <body> <h2>Currency Rates</h2> <table> <thead> <tr> <th> <label>Currency Pair</label> </th> <th> <label>Bid Price</label> </th> <th> <label>Ask Price</label> </th> <th> <label>Date</label> </th> </tr> </thead> <tbody> <tr> <td> BOB/BOV </td> <td> 3.000 </td> <td> 2.000 </td> <td> 2026-02-01T00:00 </td> </tr> <tr> <td> LVL/USS </td> <td> 9.000 </td> <td> 6.000 </td> <td> 2026-02-01T00:00 </td> </tr> <tr> <td> SSP/CUC </td> <td> 15.000 </td> <td> 10.000 </td> <td> 2026-02-01T00:00 </td> </tr> <tr> <td> AFA/OMR </td> <td> 21.000 </td> <td> 14.000 </td> <td> 2026-02-01T00:00 </td> </tr> <tr> <td> XDR/VEF </td> <td> 27.000 </td> <td> 18.000 </td> <td> 2026-02-01T00:00 </td> </tr> </tbody> </table> </body> </html>
Example ProjectDependencies and Technologies Used: - spring-webmvc 5.0.0.RELEASE (Spring Web MVC)
- compiler 0.9.5 (Implementation of mustache.js for Java)
- mustache-spring-view 1.4 (a spring view for the mustache templating language http://mustache.github.com/)
- javax.servlet-api 3.0.1 (Java Servlet API)
- guava 20.0 (Guava is a suite of core and expanded libraries that include
utility classes, google's collections, io classes, and much
much more.
Guava has only one code dependency - javax.annotation,
per the JSR-305 spec. [Description from guava-20.0.pom])
- JDK 1.8
- Maven 3.9.11
|
|