or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cache-configuration.mdconditional-configuration.mdcore-autoconfiguration.mddata-configuration.mdindex.mdjson-configuration.mdmessaging-configuration.mdsecurity-configuration.mdservice-connections.mdtemplate-configuration.mdweb-configuration.md

template-configuration.mddocs/

0

# Template Engine Configuration

1

2

Spring Boot's template engine configuration provides comprehensive auto-configuration for popular template engines including Thymeleaf, FreeMarker, Mustache, and Groovy templates.

3

4

## Capabilities

5

6

### Thymeleaf Configuration

7

8

Auto-configuration for Thymeleaf template engine with Spring integration.

9

10

```java { .api }

11

/**

12

* Auto-configuration for Thymeleaf template engine

13

* Configures Thymeleaf for web applications with Spring MVC and WebFlux support

14

*/

15

@AutoConfiguration

16

@ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class})

17

@ConditionalOnWebApplication

18

@AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})

19

@EnableConfigurationProperties(ThymeleafProperties.class)

20

public class ThymeleafAutoConfiguration {

21

22

/**

23

* Thymeleaf template engine with Spring integration

24

*/

25

@Bean

26

@ConditionalOnMissingBean(SpringTemplateEngine.class)

27

public SpringTemplateEngine templateEngine(ThymeleafProperties properties,

28

ObjectProvider<ITemplateResolver> templateResolvers,

29

ObjectProvider<IDialect> dialects) {

30

SpringTemplateEngine engine = new SpringTemplateEngine();

31

for (ITemplateResolver templateResolver : templateResolvers.orderedStream().collect(Collectors.toList())) {

32

engine.addTemplateResolver(templateResolver);

33

}

34

for (IDialect dialect : dialects.orderedStream().collect(Collectors.toList())) {

35

engine.addDialect(dialect);

36

}

37

return engine;

38

}

39

40

/**

41

* Thymeleaf template resolver for classpath templates

42

*/

43

@Bean

44

@ConditionalOnMissingBean(name = "defaultTemplateResolver")

45

public ITemplateResolver defaultTemplateResolver(ThymeleafProperties properties,

46

ApplicationContext applicationContext) {

47

SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();

48

resolver.setApplicationContext(applicationContext);

49

resolver.setPrefix(properties.getPrefix());

50

resolver.setSuffix(properties.getSuffix());

51

resolver.setTemplateMode(properties.getMode());

52

if (properties.getEncoding() != null) {

53

resolver.setCharacterEncoding(properties.getEncoding().name());

54

}

55

resolver.setCacheable(properties.isCache());

56

Integer order = properties.getTemplateResolverOrder();

57

if (order != null) {

58

resolver.setOrder(order);

59

}

60

resolver.setCheckExistence(properties.isCheckTemplate());

61

return resolver;

62

}

63

}

64

65

/**

66

* Thymeleaf configuration properties

67

*/

68

@ConfigurationProperties(prefix = "spring.thymeleaf")

69

public class ThymeleafProperties {

70

71

/**

72

* Templates encoding

73

*/

74

private Charset encoding = StandardCharsets.UTF_8;

75

76

/**

77

* Whether to check that the template exists before rendering it

78

*/

79

private boolean checkTemplate = true;

80

81

/**

82

* Whether to check that the templates location exists

83

*/

84

private boolean checkTemplateLocation = true;

85

86

/**

87

* Prefix that gets prepended to view names when building a URL

88

*/

89

private String prefix = "classpath:/templates/";

90

91

/**

92

* Suffix that gets appended to view names when building a URL

93

*/

94

private String suffix = ".html";

95

96

/**

97

* Template mode to be applied to templates

98

*/

99

private String mode = "HTML";

100

101

/**

102

* Whether to enable template caching

103

*/

104

private boolean cache = true;

105

106

/**

107

* Order of the template resolver in the chain

108

*/

109

private Integer templateResolverOrder;

110

111

/**

112

* Comma-separated list of view names that can be resolved

113

*/

114

private String[] viewNames;

115

116

/**

117

* Comma-separated list of view names that should be excluded from resolution

118

*/

119

private String[] excludedViewNames;

120

121

/**

122

* Whether to enable MVC Thymeleaf view resolution

123

*/

124

private boolean enableSpringElCompiler = false;

125

126

/**

127

* Whether to render the partial mode in case of AJAX requests

128

*/

129

private boolean renderHiddenMarkersBeforeCheckboxes = false;

130

131

// Getters and setters

132

public String getPrefix() { return this.prefix; }

133

public void setPrefix(String prefix) { this.prefix = prefix; }

134

public String getSuffix() { return this.suffix; }

135

public void setSuffix(String suffix) { this.suffix = suffix; }

136

public String getMode() { return this.mode; }

137

public void setMode(String mode) { this.mode = mode; }

138

public boolean isCache() { return this.cache; }

139

public void setCache(boolean cache) { this.cache = cache; }

140

public Charset getEncoding() { return this.encoding; }

141

public void setEncoding(Charset encoding) { this.encoding = encoding; }

142

}

143

```

