问题现象
后端接口返回:
{
"price": 5.0
}在浏览器 Network → Response 中可以看到:
{
"price": 5.0
}但是在 Network → Preview 中:
{
"price": 5
}前端页面显示:
5
而不是:
5.000
原因分析
JSON Number 不保存数字格式
JSON 中的数字类型只保存 数值本身,不会保存数字格式。
例如:
{
"price": 5
}和:
{
"price": 5.0
}对于 JSON 解析器来说完全一样。
JavaScript:
5 === 5.0;结果:
true原因是 JavaScript 使用:
Number类型存储数字。
它不会记录:
- 小数位数量
- 尾随 0
- 原始输入格式
例如:
const price = 5.0;
console.log(price);输出:
5浏览器为什么 Response 和 Preview 不一致?
Response
Network 中 Response 显示的是:
后端返回的原始 HTTP 响应文本
例如:
{
"price": 5.0
}Preview
Preview 显示的是:
浏览器解析 JSON 后生成的 JavaScript 对象
解析过程:
JSON.parse('{"price":5.000}');结果:
{
price: 5;
}因为:
5.000 → Number → 5
如何解决
方案一:后端返回字符串
适用于:
- 金额
- 汇率
- 单价
- 财务数据
- 精度敏感字段
后端返回:
{
"price": "5.000"
}前端:
row.price;结果:
"5.000"优点:
- 保留展示格式
- 不丢失精度
- 适合财务系统
缺点:
前端计算时需要转换:
Number(price);方案二:前端格式化显示
如果接口返回:
{
"price": 5
}展示时处理:
Number(price).toFixed(3);结果:
5.000项目中建议统一处理:
export function formatDecimal(value, digit = 3) {
if (value === null || value === undefined) {
return '-';
}
return Number(value).toFixed(digit);
}使用:
{{ formatDecimal(row.price, 3) }}效果:
| 后端返回 | 页面显示 |
|---|---|
| 5 | 5.000 |
| 5.0 | 5.000 |
| 5.000 | 5.000 |
| 5.123 | 5.123 |
Java 后端处理
BigDecimal 问题
Java:
BigDecimal price =
new BigDecimal("5.000");序列化:
{
"price": 5.0
}但是:
浏览器解析后:
{
price: 5;
}依然会丢失格式。
返回字符串
例如:
price.toPlainString()返回:
{
"price": "5.000"
}或者:
@JsonSerialize(using = ToStringSerializer.class)
private BigDecimal price;企业系统最佳实践
对于:
- ERP
- CRM
- SRM
- 财务系统
- 报价系统
- 供应链系统
推荐设计:
数据层
使用:
BigDecimal
保证计算精度。
API 层
金额字段:
{
"amount": "123.4500"
}使用字符串传输。
前端展示层
统一格式化:
formatDecimal(amount, 4);项目实践建议
仅用于展示
例如:
- 单价
- 汇率
- 税率
- 成本
推荐:
后端返回字符串
+
前端统一格式化
参与计算
例如:
- 总价
- 毛利
- 成本计算
推荐:
后端 BigDecimal 计算
+
返回字符串结果
避免 JavaScript Number 精度问题。
总结
核心原因:
JSON Number 只保存数值,不保存数字格式,因此
5.000在 JavaScript 中会变成5。
如果需要保留:
5.000
必须:
- 后端返回字符串:
{
"price": "5.000"
}或者:
- 前端展示时格式化:
Number(price).toFixed(3);企业系统中(ERP / SRM / 财务类系统)通常采用:
BigDecimal
+
String API 返回
+
前端统一格式化展示