本文目录导读:

我来为您提供几个Java模板引擎的完整案例,涵盖常用的FreeMarker、Thymeleaf和Velocity。
FreeMarker 模板引擎案例
基础使用案例
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.*;
import java.util.*;
public class FreeMarkerExample {
public static void main(String[] args) {
// 1. 创建配置
Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
cfg.setDefaultEncoding("UTF-8");
// 2. 设置模板加载目录
cfg.setClassForTemplateLoading(FreeMarkerExample.class, "/templates");
// 3. 准备数据模型
Map<String, Object> dataModel = new HashMap<>();
// 用户信息
User user = new User("张三", 25, "zhangsan@example.com");
dataModel.put("user", user);
// 订单列表
List<Order> orders = new ArrayList<>();
orders.add(new Order("2024001", 199.99, "已支付"));
orders.add(new Order("2024002", 399.50, "待发货"));
orders.add(new Order("2024003", 599.00, "已完成"));
dataModel.put("orders", orders);
dataModel.put("totalAmount", 1198.49);
// 4. 生成模板
try {
Template template = cfg.getTemplate("order.ftl");
StringWriter writer = new StringWriter();
template.process(dataModel, writer);
System.out.println("生成的HTML:");
System.out.println(writer.toString());
} catch (IOException | TemplateException e) {
e.printStackTrace();
}
}
}
class User {
private String name;
private int age;
private String email;
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
// getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
class Order {
private String orderId;
private double amount;
private String status;
public Order(String orderId, double amount, String status) {
this.orderId = orderId;
this.amount = amount;
this.status = status;
}
// getters and setters
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public double getAmount() { return amount; }
public void setAmount(double amount) { this.amount = amount; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
}
模板文件 order.ftl
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">用户订单信息</title>
<style>
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #4CAF50; color: white; }
</style>
</head>
<body>
<h1>订单管理</h1>
<div class="user-info">
<h2>用户信息</h2>
<p>姓名:${user.name}</p>
<p>年龄:${user.age}</p>
<p>邮箱:${user.email}</p>
</div>
<div class="orders">
<h2>订单列表</h2>
<table>
<tr>
<th>订单号</th>
<th>金额</th>
<th>状态</th>
<th>备注</th>
</tr>
<#list orders as order>
<tr>
<td>${order.orderId}</td>
<td>${order.amount?string("0.00")} 元</td>
<td>
<#if order.status == "已支付">
<span style="color: green">${order.status}</span>
<#elseif order.status == "待发货">
<span style="color: orange">${order.status}</span>
<#else>
<span style="color: blue">${order.status}</span>
</#if>
</td>
<td>
<#if order.amount > 500>
大额订单
<#else>
普通订单
</#if>
</td>
</tr>
</#list>
</table>
<div class="total">
<h3>总计:${totalAmount?string("0.00")} 元</h3>
</div>
</div>
</body>
</html>
Thymeleaf 模板引擎案例
配置和基本使用
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import java.util.*;
public class ThymeleafExample {
public static void main(String[] args) {
// 1. 创建模板解析器
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setCacheable(false);
// 2. 创建模板引擎
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
// 3. 创建上下文并添加变量
Context context = new Context();
context.setVariable("title", "产品列表");
// 产品数据
List<Product> products = new ArrayList<>();
products.add(new Product(1, "iPhone 15", 5999.00, 10, true));
products.add(new Product(2, "MacBook Pro", 12999.00, 5, true));
products.add(new Product(3, "iPad Air", 4799.00, 0, false));
products.add(new Product(4, "AirPods Pro", 1899.00, 20, true));
context.setVariable("products", products);
// 促销信息
Map<String, String> promotions = new HashMap<>();
promotions.put("iPhone 15", "限时优惠500元");
promotions.put("MacBook Pro", "赠送保护套");
context.setVariable("promotions", promotions);
// 4. 渲染模板
String html = templateEngine.process("products", context);
System.out.println("生成的HTML:");
System.out.println(html);
}
}
class Product {
private int id;
private String name;
private double price;
private int stock;
private boolean featured;
public Product(int id, String name, double price, int stock, boolean featured) {
this.id = id;
this.name = name;
this.price = price;
this.stock = stock;
this.featured = featured;
}
// getters and setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public int getStock() { return stock; }
public void setStock(int stock) { this.stock = stock; }
public boolean isFeatured() { return featured; }
public void setFeatured(boolean featured) { this.featured = featured; }
}
模板文件 products.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">th:text="${title}">产品列表</title>
<style>
.featured { background-color: #ffffcc; }
.out-of-stock { color: red; }
</style>
</head>
<body>
<h1 th:text="${title}">产品列表</h1>
<div th:if="${#lists.isEmpty(products)}">
<p>暂时没有产品</p>
</div>
<table th:if="${!#lists.isEmpty(products)}">
<thead>
<tr>
<th>ID</th>
<th>产品名称</th>
<th>价格</th>
<th>库存</th>
<th>促销信息</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr th:each="product : ${products}"
th:class="${product.featured} ? 'featured' : ''">
<td th:text="${product.id}">1</td>
<td>
<span th:text="${product.name}">产品名称</span>
<span th:if="${product.featured}" style="color: orange">★</span>
</td>
<td th:text="'¥' + ${#numbers.formatDecimal(product.price, 1, 2)}">
¥0.00
</td>
<td th:text="${product.stock}">0</td>
<td>
<span th:if="${promotions.containsKey(product.name)}"
th:text="${promotions[product.name]}">
促销信息
</span>
<span th:unless="${promotions.containsKey(product.name)}">
-
</span>
</td>
<td>
<span th:if="${product.stock > 0}"
th:text="'有货 (' + ${product.stock} + ')'"
style="color: green">有货</span>
<span th:unless="${product.stock > 0}"
th:text="'缺货'"
th:class="'out-of-stock'">缺货</span>
</td>
</tr>
</tbody>
</table>
<div th:switch="${#lists.size(products)}">
<p th:case="'0'">没有产品</p>
<p th:case="'1'">只有1个产品</p>
<p th:case="*">共有 <span th:text="${#lists.size(products)}">0</span> 个产品</p>
</div>
</body>
</html>
完整项目案例(整合Spring Boot)
Maven依赖配置 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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<groupId>com.example</groupId>
<artifactId>template-demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- FreeMarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.32</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
Spring Boot 配置文件 application.yml
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
mode: HTML
encoding: UTF-8
cache: false
server:
port: 8080
实体类
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class BlogPost {
private Long id;
private String title;
private String content;
private String author;
private LocalDateTime createTime;
private List<String> tags;
private int views;
private boolean published;
// 构造函数
public BlogPost(Long id, String title, String content, String author,
LocalDateTime createTime, List<String> tags) {
this.id = id;
this.title = title;
this.content = content;
this.author = author;
this.createTime = createTime;
this.tags = tags;
this.views = 0;
this.published = true;
}
}
Controller
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Controller
@RequestMapping("/blog")
public class BlogController {
private List<BlogPost> posts = createSamplePosts();
@GetMapping
public String list(@RequestParam(required = false) String tag, Model model) {
List<BlogPost> filteredPosts = posts;
if (tag != null && !tag.isEmpty()) {
filteredPosts = posts.stream()
.filter(post -> post.getTags().contains(tag))
.collect(Collectors.toList());
}
model.addAttribute("posts", filteredPosts);
model.addAttribute("activeTag", tag);
model.addAttribute("totalPosts", posts.size());
return "blog/list";
}
@GetMapping("/{id}")
public String detail(@PathVariable Long id, Model model) {
BlogPost post = posts.stream()
.filter(p -> p.getId().equals(id))
.findFirst()
.orElse(null);
if (post != null) {
post.setViews(post.getViews() + 1);
model.addAttribute("post", post);
model.addAttribute("relatedPosts", findRelatedPosts(post));
return "blog/detail";
}
return "error/404";
}
private List<BlogPost> findRelatedPosts(BlogPost post) {
return posts.stream()
.filter(p -> !p.getId().equals(post.getId()))
.filter(p -> p.getTags().stream().anyMatch(post.getTags()::contains))
.limit(3)
.collect(Collectors.toList());
}
private List<BlogPost> createSamplePosts() {
return Arrays.asList(
new BlogPost(1L, "Java 17 新特性详解",
"Java 17 带来了许多激动人心的新特性...",
"张三", LocalDateTime.now().minusDays(3),
Arrays.asList("Java", "编程")),
new BlogPost(2L, "Spring Boot 实战经验",
"在使用 Spring Boot 开发时,我们遇到了一些问题...",
"李四", LocalDateTime.now().minusDays(2),
Arrays.asList("Spring", "Java")),
new BlogPost(3L, "微服务架构设计",
"微服务架构已经成为现代应用开发的主流...",
"王五", LocalDateTime.now().minusDays(1),
Arrays.asList("架构", "微服务")),
new BlogPost(4L, "数据库性能优化",
"数据库性能优化是每个开发者必备的技能...",
"张三", LocalDateTime.now(),
Arrays.asList("数据库", "性能"))
);
}
}
Thymeleaf 模板 - blog/list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">技术博客</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
.post { border: 1px solid #ddd; margin-bottom: 20px; padding: 15px; border-radius: 5px; }
.post-title { color: #333; margin-top: 0; }
.tag { background-color: #eee; padding: 3px 8px; margin-right: 5px; border-radius: 3px; font-size: 12px; }
.meta { color: #666; font-size: 14px; }
.nav { margin-bottom: 20px; }
.nav a { color: #2196F3; text-decoration: none; margin-right: 10px; }
.active { font-weight: bold; color: #1976D2 !important; }
</style>
</head>
<body>
<header>
<h1>技术博客</h1>
<p>共 <span th:text="${totalPosts}">0</span> 篇文章</p>
</header>
<nav th:with="allTags=${@blogController.getPosts().stream().flatMap(p -> p.getTags().stream()).distinct().collect(@java.util.stream.Collectors.toList())}">
<div class="nav">
<a href="/blog" th:classappend="${activeTag == null} ? 'active'">全部</a>
<a th:each="tag : ${allTags}"
th:href="@{/blog(tag=${tag})}"
th:text="${tag}"
th:classappend="${tag == activeTag} ? 'active'">标签</a>
</div>
</nav>
<main>
<article class="post" th:each="post : ${posts}">
<h2 class="post-title">
<a th:href="@{/blog/{id}(id=${post.id})}" th:text="${post.title}">标题</a>
</h2>
<div class="meta">
<span th:text="${post.author}">作者</span> |
<span th:text="${#temporals.format(post.createTime, 'yyyy-MM-dd HH:mm')}">时间</span> |
阅读 <span th:text="${post.views}">0</span> 次
</div>
<div>
<span class="tag" th:each="tag : ${post.tags}" th:text="${tag}">标签</span>
</div>
</article>
<div th:if="${posts.isEmpty()}">
<p>暂无文章</p>
</div>
</main>
</body>
</html>
Thymeleaf 模板 - blog/detail.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">th:text="${post.title}">博客详情</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
h1 { color: #333; }
.meta { color: #666; margin-bottom: 20px; border-bottom: 1px solid #eee; padding-bottom: 10px; }
.content { line-height: 1.6; }
.tag { display: inline-block; background-color: #eee; padding: 5px 10px; margin-right: 5px; border-radius: 3px; }
.related { background-color: #f9f9f9; padding: 15px; margin-top: 30px; border-radius: 5px; }
.related a { display: block; margin-bottom: 10px; color: #2196F3; text-decoration: none; }
.back { display: inline-block; margin-top: 20px; }
</style>
</head>
<body>
<main>
<h1 th:text="${post.title}">标题</h1>
<div class="meta">
<span th:text="${post.author}">作者</span> |
<span th:text="${#temporals.format(post.createTime, 'yyyy-MM-dd HH:mm')}">时间</span> |
阅读 <span th:text="${post.views}">0</span> 次
</div>
<div class="tags" th:if="${!#lists.isEmpty(post.tags)}">
<span class="tag" th:each="tag : ${post.tags}" th:text="${tag}">标签</span>
</div>
<div class="content" th:text="${post.content}">
文章内容
</div>
<div th:if="${!#lists.isEmpty(relatedPosts)}" class="related">
<h3>相关文章</h3>
<a th:each="related : ${relatedPosts}"
th:href="@{/blog/{id}(id=${related.id})}"
th:text="${related.title}">相关文章标题</a>
</div>
<a class="back" href="/blog" th:text="'← 返回列表'">返回列表</a>
</main>
</body>
</html>
高级案例:动态报表生成
Freemarker 批量生成 HTML
import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.*;
import java.util.*;
public class DynamicReportGenerator {
public static void main(String[] args) throws Exception {
// 配置
Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
cfg.setClassForTemplateLoading(DynamicReportGenerator.class, "/templates");
cfg.setDefaultEncoding("UTF-8");
// 示例:生成月度销售报告
Template template = cfg.getTemplate("sales_report.ftl");
List<SalesData> salesData = generateSalesData();
for (SalesData data : salesData) {
Map<String, Object> model = new HashMap<>();
model.put("report", data);
String fileName = "report_" + data.getMonth() + ".html";
try (Writer writer = new FileWriter("output/" + fileName)) {
template.process(model, writer);
}
System.out.println("已生成报告: " + fileName);
}
}
private static List<SalesData> generateSalesData() {
List<SalesData> reports = new ArrayList<>();
Random random = new Random(42);
String[] months = {"一月", "二月", "三月", "四月", "五月", "六月"};
String[] products = {"智能手机", "笔记本电脑", "平板电脑", "智能手表", "耳机"};
for (String month : months) {
SalesData report = new SalesData(month);
for (String product : products) {
report.addSales(product,
random.nextInt(5000) + 1000, // 销售数量
random.nextDouble() * 500 + 50); // 单价
}
reports.add(report);
}
return reports;
}
}
class SalesData {
private String month;
private List<ProductSale> sales = new ArrayList<>();
private double totalRevenue = 0;
public SalesData(String month) { this.month = month; }
public void addSales(String product, int quantity, double price) {
sales.add(new ProductSale(product, quantity, price));
totalRevenue += quantity * price;
}
public String getMonth() { return month; }
public List<ProductSale> getSales() { return sales; }
public double getTotalRevenue() { return totalRevenue; }
}
class ProductSale {
private String product;
private int quantity;
private double price;
public ProductSale(String product, int quantity, double price) {
this.product = product;
this.quantity = quantity;
this.price = price;
}
public String getProduct() { return product; }
public int getQuantity() { return quantity; }
public double getPrice() { return price; }
}
这些案例涵盖了Java中常用的模板引擎使用方式,您可以根据项目需求选择合适的模板引擎,并结合Spring Boot等框架集成使用,如需了解特定场景下的更多细节,请告诉我。