天天看點

Spring MVC自定義消息轉換器(可解決Long類型資料傳入前端精度丢失的問題)

1、前言

對于Long 類型的資料,如果我們在Controller層通過@ResponseBody将傳回資料自動轉換成json時,不做任何處理,而直接傳給前端的話,在Long長度大于17位時會出現精度丢失的問題。

至于為啥丢失,我們在此處不探讨。

如圖所示:後端傳回資料如下:

Spring MVC自定義消息轉換器(可解決Long類型資料傳入前端精度丢失的問題)

而前端接收的資料時就丢失了精度

Spring MVC自定義消息轉換器(可解決Long類型資料傳入前端精度丢失的問題)

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 MVC自定義消息轉換器(可解決Long類型資料傳入前端精度丢失的問題)

方法二.

是以,我們可以采用配置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;
    }      

我們來看效果。

Spring MVC自定義消息轉換器(可解決Long類型資料傳入前端精度丢失的問題)

 相關代碼:https://github.com/XWxiaowei/JavaWeb.git

繼續閱讀