144

145

### FreeMarker Configuration

146

147

Auto-configuration for FreeMarker template engine.

148

149

```java { .api }

150

/**

151

* Auto-configuration for FreeMarker template engine

152

* Configures FreeMarker for web applications and email templates

153

*/

154

@AutoConfiguration

155

@ConditionalOnClass({freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class})

156

@AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})

157

@EnableConfigurationProperties(FreeMarkerProperties.class)

158

public class FreeMarkerAutoConfiguration {

159

160

/**

161

* FreeMarker configuration

162

*/

163

@Bean

164

@ConditionalOnMissingBean

165

public FreeMarkerConfigurationFactoryBean freeMarkerConfiguration(FreeMarkerProperties properties) {

166

FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean = new FreeMarkerConfigurationFactoryBean();

167

applyProperties(freeMarkerConfigurationFactoryBean, properties);

168

return freeMarkerConfigurationFactoryBean;

169

}

170

171

/**

172

* FreeMarker configuration for web applications

173

*/

174

@Configuration(proxyBeanMethods = false)

175

@ConditionalOnWebApplication(type = Type.SERVLET)

176

@ConditionalOnClass({Servlet.class, FreeMarkerConfigurer.class})

177

protected static class FreeMarkerWebConfiguration {

178

179

@Bean

180

@ConditionalOnMissingBean(FreeMarkerConfig.class)

181

public FreeMarkerConfigurer freeMarkerConfigurer(FreeMarkerProperties properties) {

182

FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();

183

applyProperties(configurer, properties);

184

return configurer;

185

}

186

187

@Bean

188

@ConditionalOnMissingBean(name = "freeMarkerViewResolver")

189

@ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true)

190

public FreeMarkerViewResolver freeMarkerViewResolver(FreeMarkerProperties properties) {

191

FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();

192

properties.applyToMvcViewResolver(resolver);

193

return resolver;

194

}

195

}

196

}

197

198

/**

199

* FreeMarker configuration properties

200

*/

201

@ConfigurationProperties(prefix = "spring.freemarker")

202

public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {

203

204

/**

205

* Default encoding of templates

206

*/

207

public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";

208

209

/**

210

* Default suffix for template names

211

*/

212

public static final String DEFAULT_SUFFIX = ".ftlh";

213

214

/**

215

* Comma-separated list of template loader paths

216

*/

217

private String[] templateLoaderPath = new String[]{DEFAULT_TEMPLATE_LOADER_PATH};

218

219

/**

220

* Whether HttpSession attributes are allowed to override controller generated model attributes

221

*/

222

private boolean allowSessionOverride = false;

223

224

/**

225

* Whether to allow RequestContext attributes to override controller generated model attributes

226

*/

227

private boolean allowRequestOverride = false;

228

229

/**

230

* Whether to expose RequestContext to templates for use by Spring's macro library

231

*/

232

private boolean exposeRequestAttributes = false;

233

234

/**

235

* Whether to expose HttpSession attributes to templates

236

*/

237

private boolean exposeSessionAttributes = false;

238

239

/**

240

* Whether to expose all Spring beans to templates

241

*/

242

private boolean exposeSpringMacroHelpers = true;

243

244

/**

245

* Prefer file system access for template loading

246

*/

247

private boolean preferFileSystemAccess = true;

248

249

/**

250

* Template encoding

251

*/

252

private String defaultEncoding = "UTF-8";

253

254

/**

255

* Well-known FreeMarker keys which are passed to FreeMarker's Configuration

256

*/

257

private Map<String, String> settings = new HashMap<>();

258

259

// Getters and setters

260

public String[] getTemplateLoaderPath() { return this.templateLoaderPath; }

261

public void setTemplateLoaderPath(String... templateLoaderPath) { this.templateLoaderPath = templateLoaderPath; }

262

public boolean isPreferFileSystemAccess() { return this.preferFileSystemAccess; }

263

public void setPreferFileSystemAccess(boolean preferFileSystemAccess) { this.preferFileSystemAccess = preferFileSystemAccess; }

264

public Map<String, String> getSettings() { return this.settings; }

265

public void setSettings(Map<String, String> settings) { this.settings = settings; }

266

}

267

```

