惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
博客园_首页
Schneier on Security
Schneier on Security
T
Tailwind CSS Blog
J
Java Code Geeks
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
雷峰网
雷峰网
Jina AI
Jina AI
腾讯CDC
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
罗磊的独立博客
B
Blog RSS Feed
宝玉的分享
宝玉的分享
博客园 - 叶小钗
S
SegmentFault 最新的问题
酷 壳 – CoolShell
酷 壳 – CoolShell
The GitHub Blog
The GitHub Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The Cloudflare Blog
A
About on SuperTechFans
爱范儿
爱范儿
Y
Y Combinator Blog
量子位
有赞技术团队
有赞技术团队
MongoDB | Blog
MongoDB | Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
aimingoo的专栏
aimingoo的专栏
Hacker News - Newest:
Hacker News - Newest: "LLM"
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News | PayPal Newsroom
I
Intezer
Security Latest
Security Latest
V
Visual Studio Blog
H
Hacker News: Front Page
Scott Helme
Scott Helme
Latest news
Latest news
Forbes - Security
Forbes - Security
Engineering at Meta
Engineering at Meta
Cyberwarzone
Cyberwarzone
C
Check Point Blog
Last Week in AI
Last Week in AI
Google Online Security Blog
Google Online Security Blog
I
InfoQ
阮一峰的网络日志
阮一峰的网络日志
L
LINUX DO - 最新话题
WordPress大学
WordPress大学
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint

码志

如何在 IT 运维中节省开支 借助 Let's Encrypt 节省 SSL 证书费用 解决访问 https 网站时,后端重定向或获取 URL 变成 http 的问题 清除 GitHub 上的幽灵通知 DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI Mac mini 外接三方键盘如何微调音量 Java|小数据量场景的模糊搜索体验优化 家里老人迷信医疗广告?我可能找到办法了 iOS|解决 setBrightness 调节屏幕亮度不生效的问题
Java|FreeMarker 复用 layout
Zhuang Ma · 2025-08-30 · via 码志

项目里的页面一多,重复的页面布局就不可避免地冒了出来,作为程序员,消除重复,义不容辞。那么,今天就来聊聊如何在 FreeMarker 中复用页面 layout,让代码更优雅、更易维护。

常规做法:include

FreeMarker 提供了 include 指令,可以把一些公共页面元素单独提取出来,然后在需要的地方通过 include 引入,例如:

<#-- includes/header.ftl -->
<p>我来组成头部</p>
<#-- includes/footer.ftl -->
<p>我来组成底部</p>
<#-- somepage.ftl -->
<#include "./includes/header.ftl">

<p>我是页面内容</p>

<#include "./includes/footer.ftl">

<script>
// 这里是一些 JavaScript 代码
</script>

去除重复:抽象 layout

但是所有类似的页面都要手写这个结构也挺麻烦的,更糟糕的是,一旦这些页面的结构发生变化,得在 N 个页面里反复修改,想想都头大。

很多博客引擎(比如 Jekyll)都支持 layout 功能,允许我们定义统一的页面布局,具体页面只需专注于内容。

FreeMarker 虽然没有内置 layout,但我们可以用 macro 来实现类似的效果。

比如,抽象出一个 layout/page.ftl 文件,作为布局模板:

<#-- layout/page.ftl -->
<#macro layout body js="">

<#include "../includes/header.ftl" />

${body}

<#include "../includes/footer.ftl" />

${js}

</#macro>

然后在需要的页面这样用:

<#import "./layout/page.ftl" as base>

<#assign body>

<p>我是页面内容</p>
<p>当前时间:<span id="current-time">${.now?string("yyyy-MM-dd HH:mm:ss")}</span></p>

</#assign>

<#assign js>

<script>
// 每隔一秒刷新当前时间
setInterval(function() {
    document.getElementById("current-time").innerHTML = new Date().toLocaleString();
}, 1000);
</script>

</#assign>

<@base.layout body=body js=js />

页面效果如下:

减少手工输入:code snippets

虽然布局复用问题解决了,但每次新建页面还得手写一遍结构,还是不够优雅。程序员的信条是:能自动化的绝不手动!

这时就轮到编辑器/IDE 的 code snippets 功能登场了。把上面的结构定义成代码片段,新建页面时只需输入一个触发词,基本结构就自动生成。

以 VSCode 为例,可以在项目的 .vscode 目录下新建 layout.code-snippets 文件,内容如下:

{
    "page_layout": {
        "scope": "ftl",
        "prefix": "layout:page",
        "body": [
            "<#import \"./layout/page.ftl\" as base>",
            "",
            "<#assign body>",
            "",
            "",
            "",
            "</#assign>",
            "",
            "<#assign js>",
            "",
            "<script>",
            "",
            "</script>",
            "",
            "</#assign>",
            "",
            "<@base.layout body=body js=js />"
        ],
        "description": "Page layout template for FTL files"
    }
}

这样新建 .ftl 文件后,输入 layout:page,页面布局结构就自动生成了。

如图所示:

IntelliJ IDEA 也可以用 Live Templates 实现同样的效果。

本文相关代码和示例已上传至 GitHub,见 https://github.com/mzlogin/learn-spring 的 freemarker-test 目录。

文档信息