1、前言
對于Long 類型的資料,如果我們在Controller層通過@ResponseBody将傳回資料自動轉換成json時,不做任何處理,而直接傳給前端的話,在Long長度大于17位時會出現精度丢失的問題。
至于為啥丢失,我們在此處不探讨。
如圖所示:後端傳回資料如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZwpmL1EDN3MTN0kzNx0iM0UDMwATN0ETMycDM3EDMy0CN0ATM3ETMvw1NwcTMwIzLcRDNwEzNxEzLcd2bsJ2Lc12bj5ycn9Gbi52YuUTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.jpg)
而前端接收的資料時就丢失了精度
2、簡單分析
首先,我們分析一下@ResponseBody是怎樣将一個普通的對象轉換成Json對象傳回。
@responseBody注解的作用是将controller的方法傳回的對象通過适當的轉換器(預設使用MappingJackson2HttpMessageConverte(Spring 4.x以下使用的是MappingJackson2HttpMessageConverte))轉換為指定的格式之後,寫入到response對象的body區,需要注意的是,在使用此注解之後不會再走試圖處理器,而是直接将資料寫入到輸入流中,他的效果等同于通過response對象輸出指定格式的資料。
作用等同于response.getWriter.write(JSONObject.fromObject(user).toString());
3、怎麼處理
總的來說主要有兩種處理方式
如何避免精度丢失呢?最常用的辦法就是待轉化的字段統一轉成String類型
那麼怎樣轉化呢?
一般有兩種方式:
首先我們要在maven中添加必須的依賴
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.6</version>
</dependency>
方式一.
1、在待轉化的字段之上加上@JsonSerialize(using=ToStringSerializer.class)注解,如圖所示:
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProductVo {
@JsonSerialize(using=ToStringSerializer.class)
private Long productId
private String productName;
get,set省略
Controller方法不需要特殊處理,但是使用這種時,如果需要轉換的字段較多,就顯得比較繁瑣。
讓我們看看效果
方法二.
是以,我們可以采用配置spring的消息轉換器的ObjectMapper為自定義的類
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
super();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
registerModule(simpleModule);
}
}
然後,我們還需要在SpringMVC的配置檔案中加上如下配置
<mvc:annotation-driven >
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg index="0" value="utf-8" />
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
<-對日期進行轉化的->
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.jay.jackson.util.CustomObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />
</bean>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
至此就大功告成了,Controller方法不需要特殊處理,代碼如下:
/**
* 跳轉到首頁
* @param request
* @param response
*/
@RequestMapping(value="/index", method = RequestMethod.GET)
public String page(HttpServletRequest request, HttpServletResponse response){
return "/index";
}
@RequestMapping(value = "/getProducts",method = RequestMethod.POST)
@ResponseBody
public List getProducts(HttpServletRequest request,HttpServletResponse response){
List<ProductVo> productVos=new ArrayList<>();
for (int i=1;i<=2;i++){
ProductVo productVo= new ProductVo();
productVo.setProductId(20170720125047233L+i);
productVo.setProductName("測試商品"+i);
productVos.add(productVo);
}
return productVos;
}
@RequestMapping(value = "/getUsers",method = RequestMethod.POST)
@ResponseBody
public List<UserVo> getUsers(){
List<UserVo> userVos=new ArrayList<>();
for (int i=1;i<=2;i++){
UserVo userVo=new UserVo();
userVo.setUserid((long)i);
userVo.setUserName("測試使用者"+i);
userVo.setCreateTime(new Date());
userVos.add(userVo);
}
return userVos;
}
我們來看效果。
相關代碼:https://github.com/XWxiaowei/JavaWeb.git