268

269

### Mustache Configuration

270

271

Auto-configuration for Mustache template engine.

272

273

```java { .api }

274

/**

275

* Auto-configuration for Mustache template engine

276

* Configures Mustache for web applications with logic-less templates

277

*/

278

@AutoConfiguration

279

@ConditionalOnClass({Mustache.class, MustacheViewResolver.class})

280

@AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})

281

@EnableConfigurationProperties(MustacheProperties.class)

282

public class MustacheAutoConfiguration {

283

284

/**

285

* Mustache compiler for template compilation

286

*/

287

@Bean

288

@ConditionalOnMissingBean

289

public Mustache.Compiler mustacheCompiler(MustacheProperties mustache,

290

Environment environment,

291

ObjectProvider<MustacheEnvironmentCollector> collector) {

292

293

MustacheEnvironmentCollector environmentCollector = collector.getIfAvailable(() -> new DefaultMustacheEnvironmentCollector());

294

return Mustache.compiler()

295

.withResolver(new DefaultResolver(mustache.getPrefix()))

296

.withCollector(environmentCollector);

297

}

298

299

/**

300

* Configuration for servlet-based web applications

301

*/

302

@Configuration(proxyBeanMethods = false)

303

@ConditionalOnWebApplication(type = Type.SERVLET)

304

protected static class MustacheWebMvcConfiguration {

305

306

@Bean

307

@ConditionalOnMissingBean(name = "mustacheViewResolver")

308

public MustacheViewResolver mustacheViewResolver(Mustache.Compiler mustacheCompiler,

309

MustacheProperties mustache) {

310

MustacheViewResolver resolver = new MustacheViewResolver(mustacheCompiler);

311

mustache.applyToMvcViewResolver(resolver);

312

return resolver;

313

}

314

}

315

316

/**

317

* Configuration for reactive web applications

318

*/

319

@Configuration(proxyBeanMethods = false)

320

@ConditionalOnWebApplication(type = Type.REACTIVE)

321

protected static class MustacheReactiveConfiguration {

322

323

@Bean

324

@ConditionalOnMissingBean(name = "mustacheViewResolver")

325

public MustacheViewResolver mustacheViewResolver(Mustache.Compiler mustacheCompiler,

326

MustacheProperties mustache) {

327

MustacheViewResolver resolver = new MustacheViewResolver(mustacheCompiler);

328

resolver.setOrder(mustache.getOrder());

329

return resolver;

330

}

331

}

332

}

333

334

/**

335

* Mustache configuration properties

336

*/

337

@ConfigurationProperties(prefix = "spring.mustache")

338

public class MustacheProperties extends AbstractTemplateViewResolverProperties {

339

340

/**

341

* Default prefix for template names

342

*/

343

public static final String DEFAULT_PREFIX = "classpath:/templates/";

344

345

/**

346

* Default suffix for template names

347

*/

348

public static final String DEFAULT_SUFFIX = ".mustache";

349

350

/**

351

* Prefix to apply to template names

352

*/

353

private String prefix = DEFAULT_PREFIX;

354

355

/**

356

* Suffix to apply to template names

357

*/

358

private String suffix = DEFAULT_SUFFIX;

359

360

/**

361

* Whether to check that the template exists before rendering it

362

*/

363

private boolean checkTemplateLocation = true;

364

365

/**

366

* Character set used to read template files

367

*/

368

private Charset charset = StandardCharsets.UTF_8;

369

370

// Getters and setters

371

public String getPrefix() { return this.prefix; }

372

public void setPrefix(String prefix) { this.prefix = prefix; }

373

public String getSuffix() { return this.suffix; }

374

public void setSuffix(String suffix) { this.suffix = suffix; }

375

public boolean isCheckTemplateLocation() { return this.checkTemplateLocation; }

376

public void setCheckTemplateLocation(boolean checkTemplateLocation) { this.checkTemplateLocation = checkTemplateLocation; }

377

public Charset getCharset() { return this.charset; }

378

public void setCharset(Charset charset) { this.charset = charset; }

379

}

380

```

381

382

### Groovy Templates Configuration

383

384

Auto-configuration for Groovy template engine.

385

386

