[Java实战]Spring Boot 整合 Freemarker (十一)

发布于:2025-05-12 ⋅ 阅读:(53) ⋅ 点赞:(0)

[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 &gt; 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 &gt; 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!''}

3. 静态资源加载问题

  • 正确引用方式
    <link href="/css/style.css" rel="stylesheet">
    <script src="/js/app.js"></script>
    
  • 确保路径配置:静态资源位于 src/main/resources/static

六、企业级应用扩展

1. 生成 PDF/Word 文档

利用 Freemarker 模板生成 HTML,再通过 Flying SaucerApache 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,开发者能够快速构建高效、灵活的动态页面系统。关键点包括:

  1. 快速整合:依赖配置与基础语法
  2. 高阶扩展:自定义指令与多引擎共存
  3. 性能优化:缓存策略与集群方案
  4. 企业级应用:文档生成与动态更新

扩展思考:如何结合 Freemarker 与前端框架(如 React)实现服务端渲染(SSR)?欢迎评论区交流!

附录

希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!


网站公告

今日签到

点亮在社区的每一天
去签到