FreeMarker 是一个强大的 Java 模板引擎,广泛用于生成 HTML、XML、JSON 或纯文本。它本身是一个独立的 Java 库,可以与任何 Java 应用集成。Maven 和 Gradle 是 Java 生态中最主流的构建自动化工具,它们负责管理项目依赖、编译、测试、打包和部署。将 FreeMarker 与 Maven 或 Gradle 集成,核心在于通过构建工具的依赖管理功能,将 FreeMarker 库及其传递依赖自动下载并添加到项目的类路径(classpath)中。
1. 核心概念
- FreeMarker 库 (
freemarker
): FreeMarker 模板引擎的核心 JAR 包,包含freemarker.template.Configuration
,freemarker.template.Template
等核心类。这是集成的基础。 - 构建工具 (Build Tool): 自动化项目构建过程的工具。Maven 和 Gradle 是其代表。
- 依赖管理 (Dependency Management): 构建工具的核心功能。通过在项目配置文件(
pom.xml
for Maven,build.gradle
for Gradle)中声明对 FreeMarker 的依赖,构建工具会自动从中央仓库(如 Maven Central)下载 FreeMarker JAR 及其所有必需的传递依赖(transitive dependencies)到本地仓库,并在编译和运行时将其加入 classpath。 - 中央仓库 (Central Repository): 存储开源 Java 库(JAR 包)的公共服务器。Maven Central 是最常用的。构建工具默认从这里下载依赖。
pom.xml
(Maven Project Object Model): Maven 项目的配置文件,使用 XML 格式。<dependencies>
部分用于声明项目依赖。build.gradle
(Gradle Build Script): Gradle 项目的配置文件,使用 Groovy 或 Kotlin DSL (Kotlin DSL 更现代)。dependencies
代码块用于声明项目依赖。- 依赖范围 (Scope - Maven) / 配置 (Configuration - Gradle): 定义依赖在项目生命周期中的使用范围。
compile
(Maven) /implementation
(Gradle): 依赖在编译、测试和运行时都可用。这是添加 FreeMarker 的标准范围。provided
(Maven) /compileOnly
(Gradle): 依赖在编译和测试时需要,但不会被打包进最终的 JAR/WAR 文件。适用于由运行时环境(如 Servlet 容器)提供的库(如servlet-api
)。test
(Maven) /testImplementation
(Gradle): 依赖仅在运行测试时需要(如 JUnit)。
- 版本管理: 依赖声明中必须指定 FreeMarker 的版本号(如
2.3.32
)。构建工具确保使用指定的版本。 - 传递依赖 (Transitive Dependencies): FreeMarker 本身可能依赖于其他库(如
commons-io
)。构建工具会自动解析并下载这些依赖,简化了依赖管理。 - 本地仓库 (Local Repository): 构建工具在用户主目录下(如
~/.m2/repository
for Maven,~/.gradle/caches
for Gradle)缓存下载的依赖,避免重复下载。
2. 操作步骤 (非常详细)
以下是将 FreeMarker 集成到 Maven 和 Gradle 项目中的详细步骤。假设你已经创建了一个基本的 Java 项目。
通用前提
- 安装构建工具:
- Maven: 从 https://maven.apache.org/download.cgi 下载并安装。确保
mvn
命令在终端/命令提示符中可用。 - Gradle: 从 https://gradle.org/install/ 下载并安装。确保
gradle
命令可用。或者,更推荐使用 Gradle Wrapper (gradlew
/gradlew.bat
),它会自动管理 Gradle 版本。
- Maven: 从 https://maven.apache.org/download.cgi 下载并安装。确保
- 创建项目结构: 确保项目有标准的目录结构。
src/main/java
- Java 源代码src/main/resources
- 资源文件(如 FreeMarker 模板.ftl
)src/test/java
- 测试代码src/test/resources
- 测试资源
使用 Maven 集成 FreeMarker
步骤 1: 创建或定位 pom.xml
- 在项目根目录下创建一个名为
pom.xml
的文件,或者编辑已存在的pom.xml
。
步骤 2: 编写 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 项目基本信息 -->
<groupId>com.example</groupId>
<artifactId>freemarker-maven-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging> <!-- 或 war -->
<!-- 属性定义 (可选,便于版本管理) -->
<properties>
<maven.compiler.source>17</maven.compiler.source> <!-- 或你的 Java 版本 -->
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 定义 FreeMarker 版本变量 -->
<freemarker.version>2.3.32</freemarker.version>
</properties>
<!-- 依赖声明 -->
<dependencies>
<!-- 核心: 添加 FreeMarker 依赖 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version> <!-- 使用属性变量 -->
<!-- scope 默认是 compile, 可以省略 -->
<!-- <scope>compile</scope> -->
</dependency>
<!-- 示例: 添加 SLF4J API (用于日志,FreeMarker 可使用) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<!-- 示例: 添加 SLF4J Simple 实现 (简单日志输出) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 构建配置 (可选) -->
<build>
<plugins>
<!-- 编译器插件 (确保使用正确的 Java 版本) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- 打包插件 (可选,创建可执行 JAR) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.App</mainClass> <!-- 替换为你的主类 -->
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
步骤 3: 下载依赖
- 方法 1 (命令行): 在项目根目录(
pom.xml
所在目录)打开终端,执行:mvn clean compile
clean
清理旧编译文件,compile
编译源代码,此过程会自动下载pom.xml
中声明的所有compile
和test
范围的依赖(包括 FreeMarker 及其传递依赖)到本地 Maven 仓库(~/.m2/repository
),并编译项目。 - 方法 2 (IDE): 如果使用 IntelliJ IDEA 或 Eclipse,打开项目后,IDE 通常会自动检测
pom.xml
的更改并提示导入或刷新项目。点击 "Import Changes" 或 "Reload Project" 即可。
步骤 4: 使用 FreeMarker (代码示例)
- 创建模板: 在
src/main/resources/templates/
目录下创建一个 FreeMarker 模板文件,例如hello.ftl
:<!-- src/main/resources/templates/hello.ftl --> <#-- This is a FreeMarker template --> <h1>Hello, ${name}!</h1> <p>Welcome to FreeMarker with Maven.</p> <ul> <#list items as item> <li>${item}</li> </#list> </ul>
- 编写 Java 代码: 在
src/main/java/com/example/
下创建主类App.java
:// src/main/java/com/example/App.java package com.example; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.Version; import java.io.*; import java.util.HashMap; import java.util.Map; public class App { public static void main(String[] args) { try { // 1. 创建 FreeMarker Configuration 实例 // 使用新 API (Recommended) Configuration cfg = new Configuration(Configuration.VERSION_2_3_31); // 2. 设置模板加载路径 // 从 classpath 加载模板 cfg.setClassForTemplateLoading(App.class, "/templates"); // 或者从文件系统加载 (指定绝对或相对路径) // cfg.setDirectoryForTemplateLoading(new File("/path/to/templates")); // 3. 获取模板对象 Template template = cfg.getTemplate("hello.ftl"); // 文件名 // 4. 创建数据模型 (Model) Map<String, Object> dataModel = new HashMap<>(); dataModel.put("name", "World"); dataModel.put("items", new String[]{"Apple", "Banana", "Cherry"}); // 5. 合并模板和数据模型,输出到 Writer // 输出到控制台 Writer out = new OutputStreamWriter(System.out); template.process(dataModel, out); out.flush(); // 或者输出到文件 // try (Writer fileWriter = new FileWriter(new File("output.html"))) { // template.process(dataModel, fileWriter); // } } catch (IOException | TemplateException e) { e.printStackTrace(); } } }
- 编译和运行:
- 命令行:
# 编译 mvn compile # 运行 (使用 exec:java 插件或先打包) mvn exec:java -Dexec.mainClass="com.example.App" # 或者先打包成 JAR (如果配置了 maven-shade-plugin) # mvn package # java -jar target/freemarker-maven-demo-1.0.0-SNAPSHOT.jar
- IDE: 在 IDE 中直接运行
App
类的main
方法。
- 命令行:
使用 Gradle 集成 FreeMarker
步骤 1: 初始化 Gradle 项目 (可选)
- 在项目根目录打开终端,执行:
按提示选择项目类型(如gradle init
basic
)、DSL(推荐Kotlin
或Groovy
)、项目名称等。这会生成build.gradle
(或build.gradle.kts
) 和settings.gradle
(或settings.gradle.kts
)。
步骤 2: 编写 build.gradle
(Groovy DSL)
// build.gradle (Groovy DSL)
plugins {
id 'java' // 应用 Java 插件,提供编译、测试等任务
id 'application' // 可选,用于创建可运行的应用
}
// 项目基本信息
group = 'com.example'
version = '1.0.0-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_17 // 或 JavaVersion.VERSION_11 等
// 定义属性 (便于版本管理)
ext {
freemarkerVersion = '2.3.32'
slf4jVersion = '2.0.9'
junitVersion = '5.10.0'
}
repositories {
// 声明依赖仓库
mavenCentral() // 最常用的中央仓库
// jcenter() // (已归档,不推荐新项目使用)
// maven { url 'https://repo.spring.io/milestone' } // 其他仓库
}
dependencies {
// 核心: 添加 FreeMarker 依赖
implementation "org.freemarker:freemarker:${freemarkerVersion}"
// 示例: 添加 SLF4J
implementation "org.slf4j:slf4j-api:${slf4jVersion}"
implementation "org.slf4j:slf4j-simple:${slf4jVersion}"
// 测试依赖
testImplementation "org.junit.jupiter:junit-jupiter:${junitVersion}"
}
// 配置 application 插件 (可选)
application {
mainClass = 'com.example.App' // 替换为你的主类全名
}
// 配置编译任务 (可选)
compileJava {
options.encoding = 'UTF-8' // 设置源码编码
}
步骤 2 (替代): 编写 build.gradle.kts
(Kotlin DSL - 推荐)
// build.gradle.kts (Kotlin DSL)
plugins {
java
application // 可选
}
group = "com.example"
version = "1.0.0-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17
val freemarkerVersion: String by project
val slf4jVersion: String by project
val junitVersion: String by project
repositories {
mavenCentral()
}
dependencies {
implementation("org.freemarker:freemarker:$freemarkerVersion")
implementation("org.slf4j:slf4j-api:$slf4jVersion")
implementation("org.slf4j:slf4j-simple:$slf4jVersion")
testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion")
}
application {
mainClass.set("com.example.App") // 替换为你的主类
}
// (可选) 通过 gradle.properties 文件管理版本
// 创建 gradle.properties 文件 (与 build.gradle.kts 同级)
// freemarkerVersion=2.3.32
// slf4jVersion=2.0.9
// junitVersion=5.10.0
步骤 3: 下载依赖
- 方法 1 (命令行): 在项目根目录执行:
# 使用 Gradle Wrapper (推荐,项目自带) ./gradlew build # 或 ./gradlew compileJava # 或使用全局 Gradle gradle build
build
任务会执行编译、测试等,compileJava
仅编译。执行时会自动下载所有声明的依赖到本地 Gradle 缓存(~/.gradle/caches/modules-2/files-2.1/
)。 - 方法 2 (IDE): 打开项目后,IDE (IntelliJ IDEA, Eclipse with Buildship) 通常会自动识别
build.gradle
并提示同步。点击 "Sync Now" 或 "Reload Gradle Project"。
步骤 4: 使用 FreeMarker
- 模板文件 (
src/main/resources/templates/hello.ftl
) 和 Java 代码 (src/main/java/com/example/App.java
) 与 Maven 示例完全相同。 - 编译和运行:
- 命令行 (Wrapper):
# 编译 ./gradlew compileJava # 运行 (使用 application 插件) ./gradlew run # 或者运行特定任务 # ./gradlew classes # 编译 # java -cp build/classes/java/main:build/resources/main:$(./gradlew dependencies --configuration runtimeClasspath --console=plain | grep -o '.*\.jar' | tr '\n' ':') com.example.App
- 命令行 (全局 Gradle):
gradle run
- IDE: 直接运行
App
类的main
方法。
- 命令行 (Wrapper):
3. 常见错误
ClassNotFoundException
/NoClassDefFoundError
:- 原因: FreeMarker JAR 未正确下载或未添加到 classpath。
- 解决:
- 检查
pom.xml
/build.gradle
中的groupId
,artifactId
,version
是否拼写正确。 - 执行
mvn dependency:tree
(Maven) 或./gradlew dependencies
(Gradle) 查看依赖树,确认freemarker
是否在compile
/implementation
配置中。 - 检查网络连接,确保能访问 Maven Central。尝试手动删除本地仓库中对应的 FreeMarker 目录(
~/.m2/repository/org/freemarker/
或~/.gradle/caches/modules-2/files-2.1/org.freemarker/
),然后重新执行构建命令强制下载。 - 在 IDE 中刷新/重新导入项目。
- 检查
Could not resolve dependencies
/Could not find ...
:- 原因: 指定的 FreeMarker 版本在仓库中不存在,或仓库 URL 配置错误/网络问题。
- 解决:
- 访问 https://mvnrepository.com/artifact/org.freemarker/freemarker 确认版本号是否存在。
- 检查
pom.xml
的<repositories>
或build.gradle
的repositories
块是否包含mavenCentral()
。 - 检查代理设置(如果公司网络需要)。
编译错误 (
package freemarker.template does not exist
):- 原因: IDE 未正确识别构建文件或依赖未下载。
- 解决: 强制刷新 Maven/Gradle 项目。在 IntelliJ IDEA 中,点击 Maven/Gradle 工具窗口的刷新按钮。在 Eclipse 中,右键项目 -> Maven -> Update Project / Gradle -> Refresh Gradle Project。
运行时找不到模板 (
Template not found
):- 原因:
cfg.setClassForTemplateLoading()
或cfg.setDirectoryForTemplateLoading()
路径设置错误。模板文件未正确打包到 JAR/WAR 中。 - 解决:
- 确认模板文件在
src/main/resources
目录下,且路径与setClassForTemplateLoading
的第二个参数(如"/templates"
)匹配。 - 使用
cfg.getTemplate("templates/hello.ftl")
如果模板在resources/templates/
下。 - 打包后检查 JAR/WAR 文件内容,确认
templates/
目录和.ftl
文件存在。
- 确认模板文件在
- 原因:
Gradle DSL 语法错误:
- 原因: Groovy/Kotlin 语法错误(如缺少分号、括号不匹配、字符串引号问题)。
- 解决: 仔细检查
build.gradle
语法。使用 IDE 的 Gradle 支持进行语法检查。参考官方文档。
4. 注意事项
- 版本选择: 选择稳定且适合你项目需求的 FreeMarker 版本。查看 FreeMarker 官网 或 Maven Central 获取最新稳定版。注意版本号(如
2.3.32
)与 API 兼容性。 - 依赖范围/配置: 确保 FreeMarker 依赖使用正确的范围(Maven
compile
/implementation
)或配置(Gradleimplementation
),使其在编译和运行时都可用。避免误用provided
/compileOnly
,除非你确定运行环境会提供它。 - 传递依赖: 理解传递依赖的概念。
freemarker
依赖可能引入commons-io
等。构建工具会自动处理,但有时可能需要排除冲突的传递依赖(使用<exclusions>
in Maven,exclude
in Gradle)。 - 文件编码: 确保
.ftl
模板文件和 Java 源文件都使用 UTF-8 编码,避免乱码。在构建脚本或 IDE 中设置编码。 src/main/resources
: FreeMarker 模板通常放在src/main/resources
下,这样它们会被打包进最终的 JAR/WAR 文件,可以通过 classpath 访问。- 构建工具选择: Maven 配置更标准化(XML),Gradle 脚本更灵活强大(Groovy/Kotlin DSL),性能通常更好。根据团队习惯和项目复杂度选择。
- Gradle Wrapper: 强烈推荐在项目中包含 Gradle Wrapper (
gradlew
,gradlew.bat
,gradle/wrapper/
),确保所有开发者使用相同的 Gradle 版本,避免版本冲突。
5. 使用技巧
- 使用属性/变量管理版本: 在
pom.xml
的<properties>
或 Gradle 的ext
/gradle.properties
中定义版本号变量,便于统一管理和升级。 - 利用 IDE 支持: IntelliJ IDEA, Eclipse 等主流 IDE 对 Maven 和 Gradle 都有 excellent 支持,提供依赖搜索、自动补全、错误提示、项目刷新等功能。
- 查看依赖树: 使用
mvn dependency:tree
(Maven) 或./gradlew dependencies
(Gradle) 分析依赖关系,排查冲突或了解传递依赖。 - 排除传递依赖: 当传递依赖引入了冲突的库版本时,可以显式排除。
- Maven:
<dependency> <groupId>some.library</groupId> <artifactId>problematic-artifact</artifactId> <version>x.y.z</version> <exclusions> <exclusion> <groupId>conflicting.group</groupId> <artifactId>conflicting-artifact</artifactId> </exclusion> </exclusions> </dependency>
- Gradle:
implementation('some.library:problematic-artifact:x.y.z') { exclude group: 'conflicting.group', module: 'conflicting-artifact' }
- Maven:
- 使用 BOM (Bill of Materials): 对于大型项目或使用 Spring 等框架,可以使用 BOM 来统一管理一组相关依赖的版本。
- Maven:
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-framework-bom</artifactId> <version>6.0.11</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
- Maven:
- 离线模式: 构建工具支持离线模式(
mvn -o
,./gradlew --offline
),在已下载所有依赖后可以加速构建,但无法下载新依赖。
6. 最佳实践与性能优化
最佳实践:
- 选择合适的构建工具: 团队统一。新项目可优先考虑 Gradle (Kotlin DSL)。
- 版本控制
pom.xml
/build.gradle
: 将构建配置文件纳入版本控制(如 Git)。 - 使用 Wrapper (Gradle): 将
gradlew
,gradlew.bat
,gradle/wrapper/
目录加入版本控制。 - 清晰的依赖组织: 按功能或范围组织
dependencies
块。 - 及时更新: 定期检查并更新 FreeMarker 和其他依赖到安全、稳定的版本(使用
mvn versions:display-dependency-updates
,./gradlew dependencyUpdates
插件)。 - 最小化依赖: 只引入项目真正需要的依赖,避免臃肿。
- 文档化: 在项目 README 中说明如何构建和运行。
性能优化 (构建过程):
- Gradle Daemon: Gradle 默认启用 Daemon,一个后台进程,显著加快后续构建速度。确保它在运行。
- 并行构建 (Gradle): 在
gradle.properties
中设置org.gradle.parallel=true
,允许并行执行独立的任务。 - 配置缓存 (Gradle 6.6+): 在
gradle.properties
中设置org.gradle.configuration-cache=true
,缓存构建脚本的配置阶段,大幅缩短配置时间。 - 增量编译: Maven 和 Gradle 都支持增量编译,只编译修改过的文件。
- 构建扫描 (Gradle): 使用
--scan
参数生成构建报告,分析耗时任务。 - Maven 优化: 使用
-T
选项进行并行构建(mvn -T 4 compile
)。 - 本地镜像/私服: 在企业环境中,搭建 Nexus 或 Artifactory 私服,作为中央仓库的镜像和缓存,加速依赖下载并提高稳定性。
- 清理不必要的构建: 避免频繁执行
clean
,除非必要(如解决缓存问题)。compile
通常比clean compile
快。
通过遵循这些步骤和最佳实践,你可以轻松地将 FreeMarker 模板引擎集成到任何使用 Maven 或 Gradle 构建的 Java 项目中,享受自动化依赖管理带来的便利。