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

news2025/5/12 13:17:22

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

引言

Apache FreeMarker 作为一款高性能的模板引擎,凭借其简洁语法卓越性能灵活扩展性,在 Java Web 开发中占据重要地位。结合 Spring Boot 的自动化配置能力,开发者能快速构建动态页面、生成报表或定制代码。本文将系统讲解整合流程、实战技巧、性能优化方案,并针对企业级场景提供深度解决方案。

一、Freemarker 核心优势与适用场景

1. 为什么选择 Freemarker?

特性说明
高性能编译型模板引擎,执行效率优于传统 JSP
语法简洁类似 Python 的直观语法,学习成本低
强类型支持严格的类型检查,减少运行时错误
多场景适用支持 HTML、XML、JSON、纯文本等多种输出格式

2. 与 Thymeleaf 对比

维度FreemarkerThymeleaf
模板类型非自然模板(需渲染后查看)自然模板(浏览器直接预览)
性能更高(适合高并发场景)中等
功能扩展支持自定义指令、宏依赖方言扩展
集成复杂度简单需额外配置布局方言

二、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)?欢迎评论区交流!

附录

  • Freemarker 官方手册
  • Spring Boot 模板引擎配置指南

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2373951.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode 高频题实战:如何优雅地序列化和反序列化字符串数组?

文章目录 摘要描述题解答案题解代码分析编码方法解码方法 示例测试及结果时间复杂度空间复杂度总结 摘要 在分布式系统中&#xff0c;数据的序列化与反序列化是常见的需求&#xff0c;尤其是在网络传输、数据存储等场景中。LeetCode 第 271 题“字符串的编码与解码”要求我们设…

C#游戏开发中的注意事项

目录 一、性能优化:提升游戏运行效率 1. 避免不必要的循环和迭代 2. 减少字符串拼接 3. 利用Unity的生命周期函数 4. 使用对象池(Object Pooling) 二、内存管理:避免内存泄漏和资源浪费 1. 及时释放非托管资源 2. 避免空引用异常 3. 合理使用引用类型和值类型 4. …

Spring Boot项目(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot前后端分离)

下载地址&#xff1a; 前端&#xff1a;https://download.csdn.net/download/2401_83418369/90811402 后端&#xff1a;https://download.csdn.net/download/2401_83418369/90811405 一、前端vue部分的搭建 这里直接看另一期刊的搭建Vue前端工程部分 前端vue后端ssm项目_v…

Spyglass:在batch/shell模式下运行目标的顶层是什么?

相关阅读 Spyglasshttps://blog.csdn.net/weixin_45791458/category_12828934.html?spm1001.2014.3001.5482 除了可以在图形用户界面(GUI)中运行目标外&#xff0c;使用Batch模式或Shell模式也可以运行目标&#xff0c;如下面的命令所示。 % spyglass -project test.prj -ba…

微服务架构中如何保证服务间通讯的安全

在微服务架构中,保证服务间通信的安全至关重要。服务间的通信通常是通过HTTP、gRPC、消息队列等方式实现的,而这些通信链路可能面临多种安全风险。为了应对这些风险,可以采取多种措施来保证通信安全。 常见的服务间通信风险 1.数据泄露:在服务间通信过程中,敏感数据可能会…

工具篇-Cherry Studio之MCP使用

一、添加MCP 打开Cherry Studio,如果没有可以到官网下载:Cherry Studio 官方网站 - 全能的AI助手 按上面步骤打开同步服务器 1、先去注册ModelScope,申请令牌 2、再打开MCP广场,找到高德MCP 选择工具测试,这里有个高德的api key需要申请 打开如下地址高德开放平…

Python 运维脚本

1、备份文件 import os import shutil# 定义配置文件目录和备份目录的路径 config_dir "/root/python/to/config/files/" backup_dir "/root/python/to/backup/"# 遍历配置文件目录中的所有文件 for filename in os.listdir(config_dir):# 如果文件名以…

大模型项目:普通蓝牙音响接入DeepSeek,解锁语音交互新玩法

本文附带视频讲解 【代码宇宙019】技术方案&#xff1a;蓝牙音响接入DeepSeek&#xff0c;解锁语音交互新玩法_哔哩哔哩_bilibili 目录 效果演示 核心逻辑 技术实现 大模型对话&#xff08;技术&#xff1a; LangChain4j 接入 DeepSeek&#xff09; 语音识别&#xff08;…

单链表设计与实现

