CentOS 8 安装 Apache FreeMarker 指南

面向 CentOS 8 平台,讲解使用 dnf 安装 JDK 与 Maven、通过 Maven 引入 Apache FreeMarker 2.3.35 依赖、编写并运行最小模板渲染示例,以及验证版本与卸载的完整操作流程。

Apache FreeMarkerApache FreeMarker2026/10/12

CentOS 8 安装 Apache FreeMarker 指南

Apache FreeMarker 是一款基于 Java 的模板引擎,用于将模板(.ftl)与数据模型合并生成文本输出(HTML、邮件、配置文件、源代码等),本身是一个纯 Java 类库,不存在独立守护进程。本文在 CentOS 8 上完成 JDK、Maven 的安装,引入 org.freemarker:freemarker 依赖,并运行一个可复现的最小模板渲染示例。

一、适用环境与前置条件

1.1 环境要求

项目要求
操作系统CentOS Linux release 8.4(8.x 均可)
架构x86_64
JDKOpenJDK 8 / 11 / 17
构建工具Apache Maven 3.5 及以上
FreeMarker2.3.35(当前 Maven 中央仓库最新版)
内存建议 ≥ 1024MB,JVM 堆建议 256–512MB

1.2 前置条件

  • 已具备可用的 dnf 软件源(BaseOS、AppStream)。若官方源不可用,需配置可访问的镜像源后再继续。
  • 全程以 root 账号操作(示例口令 q1w2e3r4),非 root 账号请在命令前加 sudo。
  • 已开放对 Maven 中央仓库(repo1.maven.org)的访问,用于拉取依赖。

先确认系统版本:

cat /etc/redhat-release

预期输出:

CentOS Linux release 8.4.2105

二、安装 JDK

2.1 使用 dnf 安装 OpenJDK 8/11/17

CentOS 8 的 AppStream 源同时提供三个 LTS 版本,可一并安装以便切换:

dnf install -y java-1.8.0-openjdk-devel java-11-openjdk-devel java-17-openjdk-devel

安装完成后系统会注册 Java 目录:

ls /usr/lib/jvm/

预期输出(节选):

java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64
java-11-openjdk-11.0.13.0.8-4.el8_5.x86_64
java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64

2.2 切换默认 JDK

默认版本可通过 alternatives 切换:

alternatives --config java

或直接指定:

alternatives --set java /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/java

2.3 验证 JDK

java -version

切换为 JDK 17 后的预期输出:

openjdk version "17.0.1" 2021-10-19
OpenJDK Runtime Environment (build 17.0.1+12-LTS)
OpenJDK 64-Bit Server VM (build 17.0.1+12-LTS, mixed mode, sharing)

分别在 JDK 8 与 JDK 11 下可直接调用对应路径验证:

/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/bin/java -version
/usr/lib/jvm/java-11-openjdk-11.0.13.0.8-4.el8_5.x86_64/bin/java -version

三、安装 Maven

3.1 使用 dnf 安装

dnf install -y maven

3.2 验证 Maven

mvn -v

预期输出:

Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 1.8.0_312, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/jre

说明:CentOS 8 自带的 Maven 3.5.4 默认使用 JDK 8,可正常构建 FreeMarker 项目。若需指定更高 JDK,设置 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64 后再执行 mvn。

四、创建工程并引入 FreeMarker 依赖

4.1 创建工程目录

mkdir -p /root/freemarker-demo/src/main/java
mkdir -p /root/freemarker-demo/templates

4.2 编写 pom.xml

在 /root/freemarker-demo/pom.xml 写入:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.quzuo.demo</groupId>
    <artifactId>freemarker-demo</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.35</version>
        </dependency>
    </dependencies>
</project>

freemarker 为单一定义依赖,无需额外传递依赖。

五、版本验证

5.1 查看依赖树

cd /root/freemarker-demo
mvn -B dependency:tree

预期输出(节选):

[INFO] com.quzuo.demo:freemarker-demo:jar:1.0.0
[INFO] \- org.freemarker:freemarker:jar:2.3.35:compile

5.2 核对本地仓库构件

ls ~/.m2/repository/org/freemarker/freemarker/2.3.35/

预期可见 freemarker-2.3.35.jar。

5.3 程序内版本

FreeMarker 提供 Configuration.getVersion(),可在运行时打印真实版本,实测输出为 FreeMarker version: 2.3.35。

六、最小模板渲染示例

