核心原理
本質是字符串拼接 + 文件輸出。
通過 StringBuilder 構建完整 HTML 內容,再用 PrintStream/Files.write 落盤。
同樣邏輯若輸出到 HttpServletResponse 即為動態 JSP/Servlet。
原生拼接實戰 (無依賴)
public class HtmlReportGenerator {
public void generateDailyReport(String outputPath, List<Map<String, Object>> data) {
StringBuilder sb = new StringBuilder(4096); // 預估容量減擴容
// 1. HTML 骨架
sb.append("")
.append("每日運營報表")
.append("");
// 2. 標題
sb.append("每日運營報表 - ").append(LocalDate.now()).append("
");
// 3. 表頭
if (!data.isEmpty()) {
sb.append("");
for (String key : data.get(0).keySet()) {
sb.append("| ").append(escapeHtml(key)).append(" | ");
}
sb.append("
");
// 4. 數據行
for (Map<String, Object> row : data) {
sb.append("");
for (Object val : row.values()) {
sb.append("| ").append(escapeHtml(val == null ? "" : val.toString())).append(" | ");
}
sb.append("
");
}
sb.append("
");
}
sb.append("");
// 5. 落盤
try (PrintStream ps = new PrintStream(new FileOutputStream(outputPath), false, "UTF-8")) {
ps.print(sb.toString());
} catch (IOException e) {
throw new RuntimeException("報表生成失敗: " + outputPath, e);
}
}
/** 簡單 HTML 轉義,防 XSS */
private String escapeHtml(String s) {
return s.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """)
.replace("'", "'");
}
}
模板引擎進階:FreeMarker / Thymeleaf (推薦生產)
${title}
${title} - ${date}
<#list headers as h>| ${h} | #list>
<#list rows as row>
<#list row?values as v>| ${v!?string("")} | #list>
#list>
// FreeMarker 渲染
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
cfg.setClassForTemplateLoading(this.getClass(), "/templates");
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
Map<String, Object> model = new HashMap<>();
model.put("title", "每日運營報表");
model.put("date", LocalDate.now());
model.put("headers", data.get(0).keySet());
model.put("rows", data);
try (Writer out = new OutputStreamWriter(new FileOutputStream(outputPath), "UTF-8")) {
cfg.getTemplate("report.ftl").process(model, out);
}
應用場景對比
| 場景 | 推薦方案 | 理由 |
| 簡單報表、郵件內容、靜態化頁面 | StringBuilder + 原生輸出 | 零依賴、極快、可控 |
| 複雜佈局、條件渲染、循環嵌套、團隊協作 | FreeMarker / Thymeleaf | 模板分離、語法豐富、前端易維護 |
| 高併發靜態化 (每秒千級) | 模板預編譯 + 異步佇列 + CDN | 剝離 Web 線程、靜態化上傳 OSS |
| PDF 導出 | iText / Flying Saucer (HTML→PDF) | 同樣模板復用 |
性能優化清單
StringBuilder 預估初始容量
- 大數據分批寫入,避免巨大字符串佔用堆內存
- 模板引擎開啟緩存 (
cfg.setCacheStorage)
- 靜態資源 (CSS/JS/圖片) 走 CDN,HTML 只引用外鏈
- 生成後
gzip 壓縮存儲,傳輸節省 70%+
安全提醒
- 所有動態內容必須 HTML 轉義,防止存儲型 XSS
- 文件輸出路徑嚴格校驗,防止目錄遍歷寫入任意路徑
- 定期清理過期靜態文件,避免磁盤佔滿