StringBuffer msg = new StringBuffer();
msg.append("親愛的 ").append(cust.getName()).append(":\n\n");
msg.append("您的帳戶餘額是 ").append(cust.getBalance()).append("\n\n");
msg.append("致禮!\n某某公司");
mail.send(cust.getEmail(), "帳單", msg.toString());
缺點:業務邏輯與文字耦合、非程式設計師無法維護、結構變更需改碼重編譯。
模型:資料物件。視圖:純文字模板。控制器:準備資料、合併模板、發送輸出。Velocity 是成熟、輕量、語法簡單的選擇。
| 語法 | 說明 |
|---|---|
$variable | 輸出變數 toString(),找不到輸出原字面值 |
$obj.property | 自動呼叫 getProperty() 或直接存取欄位(反射) |
#if ... #else #end | 條件判斷 |
#foreach($item in $list) ... #end | 迭代 Collection/Array/Iterator |
#set($x = 1) | 賦值 |
#include("file") | 靜態包含 |
#parse("file") | 動態解析包含 |
email.vm親愛的 $customer.name:
您的帳戶餘額是 $customer.balance
致禮!
某某公司
#if($month == 12)
祝您聖誕快樂!
#end
VelocityContext ctx = new VelocityContext();
ctx.put("customer", customer); // 直接放入領域物件
ctx.put("month", Calendar.getInstance().get(Calendar.MONTH) + 1);
StringWriter writer = new StringWriter();
Velocity.mergeTemplate("email.vm", "UTF-8", ctx, writer);
mail.send(customer.getEmail(), "帳單", writer.toString());
Template tmpl = Velocity.getTemplate("report.vm");
VelocityContext ctx = new VelocityContext();
ctx.put("customers", CustomerDAO.getAll());
response.setContentType("text/html;charset=UTF-8");
Velocity.mergeTemplate("report.vm", "UTF-8", ctx, response.getWriter());
<html><body><h1>客戶報表</h1>
#foreach($c in $customers)
<h2>$c.name</h2>
<table>
#foreach($tx in $c.transactions)
<tr><td>$tx.date</td><td>$tx.desc</td><td>$tx.amount</td></tr>
#end
<tr><td colspan="2">總計</td><td><b>$c.total</b></td></tr>
</table>
#end
</body></html>
Properties props = new Properties();
props.setProperty("file.resource.loader.cache", "true");
props.setProperty("file.resource.loader.modificationCheckInterval", "3600"); // 秒
Velocity.init(props);
Directive 擴展標籤(如 #paginate)。VelocityTools 提供 $date, $number, $link 等常用工具。模板引擎以「邏輯與視圖分離」解決文字生成維護難題。Velocity 語法極簡、學習曲線平緩,適合非技術人員協作。核心流程:Context.put(data) → Template.merge(context, writer)。生產環境務必啟用快取。現代專案可考慮 FreeMarker/Thymeleaf 獲得更好 IDE 支援與型別安全,但「模板化思想」永不過時。