```java { .api }

387

/**

388

* Auto-configuration for Groovy template engine

389

* Configures Groovy templates for web applications

390

*/

391

@AutoConfiguration

392

@ConditionalOnClass({GroovyTemplateEngine.class, GroovyMarkupConfigurer.class})

393

@AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})

394

@EnableConfigurationProperties(GroovyTemplateProperties.class)

395

public class GroovyTemplateAutoConfiguration {

396

397

/**

398

* Configuration for servlet-based web applications

399

*/

400

@Configuration(proxyBeanMethods = false)

401

@ConditionalOnWebApplication(type = Type.SERVLET)

402

@ConditionalOnClass({Servlet.class, GroovyMarkupConfigurer.class})

403

protected static class GroovyMarkupConfiguration {

404

405

@Bean

406

@ConditionalOnMissingBean(GroovyMarkupConfig.class)

407

public GroovyMarkupConfigurer groovyMarkupConfigurer(GroovyTemplateProperties properties) {

408

GroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer();

409

configurer.setResourceLoaderPath(properties.getResourceLoaderPath());

410

configurer.setCacheTemplates(properties.isCache());

411

Configuration configuration = new Configuration();

412

configuration.setAutoNewLine(properties.getConfiguration().isAutoNewLine());

413

configuration.setAutoIndent(properties.getConfiguration().isAutoIndent());

414

configurer.setConfiguration(configuration);

415

return configurer;

416

}

417

418

@Bean

419

@ConditionalOnMissingBean(name = "groovyMarkupViewResolver")

420

public GroovyMarkupViewResolver groovyMarkupViewResolver(GroovyTemplateProperties properties) {

421

GroovyMarkupViewResolver resolver = new GroovyMarkupViewResolver();

422

properties.applyToMvcViewResolver(resolver);

423

return resolver;

424

}

425

}

426

}

427

428

/**

429

* Groovy template configuration properties

430

*/

431

@ConfigurationProperties(prefix = "spring.groovy.template")

432

public class GroovyTemplateProperties extends AbstractTemplateViewResolverProperties {

433

434

/**

435

* Default prefix for template names

436

*/

437

public static final String DEFAULT_RESOURCE_LOADER_PATH = "classpath:/templates/";

438

439

/**

440

* Default suffix for template names

441

*/

442

public static final String DEFAULT_SUFFIX = ".tpl";

443

444

/**

445

* Template path

446

*/

447

private String resourceLoaderPath = DEFAULT_RESOURCE_LOADER_PATH;

448

449

/**

450

* Whether to cache templates

451

*/

452

private boolean cache = true;

453

454

/**

455

* Groovy template engine configuration

456

*/

457

private final Configuration configuration = new Configuration();

458

459

// Getters and setters

460

public String getResourceLoaderPath() { return this.resourceLoaderPath; }

461

public void setResourceLoaderPath(String resourceLoaderPath) { this.resourceLoaderPath = resourceLoaderPath; }

462

public boolean isCache() { return this.cache; }

463

public void setCache(boolean cache) { this.cache = cache; }

464

public Configuration getConfiguration() { return this.configuration; }

465

466

/**

467

* Groovy template configuration settings

468

*/

469

public static class Configuration {

470

/**

471

* Whether to auto indent generated markup

472

*/

473

private boolean autoIndent = false;

474

475

/**

476

* Whether to auto generate new lines in generated markup

477

*/

478

private boolean autoNewLine = false;

479

480

// Getters and setters

481

public boolean isAutoIndent() { return this.autoIndent; }

482

public void setAutoIndent(boolean autoIndent) { this.autoIndent = autoIndent; }

483

public boolean isAutoNewLine() { return this.autoNewLine; }

484

public void setAutoNewLine(boolean autoNewLine) { this.autoNewLine = autoNewLine; }

485

}

486

}

487

```

488

489

**Usage Examples:**

490

491

