0
# FreeMarker Templates
1
2
Spring Context Support provides comprehensive FreeMarker template engine integration for server-side rendering. It offers factory beans for configuration, utilities for template processing, and Spring Resource-based template loading for both web and non-web contexts.
3
4
## Capabilities
5
6
### FreeMarker Configuration Factory
7
8
Factory for creating and configuring FreeMarker Configuration instances with Spring integration.
9
10
```java { .api }
11
/**
12
* Factory for creating FreeMarker Configuration instances with Spring integration
13
*/
14
public class FreeMarkerConfigurationFactory {
15
16
/**
17
* Set the location of the FreeMarker config file
18
* @param resource the config file resource
19
*/
20
public void setConfigLocation(Resource resource);
21
22
/**
23
* Set FreeMarker settings as Properties
24
* @param settings the FreeMarker settings
25
*/
26
public void setFreemarkerSettings(Properties settings);
27
28
/**
29
* Set FreeMarker variables (objects available in all templates)
30
* @param variables map of variable names to objects
31
*/
32
public void setFreemarkerVariables(Map<String, Object> variables);
33
34
/**
35
* Set the default encoding for templates
36
* @param defaultEncoding the default encoding (e.g., "UTF-8")
37
*/
38
public void setDefaultEncoding(String defaultEncoding);
39
40
/**
41
* Set the default charset for templates
42
* @param defaultCharset the default charset
43
*/
44
public void setDefaultCharset(Charset defaultCharset);
45
46
/**
47
* Set template loaders that will be used before default loaders
48
* @param preTemplateLoaders template loaders to register first
49
*/
50
public void setPreTemplateLoaders(TemplateLoader... preTemplateLoaders);
51
52
/**
53
* Set template loaders that will be used after default loaders
54
* @param postTemplateLoaders template loaders to register last
55
*/
56
public void setPostTemplateLoaders(TemplateLoader... postTemplateLoaders);
57
58
/**
59
* Set the template loader path (single path)
60
* @param templateLoaderPath the template loader path
61
*/
62
public void setTemplateLoaderPath(String templateLoaderPath);
63
64
/**
65
* Set multiple template loader paths
66
* @param templateLoaderPaths array of template loader paths
67
*/
68
public void setTemplateLoaderPaths(String... templateLoaderPaths);
69
70
/**
71
* Set the ResourceLoader for template loading
72
* @param resourceLoader the ResourceLoader to use
73
*/
74
public void setResourceLoader(ResourceLoader resourceLoader);
75
76
/**
77
* Set whether to prefer file system access for template loading
78
* @param preferFileSystemAccess whether to prefer file system access
79
*/
80
public void setPreferFileSystemAccess(boolean preferFileSystemAccess);
81
82
/**
83
* Create the FreeMarker Configuration instance
84
* @return the configured Configuration
85
* @throws IOException if configuration fails
86
* @throws TemplateException if template configuration fails
87
*/
88
public Configuration createConfiguration() throws IOException, TemplateException;
89
90
/**
91
* Get the ResourceLoader (available after ApplicationContext injection)
92
* @return the ResourceLoader
93
*/
94
protected ResourceLoader getResourceLoader();
95
}
96
```
97
98
**Usage Examples:**
99
100
```java
101
@Configuration
102
public class FreeMarkerConfig {
103
104
@Bean
105
public FreeMarkerConfigurationFactory freeMarkerConfigurationFactory() {
106
FreeMarkerConfigurationFactory factory = new FreeMarkerConfigurationFactory();
107
factory.setTemplateLoaderPaths(
108
"classpath:/templates/",
109
"file:/opt/app/templates/"
110
);
111
factory.setDefaultEncoding("UTF-8");
112
113
Properties settings = new Properties();
114
settings.setProperty("number_format", "0.##");
115
settings.setProperty("date_format", "yyyy-MM-dd");
116
settings.setProperty("time_format", "HH:mm:ss");
117
settings.setProperty("datetime_format", "yyyy-MM-dd HH:mm:ss");
118
factory.setFreemarkerSettings(settings);
119
120
// Global variables available in all templates
121
Map<String, Object> variables = new HashMap<>();
122
variables.put("app", applicationProperties);
123
variables.put("utils", templateUtils);
124
factory.setFreemarkerVariables(variables);
125
126
return factory;
127
}
128
129
@Bean
130
public Configuration freeMarkerConfiguration() throws Exception {
131
return freeMarkerConfigurationFactory().createConfiguration();
132
}
133
}
134
```
135
136
### FreeMarker Configuration Factory Bean
137
138
FactoryBean wrapper around FreeMarkerConfigurationFactory for easier Spring integration.
139
140
```java { .api }
141
/**
142
* FactoryBean wrapper around FreeMarkerConfigurationFactory
143
*/
144
public class FreeMarkerConfigurationFactoryBean extends FreeMarkerConfigurationFactory
145
implements FactoryBean<Configuration>, InitializingBean, ResourceLoaderAware {
146
147
/**
148
* Get the FreeMarker Configuration instance
149
* @return the Configuration instance
150
* @throws Exception if creation fails
151
*/
152
@Override
153
public Configuration getObject() throws Exception;
154
155
/**
156
* Get the object type
157
* @return Configuration.class
158
*/
159
@Override
160
public Class<Configuration> getObjectType();
161
162
/**
163
* Check if this factory returns singletons
164
* @return true (singleton)
165
*/
166
@Override
167
public boolean isSingleton();
168
169
/**
170
* Initialize the factory bean
171
* @throws IOException if initialization fails
172
* @throws TemplateException if template configuration fails
173
*/
174
@Override
175
public void afterPropertiesSet() throws IOException, TemplateException;
176
177
/**
178
* Set the ResourceLoader for template loading
179
* @param resourceLoader the ResourceLoader
180
*/
181
@Override
182
public void setResourceLoader(ResourceLoader resourceLoader);
183
}
184
```
185
186
**Usage Examples:**
187
188
```java
189
@Configuration
190
public class FreeMarkerFactoryBeanConfig {
191
192
@Bean
193
public FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean() {
194
FreeMarkerConfigurationFactoryBean factoryBean = new FreeMarkerConfigurationFactoryBean();
195
factoryBean.setTemplateLoaderPath("classpath:/templates/");
196
factoryBean.setDefaultEncoding("UTF-8");
197
198
Properties settings = new Properties();
199
settings.setProperty("template_update_delay", "0"); // Development setting
200
settings.setProperty("default_encoding", "UTF-8");
201
settings.setProperty("output_encoding", "UTF-8");
202
settings.setProperty("locale", "en_US");
203
factoryBean.setFreemarkerSettings(settings);
204
205
return factoryBean;
206
}
207
}
208
```
209
210
### Template Processing Utilities
211
212
Utility methods for processing FreeMarker templates in various contexts.
213
214
```java { .api }
215
/**
216
* Utility methods for processing FreeMarker templates
217
*/
218
public abstract class FreeMarkerTemplateUtils {
219
220
/**
221
* Process a FreeMarker template into a String
222
* @param template the FreeMarker Template
223
* @param model the template model (data)
224
* @return the processed template as String
225
* @throws IOException if template processing fails
226
* @throws TemplateException if template has errors
227
*/
228
public static String processTemplateIntoString(Template template, Object model)
229
throws IOException, TemplateException;
230
}
231
```
232
233
**Usage Examples:**
234
235
```java
236
@Service
237
public class ReportService {
238
239
@Autowired
240
private Configuration freeMarkerConfiguration;
241
242
public String generateReport(String templateName, Map<String, Object> data) {
243
try {
244
Template template = freeMarkerConfiguration.getTemplate(templateName + ".ftl");
245
return FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
246
} catch (IOException | TemplateException e) {
247
throw new RuntimeException("Failed to generate report", e);
248
}
249
}
250
251
public String generateLocalizedReport(String templateName, Map<String, Object> data, Locale locale) {
252
try {
253
Template template = freeMarkerConfiguration.getTemplate(templateName + ".ftl", locale);
254
return FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
255
} catch (IOException | TemplateException e) {
256
throw new RuntimeException("Failed to generate localized report", e);
257
}
258
}
259
}
260
261
@RestController
262
public class TemplateController {
263
264
@Autowired
265
private ReportService reportService;
266
267
@GetMapping("/reports/{type}")
268
public ResponseEntity<String> generateReport(@PathVariable String type) {
269
Map<String, Object> data = new HashMap<>();
270
data.put("reportDate", new Date());
271
data.put("title", "Monthly Report");
272
data.put("items", getReportItems());
273
274
String html = reportService.generateReport(type, data);
275
276
return ResponseEntity.ok()
277
.contentType(MediaType.TEXT_HTML)
278
.body(html);
279
}
280
}
281
```
282
283
### Spring Template Loader
284
285
FreeMarker TemplateLoader implementation that loads templates from Spring Resource locations.
286
287
```java { .api }
288
/**
289
* FreeMarker TemplateLoader that loads templates from Spring Resource locations
290
*/
291
public class SpringTemplateLoader implements TemplateLoader {
292
293
/**
294
* Create a SpringTemplateLoader with a ResourceLoader and template path
295
* @param resourceLoader the ResourceLoader to use
296
* @param templateLoaderPath the base path for templates
297
*/
298
public SpringTemplateLoader(ResourceLoader resourceLoader, String templateLoaderPath);
299
300
/**
301
* Find a template source
302
* @param name the template name
303
* @return the template source object
304
* @throws IOException if template loading fails
305
*/
306
@Override
307
public Object findTemplateSource(String name) throws IOException;
308
309
/**
310
* Get the last modified time of a template
311
* @param templateSource the template source
312
* @return the last modified time
313
*/
314
@Override
315
public long getLastModified(Object templateSource);
316
317
/**
318
* Get a Reader for the template content
319
* @param templateSource the template source
320
* @param encoding the character encoding
321
* @return a Reader for the template
322
* @throws IOException if reading fails
323
*/
324
@Override
325
public Reader getReader(Object templateSource, String encoding) throws IOException;
326
327
/**
328
* Close a template source
329
* @param templateSource the template source to close
330
* @throws IOException if closing fails
331
*/
332
@Override
333
public void closeTemplateSource(Object templateSource) throws IOException;
334
}
335
```
336
337
### Advanced Configuration Examples
338
339
Complete configuration examples for different use cases.
340
341
```java
342
@Configuration
343
public class AdvancedFreeMarkerConfig {
344
345
/**
346
* Configuration for web applications with multiple template locations
347
*/
348
@Bean
349
@Profile("web")
350
public FreeMarkerConfigurationFactoryBean webFreeMarkerConfig() {
351
FreeMarkerConfigurationFactoryBean factoryBean = new FreeMarkerConfigurationFactoryBean();
352
353
// Multiple template locations
354
factoryBean.setTemplateLoaderPaths(
355
"classpath:/templates/", // Built-in templates
356
"classpath:/templates/mail/", // Email templates
357
"file:/opt/app/custom-templates/" // Custom templates
358
);
359
360
factoryBean.setDefaultEncoding("UTF-8");
361
factoryBean.setPreferFileSystemAccess(false); // For WAR deployment
362
363
Properties settings = new Properties();
364
// Development settings
365
settings.setProperty("template_update_delay", "0");
366
settings.setProperty("template_exception_handler", "html_debug");
367
// Production settings would use:
368
// settings.setProperty("template_update_delay", "60000");
369
// settings.setProperty("template_exception_handler", "ignore");
370
371
settings.setProperty("default_encoding", "UTF-8");
372
settings.setProperty("output_encoding", "UTF-8");
373
settings.setProperty("auto_flush", "true");
374
settings.setProperty("url_escaping_charset", "UTF-8");
375
376
factoryBean.setFreemarkerSettings(settings);
377
378
// Global variables
379
Map<String, Object> variables = new HashMap<>();
380
variables.put("contextPath", "${request.contextPath}");
381
variables.put("springMacroRequestContext", new RequestContextHashModel());
382
factoryBean.setFreemarkerVariables(variables);
383
384
return factoryBean;
385
}
386
387
/**
388
* Configuration for standalone/batch applications
389
*/
390
@Bean
391
@Profile("batch")
392
public FreeMarkerConfigurationFactoryBean batchFreeMarkerConfig() {
393
FreeMarkerConfigurationFactoryBean factoryBean = new FreeMarkerConfigurationFactoryBean();
394
395
factoryBean.setTemplateLoaderPaths(
396
"classpath:/batch-templates/",
397
"file:/data/templates/"
398
);
399
400
factoryBean.setDefaultEncoding("UTF-8");
401
factoryBean.setPreferFileSystemAccess(true); // Better performance for file system
402
403
Properties settings = new Properties();
404
settings.setProperty("template_update_delay", "300000"); // 5 minutes
405
settings.setProperty("template_exception_handler", "rethrow");
406
settings.setProperty("arithmetic_engine", "bigdecimal");
407
settings.setProperty("number_format", "0.####");
408
settings.setProperty("boolean_format", "yes,no");
409
410
factoryBean.setFreemarkerSettings(settings);
411
412
return factoryBean;
413
}
414
415
/**
416
* Service for template-based document generation
417
*/
418
@Service
419
public static class DocumentGenerationService {
420
421
@Autowired
422
private Configuration freeMarkerConfiguration;
423
424
public void generateDocument(String templateName, Map<String, Object> data, OutputStream output)
425
throws IOException, TemplateException {
426
427
Template template = freeMarkerConfiguration.getTemplate(templateName);
428
429
try (Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) {
430
template.process(data, writer);
431
writer.flush();
432
}
433
}
434
435
public void generatePdfReport(String templateName, Map<String, Object> data, String outputPath)
436
throws IOException, TemplateException {
437
438
// Generate HTML from template
439
String html = generateHtmlFromTemplate(templateName, data);
440
441
// Convert to PDF (using a library like Flying Saucer or similar)
442
convertHtmlToPdf(html, outputPath);
443
}
444
445
private String generateHtmlFromTemplate(String templateName, Map<String, Object> data)
446
throws IOException, TemplateException {
447
448
Template template = freeMarkerConfiguration.getTemplate(templateName);
449
return FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
450
}
451
}
452
}
453
```
454
455
### Template Context Integration
456
457
Integration with Spring's web context and request handling.
458
459
```java { .api }
460
/**
461
* Utility methods for integrating FreeMarker with Spring web contexts
462
*/
463
public abstract class RequestContextUtils {
464
465
/**
466
* Get the current request context for use in templates
467
* @param request the HTTP request
468
* @param response the HTTP response
469
* @param servletContext the servlet context
470
* @return RequestContext for template use
471
*/
472
public static RequestContext getRequestContext(HttpServletRequest request,
473
HttpServletResponse response, ServletContext servletContext);
474
}
475
476
/**
477
* Hash model for exposing Spring RequestContext in FreeMarker templates
478
*/
479
public class RequestContextHashModel implements TemplateHashModel {
480
481
/**
482
* Create a RequestContextHashModel for the current request
483
*/
484
public RequestContextHashModel();
485
486
/**
487
* Create a RequestContextHashModel for a specific request
488
* @param request the HTTP request
489
* @param response the HTTP response
490
*/
491
public RequestContextHashModel(HttpServletRequest request, HttpServletResponse response);
492
493
@Override
494
public TemplateModel get(String key) throws TemplateModelException;
495
496
@Override
497
public boolean isEmpty() throws TemplateModelException;
498
}
499
```
500
501
## Integration with Spring Boot
502
503
For Spring Boot applications, FreeMarker auto-configuration is available:
504
505
```yaml
506
spring:
507
freemarker:
508
template-loader-path: classpath:/templates/
509
suffix: .ftl
510
cache: true
511
charset: UTF-8
512
check-template-location: true
513
content-type: text/html
514
expose-request-attributes: false
515
expose-session-attributes: false
516
expose-spring-macro-helpers: true
517
prefer-file-system-access: true
518
settings:
519
template_update_delay: 0
520
default_encoding: UTF-8
521
output_encoding: UTF-8
522
locale: en_US
523
date_format: yyyy-MM-dd
524
time_format: HH:mm:ss
525
datetime_format: yyyy-MM-dd HH:mm:ss
526
```
527
528
The Spring Context Support FreeMarker integration provides the foundation for this auto-configuration and can be used directly in non-Boot applications or for advanced customization scenarios.