Freemarker修仙指南:从模板小厮到页面渲染大能的终极奥义

各位在前后端分离与不分离之间反复横跳的道友们!今天要解锁的是上古模板引擎Freemarker!这货虽然年岁已高(诞生于2003年),但在某些需要服务端渲染的场景,依然是"真香"选择!准备好用模板语法召唤动态HTML了吗? ✨


一、筑基篇:初识Freemarker

1.1 法宝祭炼(添加依赖)

xml 复制代码
<!-- Spring Boot集成版 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

<!-- 原生使用版 -->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.32</version>
</dependency>

1.2 基础配置(Spring Boot版)

yaml 复制代码
# application.yml
spring:
  freemarker:
    suffix: .ftl               # 模板文件后缀
    template-loader-path: classpath:/templates/ # 模板存放目录
    cache: false               # 开发时关闭缓存
    charset: UTF-8             # 必须设置编码!
    content-type: text/html

二、金丹篇:模板语法大全

2.1 变量输出(灵气外放)

html 复制代码
<!-- 普通变量 -->
<p>用户名:${username}</p>

<!-- 避免null值爆炸 -->
<p>余额:${balance!0}元</p>  <!-- 默认值语法 -->

<!-- 日期格式化 -->
<p>注册时间:${registerTime?string("yyyy-MM-dd HH:mm")}</p>

2.2 流程控制(御剑飞行)

html 复制代码
<#-- if判断 -->
<#if user.vip>
    <p class="gold">尊贵的VIP用户</p>
<#else>
    <p>普通用户</p>
</#if>

<#-- 遍历列表 -->
<ul>
<#list products as product>
    <li>${product.name} - ¥${product.price}</li>
</#list>
</ul>

2.3 宏定义(分身术)

html 复制代码
<#-- 定义宏 -->
<#macro userCard user>
    <div class="card">
        <h3>${user.name}</h3>
        <p>${user.bio!"这个人很懒,什么都没写"}</p>
    </div>
</#macro>

<#-- 使用宏 -->
<@userCard user=currentUser />

三、元婴篇:Spring Boot集成

3.1 Controller传参(灵力输送)

java 复制代码
@Controller
public class UserController {
    
    @GetMapping("/profile")
    public String profile(Model model) {
        model.addAttribute("username", "张无忌");
        model.addAttribute("registerTime", new Date());
        model.addAttribute("vip", true);
        return "user/profile"; // 对应templates/user/profile.ftl
    }
}

3.2 全局共享变量(宗门大阵)

java 复制代码
@Configuration
public class FreemarkerConfig {
    
    @Autowired
    private freemarker.template.Configuration configuration;

    @PostConstruct
    public void init() throws TemplateModelException {
        configuration.setSharedVariable("appName", "修仙论坛"); // 全局可用
        configuration.setSharedVariable("copyright", "2023");
    }
}

四、化神篇:高级技巧

4.1 自定义指令(独创神通)

java 复制代码
public class RoleDirective implements TemplateDirectiveModel {
    
    @Override
    public void execute(Environment env, Map params, 
                       TemplateModel[] loopVars,
                       TemplateDirectiveBody body) throws TemplateException {
        
        String role = params.get("role").toString();
        String currentRole = (String) env.getVariable("userRole");
        
        if (role.equals(currentRole)) {
            body.render(env.getOut()); // 符合条件才渲染内容
        }
    }
}

// 注册指令
configuration.setSharedVariable("hasRole", new RoleDirective());

模板中使用

html 复制代码
<@hasRole role="ADMIN">
    <button>删除用户</button>
</@hasRole>

4.2 类型处理(灵根转换)

java 复制代码
// 注册自定义日期格式化
configuration.setObjectWrapper(new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_32).build() {
    @Override
    public TemplateModel wrap(Object obj) throws TemplateModelException {
        if (obj instanceof LocalDateTime) {
            return new SimpleDate(((LocalDateTime) obj).atZone(ZoneId.systemDefault()).toInstant());
        }
        return super.wrap(obj);
    }
});

五、大乘篇:安全与性能

5.1 防XSS攻击(护体罡气)

html 复制代码
<#-- 默认输出会进行HTML转义 -->
<p>${userInput}</p> 

<#-- 禁用转义(慎用!) -->
<p>${userInput?no_esc}</p>

5.2 模板缓存优化(灵气循环)

java 复制代码
@Bean
public FreeMarkerConfigurationFactoryBean factoryBean() {
    FreeMarkerConfigurationFactoryBean bean = new FreeMarkerConfigurationFactoryBean();
    bean.setTemplateLoaderPath("classpath:/templates");
    bean.setPreferFileSystemAccess(false); // 禁用文件系统监听,提升性能
    bean.setDefaultEncoding("UTF-8");
    return bean;
}

六、实战心法

6.1 生成静态HTML(点石成金)

java 复制代码
public void generateStaticPage() throws Exception {
    Template template = configuration.getTemplate("article.ftl");
    Map<String, Object> data = new HashMap<>();
    data.put("title", "Freemarker使用指南");
    
    try (Writer out = new FileWriter("output.html")) {
        template.process(data, out);
    }
}

6.2 邮件模板应用(飞剑传书)

html 复制代码
<#-- email_template.ftl -->
<html>
<body>
    <h1>尊敬的${user.name}:</h1>
    <p>您的新密码是:<strong>${newPassword}</strong></p>
    <p>请及时<a href="${resetLink}">登录修改</a></p>
</body>
</html>

Java调用

java 复制代码
String htmlContent = FreeMarkerTemplateUtils.processTemplateIntoString(
    template, model);
emailService.sendHtmlEmail(to, subject, htmlContent);

飞升指南:最佳实践

  1. 模板管理 :合理使用<#include>拆分公共部分
  2. 逻辑精简:复杂计算应在Java代码中完成
  3. 版本控制:模板文件也应纳入Git管理
  4. 安全第一:永远不要信任模板中的用户输入
相关推荐
努力犯错玩AI1 分钟前
16.4B参数仅激活2.8B!Kimi-VL-A3B开源:长文本、多模态、低成本的AI全能选手
人工智能·后端·开源
小杨4042 分钟前
springboot框架项目实践应用二十一(git实战)
spring boot·git·后端
何似在人间5754 分钟前
SpringAI+DeepSeek大模型应用开发——3 SpringAI简介
java·ai·大模型开发·spring ai
长安城没有风11 分钟前
从入门到精通【MySQL】 JDBC
java·mysql
这里有鱼汤40 分钟前
Python 让电脑说话?没网也能用,真香!🗣️💻
后端·python
薯条不要番茄酱1 小时前
【JavaEE初阶】多线程重点知识以及常考的面试题-多线程进阶(三)
java·java-ee
doglc1 小时前
从零手写RPC-version0
java·git·rpc·maven·intellij idea
菜鸟谢1 小时前
.NET WinApi
后端
独立开阀者_FwtCoder1 小时前
Promise 引入全新 API!效率提升 300%!
前端·javascript·后端
汪小成1 小时前
NestJS学习笔记-03-使用class-validator进行接口参数校验🚀
后端·nestjs