前言:
公司项目中有一个板块需要解析JWT令牌获取载荷里面封装的数据,遇到要解析一个BigDecimal类型的数据
问题发现过程:
正常来说,我们解析一个JWT令牌的步骤如下:
public static Claims getDataFromToken(String token){
JwtParser jwtParser = Jwts.parser();
// 通过签名对Token进行解析,得到的结果是一个类似集合的封装类
Jws<Claims> claimsJws = jwtParser.setSigningKey(Constants.TOKEN_SECRET.getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token);
解析出来的类别 xxx= dataFromToken.get("令牌载荷键", 解析出来的类的字节码文件);
}
但是我按照解析Integer、String等类别的数据的做法,通过
BigDecimal price= dataFromToken.get("price", BigDecimal.class);
来解析一个BigDecimal类型的参数会报错,查过后发现好像是这种转换方法并不支持转换BigDecimal类型的数据
为此,我想着先将其解析为一个Double类型的参数,再通过new BigDecimal(double val)方法来将其转换为一个BigDecimal类型的数据
BigDecimal forntPrice = new BigDecimal(0.2);
但经过断点发现 frontPrice 的值不是 0.2,而是 0.200000000000000011102230246251565404236316680908203125 。
问题解决:
查看相关文档:
简单翻一下:
将 double 类型转换成 BigDecimal 类型。
- 这个构造函数的结果在某种程度上是不可预测的。你可能会觉得
new BigDecimal(0.1)
会创建一个刚好等于 0.1 的 BigDecimal,但它实际上等于 0.1000000000000000055511151231257827021181583404541015625 。这是因为 0.1 不能被精确地表示为一个双精度数。 - String 构造函数是完全可预测的,
new BigDecimal("0.1")
会创建一个完全等于 0.1 的 BigDecimal,建议优先使用 String 构造函数。 - 如果必须使用 double 作为转换源时,可以使用
BigDecimal.valueOf(0.1)
,它返回的结果也是精确的。
总结:
将 double 类型转换为 BigDecimal 类型的时候,不要使用new BigDecimal(0.1)
这个构造函数,应为它得到的结果是不精确的,
使用BigDecimal.valueOf(0.1)
或new BigDecimal("0.1")
。
BigDecimal transactionAmount = BigDecimal.valueOf(dataFromToken.get("transactionAmount", Double.class));