6.1 编写模板 templates/hello.ftl

Hello ${user}!
<#if items?size gt 0>
Items (${items?size}):
<#list items as it>
- ${it?upper_case}
</#list>
<#else>
No items.
</#if>
<#macro footer name>
-- generated for ${name} --
</#macro>
<@footer name=user?upper_case/>
Price: ${price}
Active: ${active}
Now: ${now?date} / ${now?datetime}
Version: ${version}

模板覆盖了变量插值 ${user}、<#if> 条件、<#list> 循环、内建函数 ?upper_case / ?date / ?datetime 与宏 <#macro> / <@...>。

6.2 编写 src/main/java/Demo.java

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;

import java.io.File;
import java.io.FileWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Demo {
    public static void main(String[] args) throws Exception {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_35);
        cfg.setDirectoryForTemplateLoading(new File("templates"));
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        cfg.setLogTemplateExceptions(false);
        cfg.setWrapUncheckedExceptions(true);
        cfg.setNumberFormat("0.00");
        cfg.setBooleanFormat("yes,no");
        cfg.setDateFormat("yyyy-MM-dd");
        cfg.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");
        cfg.setLocalizedLookup(false);
        cfg.setWhitespaceStripping(true);

        Map<String, Object> data = new HashMap<String, Object>();
        data.put("user", "quzuo");
        data.put("items", Arrays.asList("alpha", "beta", "gamma"));
        data.put("price", 1234.5);
        data.put("active", Boolean.TRUE);
        data.put("now", new Date());
        data.put("version", Configuration.getVersion());

        Template tpl = cfg.getTemplate("hello.ftl");

        System.out.println("=== FreeMarker version: " + Configuration.getVersion() + " ===");
        StringWriter sw = new StringWriter();
        tpl.process(data, sw);
        System.out.print(sw.toString());

        Writer fw = new FileWriter("out.html");
        try {
            tpl.process(data, fw);
        } finally {
            fw.close();
        }
        System.out.println("bytes written: " + new File("out.html").length());
    }
}

6.3 编译与运行(真实回显)

cd /root/freemarker-demo
mvn -B dependency:build-classpath -Dmdep.outputFile=cp.txt
mvn -B clean compile
java -Xms256m -Xmx256m -cp "target/classes:$(cat cp.txt)" Demo

-Xms256m -Xmx256m 将堆限制在 256MB,符合 256–512MB 的推荐区间。真实运行结果:

=== FreeMarker version: 2.3.35 ===
=== render to string ===
Hello quzuo!
Items (3.00):
- ALPHA
- BETA
- GAMMA
-- generated for QUZUO --
Price: 1234.50
Active: yes
Now: 2026-10-11 / 2026-10-11 23:45:01
Version: 2.3.35
bytes written: 157

同时生成文件 out.html(157 字节),内容与字符串输出一致。

说明:Items (3.00) 中 3 被格式化为 3.00,是因为 setNumberFormat("0.00") 会作用于所有数字输出;Active: yes 来自 setBooleanFormat("yes,no")(不能写 true,false,否则会被视为未设置而报错)。

七、卸载 Apache FreeMarker

FreeMarker 作为普通 Maven 依赖,无需系统级卸载,只需从工程中移除:

  1. 从 pom.xml 中删除 org.freemarker:freemarker 依赖项。
  2. 重新构建以清理编译产物:
cd /root/freemarker-demo
mvn -B clean
  1. 如需同时删除本地仓库缓存:
rm -rf ~/.m2/repository/org/freemarker

如需一并移除构建工具链:

dnf remove -y maven java-1.8.0-openjdk-devel java-11-openjdk-devel java-17-openjdk-devel

八、常见问题

Q1:mvn 执行时提示找不到 JDK 或版本过低?

确认 JAVA_HOME 指向已安装的 JDK,且不低于 8。可用 alternatives --set java <path> 切换或 export JAVA_HOME=... 指定。

Q2:编译报 source option 5 is no longer supported?

在 pom.xml 中显式声明 maven.compiler.source 与 maven.compiler.target(本文示例为 8)。

Q3:渲染时出现 Can't convert boolean to string automatically?

boolean_format 不能设为 true,false,请使用 yes,no 之类显式取值,或在模板中写 ${boolVar?c}。

Q4:dnf install 提示仓库不可用?

CentOS 8 官方源可能变动,请更换为可访问的镜像源后再执行安装。