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. 安全第一:永远不要信任模板中的用户输入
相关推荐
挺菜的5 分钟前
【算法刷题记录(简单题)003】统计大写字母个数(java代码实现)
java·数据结构·算法
蜗牛沐雨6 分钟前
警惕 Rust 字符串的性能陷阱:`chars().nth()` 的深坑与高效之道
开发语言·后端·rust
&Sinnt&1 小时前
Git 版本控制完全指南:从入门到精通
git·后端
掘金-我是哪吒1 小时前
分布式微服务系统架构第156集:JavaPlus技术文档平台日更-Java线程池使用指南
java·分布式·微服务·云原生·架构
亲爱的非洲野猪1 小时前
Kafka消息积压的多维度解决方案:超越简单扩容的完整策略
java·分布式·中间件·kafka
陈随易1 小时前
MoonBit助力前端开发,加密&性能两不误,斐波那契测试提高3-4倍
前端·后端·程序员
wfsm1 小时前
spring事件使用
java·后端·spring
微风粼粼2 小时前
程序员在线接单
java·jvm·后端·python·eclipse·tomcat·dubbo
缘来是庄2 小时前
设计模式之中介者模式
java·设计模式·中介者模式
rebel2 小时前
若依框架整合 CXF 实现 WebService 改造流程(后端)
java·后端