Spring Boot配置:将特定格式字符串转换为JavaMoney字段
解决Spring Boot中把自定义格式货币字符串转成JavaMoney的问题
这个场景我之前帮同事处理过,核心就是搞定Jackson的反序列化逻辑+JavaMoney的配置,一步步来就行:
1. 先添加必要的依赖
首先得引入JavaMoney的API、参考实现,还有Jackson专门处理JavaMoney的模块,不然Spring Boot没法识别Money类型的序列化/反序列化。
Maven 依赖(pom.xml)
<!-- JavaMoney API 核心包 --> <dependency> <groupId>org.javamoney</groupId> <artifactId>moneta-api</artifactId> <version>1.4.2</version> </dependency> <!-- JavaMoney 官方参考实现 --> <dependency> <groupId>org.javamoney</groupId> <artifactId>moneta</artifactId> <version>1.4.2</version> <classifier>all</classifier> </dependency> <!-- Jackson 适配JavaMoney的模块 --> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-money</artifactId> <version>2.15.2</version> </dependency>
Gradle 依赖(build.gradle)
implementation 'org.javamoney:moneta-api:1.4.2' implementation 'org.javamoney:moneta:1.4.2:all' implementation 'com.fasterxml.jackson.datatype:jackson-datatype-money:2.15.2'
2. 处理自定义数字格式的反序列化
你收到的"12.323,44"是欧洲风格数字格式(千分位用.,小数点用,),默认的Jackson Money模块识别不了,所以需要自定义反序列化逻辑。
方式一:给实体字段加注解(局部生效)
先写一个自定义反序列化器:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import org.javamoney.moneta.Money; import javax.money.Monetary; import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; public class EuroStyleMoneyDeserializer extends StdDeserializer<Money> { // 用德国Locale适配千分位.、小数点,的格式,欧洲多数国家通用 private static final NumberFormat EURO_NUMBER_FORMAT = NumberFormat.getNumberInstance(Locale.GERMAN); protected EuroStyleMoneyDeserializer() { super(Money.class); } @Override public Money deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String amountStr = p.getText(); try { // 解析字符串为数字 Number parsedNumber = EURO_NUMBER_FORMAT.parse(amountStr); // 这里默认用EUR作为货币代码,若需动态切换可调整逻辑(比如从请求参数取) return Money.of(parsedNumber.doubleValue(), Monetary.getCurrency("EUR")); } catch (Exception e) { throw new IOException("解析货币字符串失败: " + amountStr, e); } } }
然后在你的实体类字段上指定这个反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import org.javamoney.moneta.Money; public class MyObject { private Long id; @JsonDeserialize(using = EuroStyleMoneyDeserializer.class) private Money amount; // 记得生成getter、setter、构造方法 }
方式二:全局配置Jackson(推荐,所有Money字段生效)
如果不想每个实体都加注解,直接全局配置ObjectMapper:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.money.MoneyModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; @Configuration public class JacksonMoneyConfig { @Bean public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.build(); // 注册Jackson的JavaMoney模块 objectMapper.registerModule(new MoneyModule()); // 替换Money类型的默认反序列化器为自定义实现 objectMapper.configOverride(Money.class) .setDeserializer(com.fasterxml.jackson.databind.deser.BeanDeserializerModifier.modifyDeserializer( objectMapper.getDeserializationConfig(), Money.class, new EuroStyleMoneyDeserializer() )); return objectMapper; } }
3. 关键注意点
- 货币代码:上面默认用了EUR,如果你需要支持多货币,可以把货币代码作为请求的额外字段,或者在配置里设置默认货币。
- 精度问题:用
doubleValue()可能有精度损失,追求高精度的话可以转成BigDecimal处理:BigDecimal amountBigDecimal = new BigDecimal(parsedNumber.toString()); return Money.of(amountBigDecimal, Monetary.getCurrency("EUR")); - Locale适配:如果你的输入格式对应其他地区,只需要替换
Locale.GERMAN为对应Locale即可(比如法国、意大利的Locale也支持这种格式)。
配置完成后,Spring Boot就能自动把{"id": 1, "amount": "12.323,44"}转换成MyObject实例,其中amount字段就是Money类型的EUR 12323.44。
内容的提问来源于stack exchange,提问作者Fabio Ebner
相关产品推荐
相关产品推荐

