[Java实战]Spring Boot 整合 Freemarker (十一)
引言
Apache FreeMarker 作为一款高性能的模板引擎,凭借其简洁语法、卓越性能和灵活扩展性,在 Java Web 开发中占据重要地位。结合 Spring Boot 的自动化配置能力,开发者能快速构建动态页面、生成报表或定制代码。本文将系统讲解整合流程、实战技巧、性能优化方案,并针对企业级场景提供深度解决方案。
一、Freemarker 核心优势与适用场景
1. 为什么选择 Freemarker?
特性 | 说明 |
---|---|
高性能 | 编译型模板引擎,执行效率优于传统 JSP |
语法简洁 | 类似 Python 的直观语法,学习成本低 |
强类型支持 | 严格的类型检查,减少运行时错误 |
多场景适用 | 支持 HTML、XML、JSON、纯文本等多种输出格式 |
2. 与 Thymeleaf 对比
维度 | Freemarker | Thymeleaf |
---|---|---|
模板类型 | 非自然模板(需渲染后查看) | 自然模板(浏览器直接预览) |
性能 | 更高(适合高并发场景) | 中等 |
功能扩展 | 支持自定义指令、宏 | 依赖方言扩展 |
集成复杂度 | 简单 | 需额外配置布局方言 |
二、Spring Boot 整合 Freemarker 全流程
1. 环境准备
- JDK 1.8+(推荐 LTS 版本)
- Spring Boot 2.x(本文基于 2.1.8)
- Maven/Gradle(本文使用 Maven)
2. 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
3. 基础配置(application.yml)
spring:
freemarker:
enabled: true # 启用 Freemarker
template-loader-path: classpath:/templates/ # 模板路径
suffix: .ftl # 模板文件后缀
charset: UTF-8 # 编码格式
cache: false # 开发环境关闭缓存
settings: # Freemarker 全局配置
classic_compatible: true # 兼容旧版本语法
number_format: 0.## # 数字格式化
datetime_format: yyyy-MM-dd HH:mm:ss
三、Freemarker 实战案例
案例 1:基础数据渲染
Controller
@Controller
public class ProductController {
@GetMapping("/product")
public String productDetail(Model model) {
Product product = new Product("iPhone 15", 7999.00, 100);
model.addAttribute("product", product);
model.addAttribute("discount", 0.15);
return "product";
}
}
模板(product.ftl)
<!DOCTYPE html>
<html>
<head>
<title>商品详情</title>
</head>
<body>
<h1>${product.name}</h1>
<p>价格: ${product.price?string.currency}</p>
<p>库存:
<#if product.stock > 0>
<span style="color: green;">有货</span>
<#else>
<span style="color: red;">缺货</span>
</#if>
</p>
<p>折后价: ${(product.price * (1 - discount))?string.currency}</p>
</body>
</html>
案例 2:分页功能实现
分页工具类
public class Page<T> {
private List<T> data;
private int currentPage;
private int totalPages;
// Getter/Setter
}
分页模板(list.ftl)
<table>
<#list page.data as item>
<tr><td>${item.name}</td></tr>
</#list>
</table>
<div class="pagination">
<#if page.currentPage > 1>
<a href="/list?page=${page.currentPage - 1}">上一页</a>
</#if>
<span>${page.currentPage}/${page.totalPages}</span>
<#if page.currentPage < page.totalPages>
<a href="/list?page=${page.currentPage + 1}">下一页</a>
</#if>
</div>
四、高阶技巧与性能优化
1. 自定义指令(实现数据脱敏)
public class MaskDirective implements TemplateDirectiveModel {
@Override
public void execute(Environment env, Map params,
TemplateModel[] loopVars,
TemplateDirectiveBody body) {
String content = params.get("content").toString();
int keepLength = Integer.parseInt(params.get("keep").toString());
String masked = content.substring(0, keepLength) + "****";
env.getOut().write(masked);
}
}
注册指令
@Configuration
public class FreemarkerConfig {
@Bean
public FreeMarkerConfigurationFactoryBean getFreeMarkerConfiguration() {
FreeMarkerConfigurationFactoryBean config = new FreeMarkerConfigurationFactoryBean();
config.setTemplateLoaderPath("classpath:/templates");
Map<String, Object> variables = new HashMap<>();
variables.put("mask", new MaskDirective());
config.setFreemarkerVariables(variables);
return config;
}
}
模板中使用
<p>手机号: <@mask content="13812345678" keep=3 /></p>
2. 性能优化策略
spring:
freemarker:
cache: true # 生产环境开启缓存
settings:
template_update_delay: 3600 # 模板更新检查间隔(秒)
localized_lookup: false # 关闭本地化查找提升性能
3. 集成其他模板引擎(多引擎共存)
@Configuration
public class MultiTemplateConfig {
@Bean
public ViewResolver freeMarkerViewResolver() {
FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setPrefix("");
resolver.setSuffix(".ftl");
resolver.setOrder(1); # 优先级高于 Thymeleaf
return resolver;
}
}
五、常见问题与解决方案
1. 模板文件未找到(404)
- 检查点:
- 文件是否位于
src/main/resources/templates
- 模板名是否与 Controller 返回的视图名一致
- 文件后缀是否为
.ftl
- 文件是否位于
2. 变量解析失败
- 错误示例:
Expression product.name is undefined
- 解决:
- 确保 Controller 中通过
model.addAttribute()
添加变量 - 检查变量名拼写(Freemarker 区分大小写)
- 使用
??
判空:${product.name!''}
- 确保 Controller 中通过
3. 静态资源加载问题
- 正确引用方式:
<link href="/css/style.css" rel="stylesheet"> <script src="/js/app.js"></script>
- 确保路径配置:静态资源位于
src/main/resources/static
六、企业级应用扩展
1. 生成 PDF/Word 文档
利用 Freemarker 模板生成 HTML,再通过 Flying Saucer
或 Apache POI
转换为 PDF/Word:
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
Template template = cfg.getTemplate("report.ftl");
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
// 转换为 PDF
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(outputStream);
2. 集群环境模板热更新
结合 Spring Cloud Config 或 Nacos 实现模板动态加载:
@Scheduled(fixedRate = 60000) # 每分钟检查更新
public void reloadTemplate() {
configuration.clearTemplateCache();
}
七、总结
通过 Spring Boot 整合 Freemarker,开发者能够快速构建高效、灵活的动态页面系统。关键点包括:
- 快速整合:依赖配置与基础语法
- 高阶扩展:自定义指令与多引擎共存
- 性能优化:缓存策略与集群方案
- 企业级应用:文档生成与动态更新
扩展思考:如何结合 Freemarker 与前端框架(如 React)实现服务端渲染(SSR)?欢迎评论区交流!
附录
- Freemarker 官方手册
- Spring Boot 模板引擎配置指南
希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!