Freemarker templates for reactive applications using project Reactor
Most frameworks (Spring and Ktor) accept blocking templating mechanisms because they are heavily cached. This library provides truly non-blocking api. For details read how it works.
Advantages:
- Designed to work with project Reactor
- Uses non-blocking IO
- Resolved Mono/Flux parameters
- Provides enhanced template resolution mechanism, that supports: relative paths, scoped templates and directory index file
- Provides template separation mechanism
Add to your build.gradle
:
dependencies {
implementation "com.coditory.freemarker:freemarker-reactor:0.1.2"
}
TemplateFactory templateFactory = TemplateFactory.create();
ReactiveFreeMarkerTemplate template = templateFactory
.createTemplate("template")
.block();
Map<String, Object> params = Map.of("a",true, b, Mono.just("B"));
String result = template.process(params)
.block();
System.out.println("Result:\n"+result);
Default behavior:
- templates are resolved from classpath, under
templates
directory - templates (and all includes/imports) are cached
- templates extension is
.ftl
Sometimes it is desired to skip caches and read templates directly from project files:
TemplateFactory templateFactory = TemplateFactory.builder()
.setTemplateLoader(new FileTemplateLoader("src/main/resources/templates"))
.removeCache()
.build();
Reactive version of the <#import>
directive.
Imports collection of macros under specific namespace.
Example:
<@import "./a">
<#a.greetings user=${user}/>
<@import "./a">
- imports template "./a" as "a"<@import name="./a" ns="b">
- imports template "./a" as "b"
Parameters:
name
- points to the template (see Template Resolution)ns
- (default: derived from template file name) namespace for imported template macros
Reactive version of the <#include>
directive.
Inserts another template into current template.
Example:
<@include "./a">
- imports template "./a"<@include name="./a" parse=false required=false>
- imports optional template "./a" without interpreting
Parameters:
name
- points to the template (see Template Resolution)parse
- (default: true) if included template should be interpretedrequired
- (default: true) if included template is required
This library modifies FreeMarker template resolution mechanism. New mechanism handles relative paths , scoped templates and directory index files.
<@include "lorem">
- includeslorem.ftl
template from the base path<@include "./lorem">
- includeslorem.ftl
template relative to the template where the include was used<@include "../lorem">
- includeslorem.ftl
template relative to the template where the include was used Relative paths work with both<@include ...>
and<@import ...>
directives.
Scoped templates provide template encapsulation that work similar to java package scope. Whenever there is a template
that should not be included/imported from other directory, prefix its name with _
.
Example:
lorem/_header.ftl
- can be imported only fromlorem
directorylorem/footer.ftl
- can be imported be every other template
Imports and includes like <@include "lorem">
and <@import "lorem">
will search for lorem
and lorem/_index
.
Therefore, you can split big template files into smaller files under a single directory:
./lorem/_index.ftl
./lorem/_header.ftl
./lorem/_main.ftl
./lorem/_footer.ftl
How non-blocking templating works:
- Template Mono/Flux parameters are resolved
- Template is loaded in a non-blocking manner
- Loaded template is parsed using Freemarker library
- Template is resolved with a mocked template loader:
- All includes and imports are registered as template dependencies (no IO operation is made)
- All dependencies are resolved using non-blocking IO
- Template is resolved again until all dependencies are resolved
Until version 1.0.0
this library is under heavy development.
The API may change without backward compatibility.