Purpose
FreeMarker allows you to define your own number and date/time/datetime formats, and associate a name to them.
Here has an example to demonstrate how to convert amount from 2380 to NT$2,380.
How-To
1. Create custom number format class:
package com.cht.tool.filegenerator.ftl.custom;
import freemarker.core.Environment;
import freemarker.core.TemplateFormatUtil;
import freemarker.core.TemplateNumberFormat;
import freemarker.core.TemplateNumberFormatFactory;
import freemarker.core.TemplateValueFormatException;
import freemarker.core.UnformattableValueException;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateNumberModel;
import freemarker.template.utility.NumberUtil;
import java.text.DecimalFormat;
import java.util.Locale;
/**
* 將金額加上千分號,並註明新台幣 NT
* <p>
* 使用方式 ${total?string.@ntd},2380 會被轉換為 NT$2,380
*/
public class NTDTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
public static final NTDTemplateNumberFormatFactory INSTANCE = new NTDTemplateNumberFormatFactory();
private static DecimalFormat ntdFormat = new DecimalFormat("NT$#,###");
private NTDTemplateNumberFormatFactory() {
// Defined to decrease visibility
}
@Override
public TemplateNumberFormat get(String s, Locale locale, Environment environment)
throws TemplateValueFormatException {
TemplateFormatUtil.checkHasNoParameters(s);
return NTDTemplateStringFormat.INSTANCE;
}
private static class NTDTemplateStringFormat extends TemplateNumberFormat {
private static final NTDTemplateStringFormat INSTANCE = new NTDTemplateStringFormat();
private NTDTemplateStringFormat() {
// Defined to decrease visibility
}
/**
* 2380 會被轉換為 NT$2,380 的邏輯寫在這裡
*
* @param numberModel
* @return
* @throws TemplateValueFormatException
* @throws TemplateModelException
*/
@Override
public String formatToPlainText(TemplateNumberModel numberModel)
throws TemplateValueFormatException, TemplateModelException {
Number number = TemplateFormatUtil.getNonNullNumber(numberModel);
try {
return ntdFormat.format(NumberUtil.toIntExact(number));
} catch (RuntimeException e) {
throw new UnformattableValueException(number + " - 金額轉換失敗", e);
}
}
@Override
public boolean isLocaleBound() {
return false;
}
@Override
public String getDescription() {
return "數字轉新台幣";
}
}
}
2. Register to freemarker configuration class:
Configuration cfg = new Configuration(Configuration.getVersion());
cfg.setClassForTemplateLoading(this.getClass(), "/");
// register the "ntd" format:
Map<String, TemplateNumberFormatFactory> customNumberFormats = new HashMap<>();
customNumberFormats.put("ntd", NTDTemplateNumberFormatFactory.INSTANCE);
cfg.setCustomNumberFormats(customNumberFormats);
3. Use this format in ftl template file:
<#-- 取得現在時間 -->
<#assign aDateTime = .now>
<#-- 只保留日期 -->
<#assign aDate = aDateTime?date>
<#-- create the macro variable: -->
<#macro printDate mingguodate>
列印日期:${mingguodate}
</#macro>
<#macro footer records amount>
${"-"?right_pad(25, "-")}
總筆數:${records}
總金額:${amount}
</#macro>
<#-- call the macro: -->
<@printDate mingguodate="${aDate?string.@mingguo}" />
<#assign total = 0>
${"水果名稱"?right_pad(10)}${"單價"?right_pad(10)}${"訂購數量"?right_pad(10)}
${"-"?right_pad(25, "-")}
<#list rows as row>
<#assign total += row.price * row.quantity>
${row.name?right_pad(10)}${row.price?string.@ntd?left_pad(10)}${row.quantity?left_pad(10)}
</#list>
<#-- call the macro: -->
<@footer records="${rows?size?left_pad(10)}" amount="${total?string.@ntd?left_pad(10)}" />
Reference