1. 简介
本文将介绍如何结合 Thymeleaf,根据用户的区域设置(Locale)动态格式化货币金额。这在国际化(i18n)场景中非常实用,比如多语言电商平台或金融类系统,避免出现 $1000
被德国用户看到的尴尬场面(他们更习惯 1.000,00 €
)。
Thymeleaf 提供了开箱即用的表达式工具类,能轻松实现本地化货币展示,无需手动拼接符号或处理小数位。
2. Maven 依赖
首先引入 Spring Boot 的 Thymeleaf 启动器依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>3.1.5</version>
</dependency>
✅ 这个依赖会自动包含 Thymeleaf 核心库以及与 Spring 集成所需的组件,无需额外引入。
3. 项目搭建
我们构建一个简单的 Spring Web 应用,根据请求头中的 Accept-Language
返回对应地区的货币格式。
3.1 Thymeleaf 模板
在 resources/templates/currencies/
目录下创建 currencies.html
:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Currency table</title>
</head>
<body>
<!-- 内容将在后续步骤填充 -->
</body>
</html>
3.2 控制器
创建处理请求的控制器:
@Controller
public class CurrenciesController {
@GetMapping("/currency")
public String exchange(
@RequestParam(value = "amount", required = false) String amount,
@RequestParam(value = "amountList", required = false) List<String> amountList,
Locale locale) {
// 实际场景中可将数据放入 model,这里简化处理
return "currencies/currencies";
}
}
⚠️ 注意:Locale locale
参数会自动由 Spring 根据 Accept-Language
请求头注入。
4. 货币格式化实战
Thymeleaf 的 #numbers
工具类是本节核心,支持多种本地化数字格式化能力。
4.1 单个货币格式化
使用 #numbers.formatCurrency()
方法,自动根据当前 Locale
格式化金额:
<p th:text="${#numbers.formatCurrency(param.amount)}"></p>
param.amount
是 URL 参数传入的金额字符串- 格式化结果包含货币符号、千分位分隔符、保留两位小数
✅ 示例测试(美国地区):
@Test
public void whenCallCurrencyWithUSALocale_ThenReturnProperCurrency() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/currency")
.header("Accept-Language", "en-US")
.param("amount", "10032.5"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("$10,032.50")));
}
输出:$10,032.50
—— 美元符号 + 逗号分隔 + 小数点
4.2 货币数组格式化
#numbers
还支持直接格式化金额列表,调用 listFormatCurrency()
:
<p th:text="${#numbers.listFormatCurrency(param.amountList)}"></p>
更新控制器以接收列表参数(Spring 自动绑定):
@GetMapping("/currency")
public String exchange(
@RequestParam(value = "amount", required = false) String amount,
@RequestParam(value = "amountList", required = false) List<String> amountList,
Locale locale) {
return "currencies/currencies";
}
✅ 示例测试(英国地区):
@Test
public void whenCallCurrencyWithUkLocaleWithArrays_ThenReturnLocaleCurrencies() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/currency")
.header("Accept-Language", "en-GB")
.param("amountList", "10", "20", "30"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("£10.00, £20.00, £30.00")));
}
输出:£10.00, £20.00, £30.00
—— 英镑符号,逗号分隔各项
4.3 去除末尾零(.00)
有时整数金额不需要显示 .00
,可通过 #strings.replace
简单处理:
<p th:text="${#strings.replace(#numbers.formatCurrency(param.amount), '.00', '')}"></p>
✅ 示例测试(美国地区,整数):
@Test
public void whenCallCurrencyWithUSALocaleWithoutDecimal_ThenReturnCurrencyWithoutTrailingZeros()
throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/currency")
.header("Accept-Language", "en-US")
.param("amount", "10032"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("$10,032")));
}
输出:$10,032
—— 干净利落,无多余小数位
⚠️ 注意:此方法有局限,如金额为 100.50
会被错误替换为 100.5
,实际应保留一位小数。更严谨的做法是先判断是否为整数,或使用自定义 Dialect
。
4.4 自定义小数分隔符
某些地区(如德语区)使用逗号作为小数点。虽然 formatCurrency
会自动适配,但若需手动控制,可用 formatDecimal
:
<p th:text="${#numbers.formatDecimal(param.amount, 1, 2, 'COMMA')}"></p>
参数说明:
param.amount
: 原始数值1
: 整数部分最小位数2
: 小数部分固定位数'COMMA'
: 小数点用逗号表示
✅ 示例测试:
@Test
public void whenCallCurrencyWithUSALocale_ThenReturnReplacedDecimalPoint() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/currency")
.header("Accept-Language", "en-US")
.param("amount", "1.5"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("1,5")));
}
输出:1,5
—— 注意这不是千分位,而是小数点被替换为逗号
⚠️ 踩坑提醒:formatDecimal
不带货币符号,仅格式化数字。如需符号,需手动拼接或仍使用 formatCurrency
。
5. 总结
通过 Thymeleaf 的 #numbers
工具类,我们能以声明式方式实现货币的本地化展示,核心要点如下:
- ✅ 使用
#numbers.formatCurrency()
自动适配Locale
- ✅
listFormatCurrency()
支持金额列表批量格式化 - ✅ 结合
#strings.replace
可简单去除.00
- ✅
formatDecimal
提供更细粒度的数字格式控制
整套方案简单粗暴,适合大多数国际化场景。对于复杂需求(如动态币种、精度控制),建议封装为自定义 Utility
或 Thymeleaf Dialect
。
示例代码已托管至 GitHub: https://github.com/john-doe/spring-thymeleaf-currency-demo