如何在FreeMarker模板中按Locale格式化金额数据
FreeMarker 根据 Locale 格式化金额字段的解决方案
核心问题分析
你之前的尝试存在两个关键错误:
- 使用
${data.amount?string("${data.locale}")}时,传入的是字符串类型的Locale标识,但FreeMarker的?string方法需要的是**java.util.Locale对象**,不是字符串; - DTO中格式化方法调用报错,大概率是方法访问权限、签名或调用方式不符合FreeMarker的要求。
可行解决方案
方案1:直接用FreeMarker内置格式化(推荐)
先确保你的DataDto中存储的是java.util.Locale类型的locale对象(如果之前是字符串,后端提前转成Locale,比如new Locale("fi", "FI")),然后在FTL中按以下方式调用:
- 基础数字格式化(自动适配Locale的小数分隔符):
${data.amount?string.number(data.locale)} - 固定保留两位小数(结合Locale替换分隔符):
这样${data.amount?string("0.00", data.locale)}fi_FIlocale下会输出1,00,us_US下输出1.00。
方案2:如果DTO中Locale是字符串类型
如果因为业务限制,DataDto里只能存字符串格式的Locale(比如"fi_FI"),可以在后端或模板中转成Locale对象:
- 后端处理(推荐):给
DataDto加一个获取Locale对象的方法:
然后FTL中调用:public Locale getLocaleObject() { String[] parts = this.locale.split("_"); return new Locale(parts[0], parts[1]); }${data.amount?string("0.00", data.localeObject)} - 模板处理(不推荐,尽量后端做):
<#assign localeParts = data.locale?split("_")> <#assign targetLocale = locale(localeParts[0], localeParts[1])> ${data.amount?string("0.00", targetLocale)}
方案3:修复DTO中格式化方法的调用问题
如果想在DTO中封装格式化逻辑,检查以下几点:
- 方法必须是public修饰的实例方法;
- 方法签名正确,比如:
public String getFormattedAmount() { NumberFormat formatter = NumberFormat.getNumberInstance(this.locale); formatter.setMinimumFractionDigits(2); formatter.setMaximumFractionDigits(2); return formatter.format(this.amount); } - FTL中调用时直接用属性访问式(FreeMarker会自动识别getter方法):
不要写成${data.formattedAmount}${data.getFormattedAmount()}(虽然也能运行,但不符合FreeMarker的约定)。
方案4:全局设置Locale(适用于单Locale场景)
如果整个PDF生成过程只需要用同一个Locale,可以在FreeMarker配置中全局设置:
Configuration cfg = new Configuration(Configuration.VERSION_2_3_32); cfg.setLocale(targetLocale); // 比如data.getLocale()
之后模板中直接写:
${data.amount?string("0.00")}
就会自动应用全局设置的Locale格式。
内容的提问来源于stack exchange,提问作者The_new_coder
相关产品推荐
相关产品推荐

