1、前言
對於Long 類型的數據,如果我們在Controller層通過@ResponseBody將返回數據自動轉換成json時,不做任何處理,而直接傳給前端的話,在Long長度大於17位時會出現精度丟失的問題。
至於為啥丟失,我們在此處不探討。
如圖所示:后端返回數據如下:

而前端接收的數據時就丟失了精度

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