```java

492

// Thymeleaf controller

493

@Controller

494

public class UserController {

495

496

@GetMapping("/users/{id}")

497

public String showUser(@PathVariable Long id, Model model) {

498

User user = userService.findById(id);

499

model.addAttribute("user", user);

500

return "user-profile"; // resolves to /templates/user-profile.html

501

}

502

503

@GetMapping("/users")

504

public String listUsers(Model model) {

505

List<User> users = userService.findAll();

506

model.addAttribute("users", users);

507

return "user-list";

508

}

509

}

510

511

// FreeMarker service for email templates

512

@Service

513

public class EmailTemplateService {

514

515

private final FreeMarkerConfigurationFactoryBean freeMarkerConfig;

516

517

public EmailTemplateService(FreeMarkerConfigurationFactoryBean freeMarkerConfig) {

518

this.freeMarkerConfig = freeMarkerConfig;

519

}

520

521

public String generateWelcomeEmail(User user) throws Exception {

522

Template template = freeMarkerConfig.getObject().getTemplate("welcome-email.ftlh");

523

Map<String, Object> model = new HashMap<>();

524

model.put("user", user);

525

model.put("appName", "MyApp");

526

527

try (StringWriter writer = new StringWriter()) {

528

template.process(model, writer);

529

return writer.toString();

530

}

531

}

532

}

533

534

// Mustache API response

535

@RestController

536

public class ReportController {

537

538

private final Mustache.Compiler mustacheCompiler;

539

540

public ReportController(Mustache.Compiler mustacheCompiler) {

541

this.mustacheCompiler = mustacheCompiler;

542

}

543

544

@GetMapping("/api/reports/{id}/html")

545

public ResponseEntity<String> generateReport(@PathVariable Long id) {

546

Report report = reportService.findById(id);

547

548

String templateContent = "{{#report}}<h1>{{title}}</h1><p>{{description}}</p>{{/report}}";

549

Mustache template = mustacheCompiler.compile(templateContent);

550

551

Map<String, Object> context = Map.of("report", report);

552

String html = template.execute(context);

553

554

return ResponseEntity.ok()

555

.contentType(MediaType.TEXT_HTML)

556

.body(html);

557

}

558

}

559

560

// Properties configuration

561

# application.properties

562

# Thymeleaf

563

spring.thymeleaf.cache=false

564

spring.thymeleaf.prefix=classpath:/templates/

565

spring.thymeleaf.suffix=.html

566

spring.thymeleaf.mode=HTML

567

spring.thymeleaf.encoding=UTF-8

568

569

# FreeMarker

570

spring.freemarker.template-loader-path=classpath:/templates/

571

spring.freemarker.suffix=.ftlh

572

spring.freemarker.settings.template_update_delay=0

573

spring.freemarker.settings.default_encoding=UTF-8

574

spring.freemarker.settings.classic_compatible=true

575

576

# Mustache

577

spring.mustache.prefix=classpath:/templates/

578

spring.mustache.suffix=.mustache

579

spring.mustache.cache=true

580

spring.mustache.charset=UTF-8

581

582

# Groovy Templates

583

spring.groovy.template.cache=true

584

spring.groovy.template.configuration.auto-indent=true

585

spring.groovy.template.configuration.auto-new-line=true

586

```

587

588

## Types

589

590

### Template Configuration Types

591

592

```java { .api }

593

/**

594

* Abstract base class for template view resolver properties

595

*/

596

public abstract class AbstractTemplateViewResolverProperties extends AbstractViewResolverProperties {

597

598

/**

599

* Whether template caching is enabled

600

*/

601

private boolean cache = true;

602

603

/**

604

* Content-Type value used for views

605

*/

606

private MimeType contentType;

607

608

/**

609

* Character encoding used for views

610

*/

611

private Charset charset;

612

613

/**

614

* Name of the RequestContext attribute for all views

615

*/

616

private String requestContextAttribute;

617

618

// Getters and setters

619

public boolean isCache() { return this.cache; }

620

public void setCache(boolean cache) { this.cache = cache; }

621

public MimeType getContentType() { return this.contentType; }

622

public void setContentType(MimeType contentType) { this.contentType = contentType; }

623

}

624

625

/**

626

* Template resolver interface for resolving template names to resources

627

*/

628

public interface ITemplateResolver {

629

/**

630

* Name of this template resolver

631

*/

632

String getName();

633

634

/**

635

* Order in which this resolver will be executed

636

*/

637

Integer getOrder();

638

639

/**

640

* Resolve template for the given context

641

*/

642

TemplateResolution resolveTemplate(IEngineConfiguration configuration,

643

ITemplateContext ownerTemplate,

644

String template,

645

Map<String, Object> templateResolutionAttributes);

646

}

647

648

/**

649

* Customizer for template view resolvers

650

*/

651

@FunctionalInterface

652

public interface TemplateViewResolverCustomizer<T extends AbstractTemplateViewResolver> {

653

/**

654

* Customize the template view resolver

655

* @param viewResolver the view resolver to customize

656

*/

657

void customize(T viewResolver);

658

}

659

```