Dynamic template resolver using Thymeleaf

Viewed 2813

We have a requirement to dynamically resolve html or text templates. The template content (a string) with variable place holders will be available in database.

We have to resolve them dynamically on demand with the actual values for the variables and get the final string content.

Example: (not a complete code)

String myHtmlTemplateContent = "<h1>Hi ${first_name} ${last_name}</h1>";
Map<String, Object> myMapWithValues = ..;
engine.resolve(myHtmlTemplateContent , myMapWithValues );

Will be helpful if we have a way to resolve using thymeleaf or is it possible using thymeleaf template engine.

2 Answers

You need to create a thymeleaf template mytemplate.html containing:

<h1 th:text="Hi ${first_name} ${last_name}"></h1>

and use it with a mvc controller that sets the variables in the model:

@Controller
public class HelloController {

    @GetMapping("/hello")
    public String handle(Model model) {
        model.addAttribute("first_name", "Abel");
        model.addAttribute("last_name", "Lincon");
        return "mytemplate"; //resolves to mytemplate.html
    }
}

And it will render <h1>Hi Abel Lincon</h1>

If you want to manually process a template, you could autowire the template engine and use it manually:

@Autowired SpringTemplateEngine templateEngine;

String emailContent = templateEngine.process( "mytemplate",
                        new Context( Locale.ENGLISH, Map.of(
                                "first_name", "Abel",
                                "last_name", "Lincon"
                        )) );

I have used the following approach:

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.thymeleaf.context.Context;
import java.util.Map;

public class GenericTemplateEngine {

    private final TemplateEngine templateEngine;

    public GenericTemplateEngine(TemplateMode templateMode) {

        templateEngine = new org.thymeleaf.TemplateEngine();

        ClassLoaderTemplateResolver templateResolver
                = new ClassLoaderTemplateResolver(Thread
                        .currentThread().getContextClassLoader());
        templateResolver.setTemplateMode(templateMode);
        templateResolver.setPrefix("/thymeleaf/");
        templateResolver.setCacheTTLMs(3600000L); // one hour
        templateResolver.setCacheable(true);
        this.templateEngine.setTemplateResolver(templateResolver);
    }

    public String getTemplate(String templateName, Map<String, Object> parameters) {
        Context ctx = new Context();
        if (parameters != null) {
            parameters.forEach((k, v) -> {
                ctx.setVariable(k, v);
            });
        }
        return this.templateEngine.process(templateName, ctx).trim();
    }

}

This can then be called as follows for HTML templates:

HashMap<String, Object> values = new HashMap<>();
values.put("hello", "hello everyone");
GenericTemplateEngine engine = new GenericTemplateEngine(TemplateMode.HTML);
String s = engine.getTemplate("hello_world.html", values);
System.out.println(s);

The values in the Map are loaded into the Thymeleaf context, and then passed, along with a template, to the engine class.

If you have a text template instead of an HTML template, then you would use the following:

new GenericTemplateEngine(TemplateMode.TEXT);
Related