01. 单链表简介 在数据结构中&#xff0c;单链表的实现可以分为 带头结点 和 不带头结点 两种方式&#xff0c;这里我们讨论第二种方式。 头结点&#xff1a;链表第一个节点不存实际数据&#xff0c;仅作为辅助节点指向首元节点&#xff08;第一个数据节点&#xff09;。头指…

springboot生成二维码到海报模板上

springboot生成二维码到海报模板上 QRCodeController package com.ruoyi.web.controller.app;import com.google.zxing.WriterException; import com.ruoyi.app.domain.Opportunity; import com.ruoyi.app.tool.QRCodeGenerator; import com.ruoyi.common.core.page.TableDat…

SEO长尾关键词布局优化法则

内容概要 在SEO优化体系中&#xff0c;长尾关键词的精准布局是突破流量瓶颈的关键路径。相较于竞争激烈的核心词&#xff0c;长尾词凭借其高转化率和低竞争特性&#xff0c;成为内容矩阵流量裂变的核心驱动力。本节将系统梳理长尾关键词布局的核心逻辑框架&#xff0c;涵盖从需…

python:trimesh 用于 STL 文件解析和 3D 操作

python&#xff1a;trimesh 是一个用于处理三维模型的库&#xff0c;支持多种格式的导入导出&#xff0c;比如STL、OBJ等&#xff0c;还包含网格操作、几何计算等功能。 Python Trimesh 库使用指南 安装依赖库 pip install trimesh Downloading trimesh-4.6.8-py3-none-any.w…

应急响应基础模拟靶机-security2

PS:杰克创建的流量包(result.pcap)在root目录下&#xff0c;请根据已有信息进行分析 1、首个攻击者扫描端口使用的工具是&#xff1f; 2、后个攻击者使用的漏洞扫描工具是&#xff1f; 3、攻击者上传webshell的绝对路径及User-agent是什么&#xff1f; 4、攻击者反弹shell的…

OpenCV定位地板上的书

任务目标是将下面的图片中的书本找出来&#xff1a; 使用到的技术包括&#xff1a;转灰度图、提取颜色分量、二值化、形态学、轮廓提取等。 我们尝试先把图片转为灰度图&#xff0c;然后二值化&#xff0c;看看效果&#xff1a; 可以看到&#xff0c;二值化后&#xff0c;书的…

NHANES稀有指标推荐:MedHi

文章题目&#xff1a;Association of dietary live microbe intake with frailty in US adults: evidence from NHANES DOI&#xff1a;10.1016/j.jnha.2024.100171 中文标题&#xff1a;美国成人膳食活微生物摄入量与虚弱的相关性&#xff1a;来自 NHANES 的证据 发表杂志&…

关于我在实现用户头像更换时遇到的图片上传和保存的问题

目录 前言 前端更换头像 后端处理 文件系统存储图片 数据库存储图片 处理图片文件 生成图片名 保存图片 将图片路径存储到数据库 完整代码 总结 前言 最近在实现一个用户头像更换的功能&#xff0c;但是因为之前并没有处理过图片的上传和保存&#xff0c;所以就开始…

10.二叉搜索树中第k小的元素(medium)

1.题目链接&#xff1a; 230. 二叉搜索树中第 K 小的元素 - 力扣&#xff08;LeetCode&#xff09;230. 二叉搜索树中第 K 小的元素 - 给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数…

AlimaLinux设置静态IP

通过nmcli命令来操作 步骤 1&#xff1a;确认当前活动的网络接口名称 首先&#xff0c;需要确认当前系统中可用的网络接口名称。可以使用以下命令查看&#xff1a; nmcli device步骤 2&#xff1a;修改配置以匹配正确的接口名称 sudo nmcli connection modify ens160 ipv4.…

滑动窗口——将x减到0的最小操作数

题目&#xff1a; 这个题如果我们直接去思考方法是很困难的&#xff0c;因为我们不知道下一步是在数组的左还是右操作才能使其最小。正难则反&#xff0c;思考一下&#xff0c;无论是怎么样的&#xff0c;最终这个数组都会分成三个部分左中右&#xff0c;而左右的组合就是我们…

基于SpringBoot的抽奖系统测试报告

一、编写目的 本报告为抽奖系统测试报告&#xff0c;本项目可用于团体抽奖活动&#xff0c;包括了用户注册&#xff0c;用户登录&#xff0c;修改奖项以及抽奖等功能。 二、项目背景 抽奖系统采用前后端分离的方法来实现&#xff0c;同时使用了数据库来存储相关的数据&…