今天测试突然跟我说页面显示的数值和数据库的对应不上,一开始我以为是程序问题,把数据给修改了,但是后面检查程序发现,没有任务问题,用postman请求,发现数据也和数据库的一致。但是页面上面显示的就是不一样。
问题追踪
一开始我怀疑是前端转型把精度丢失,前端那边直接是通过Number接收的,没有任何转型操作。后来我怀疑可能是因为服务器是Long类型,前端是Number类型,可能是精度对应不上,后面一查资料发现还真是这个问题。
Number和Long精度
Number的最大长度是2的53次,也就是9007199254740992,而Long的最大长度是2的64次,也就是9223372036854775807。所以会出现精度丢失的情况。
解决方案
要解决这个问题其实不难,只要将Long类型变为String类型即可,但是我们不可能直接将字段修改为String,这样会涉及很多模块代码的修改,工作量和安全性都会受到影响。
还有一种办法是重新再添加一个新的字段,然后get的时候将需要的字段转为字符串返回即可,如下所示:
private Long userId;
private String userIdStr;
public String getUserIdStr() {
return this.userId+"";
}
public void setUserIdStr(String userIdStr) {
this.userIdStr = userIdStr;
}
但是这样一方面需要修改dto对象的字段,另一方面前端也需要相应的修改,如果有很多地方需要这样做,那工作量也是非常大的,所以这种方式也是不可取的。
方案筛选
最理想的方案应该是不修改字段任何属性,因为这样前端就不需要变动。(如果前端指定具体接收类型,那就需要修改),在序列化返回给前端的时候将Long类型的字段转为String类型。
这边就给大家介绍一下jackson是如何进行序列化和反序列化的。
首先我们来看一下没有进行任何序列化修改,Long类型怎么输出的?我们先来看一下代码。
@RequestMapping(value = "testDemo", method = RequestMethod.GET)
@ResponseBody
public TestDto testDemo() {
TestDto testDto = new TestDto();
testDto.setId(Long.valueOf("123456789012345678"));
return testDto;
}
@Data
public class TestDto {
/**
* ID标识
*/
private Long id;
}
接下来我们用postman请求一下,看看返回的结果是啥样的?
{
"id": 123456789012345678
}
我们可以看到String类型的返回结果是没有双引号或者单引号的,我们修改一下id字段的类型(从Long类型修改为String),看看输出结果有什么不一样。
@Data
public class TestDto {
/**
* ID标识
*/
private String id;
}
输出结果:
{
"id": "123456789012345678"
}
我们可以很明显的看到,字段id值是有双引号的。那我们如何在不修改任何代码的情况下,返回值值从Long类型修改为Stirng,返回给前端。
接下来就是重头戏了,我们先写一个Annotation注解,如下所示:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@JacksonAnnotationsInside
@JsonSerialize(using = LongToStringSerializer.class)
public @interface LongToString {
}
不懂@Retention和@Target含义的童鞋,可以自行百度。
重点在LongToStringSerializer类中,该类的作用是进行json序列化,它有一个serialize方法,允许我们对序列化的字段进行修改,具体我们来看一下代码:
public class LongToStringSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(String.valueOf(value));
}
}
这边我们将原来是Long类型的字段,重写为String类型,最后我们用postman来测试一下,返回结果是否包含双引号。
{
"id": "123456789012345678"
}
从结果我们可以很明显的看出,id字段的类型是String,期间我们没有修改id字段的类型,但是通过jackson序列化的时候进行字段类型重写,就可以轻轻松松实现类型的修改。
总结
用法虽然很简单,但是这其中过程是怎么样的呢,到底在什么时候会进行对象序列化输出?我们下一节来具体给大家介绍一下。今天文章分享就到这边,谢谢童鞋们的阅读~
想要更多干货、技术猛料的孩子,快点拿起手机扫码关注我,我在这里等你哦~
林老师带你学编程:https://wolzq.com