zoukankan      html  css  js  c++  java
  • Spring MVC自定义消息转换器(可解决Long类型数据传入前端精度丢失的问题)

    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

     

  • 相关阅读:
    不叹惜、不呼唤我也不哭泣
    WCF笔记(一)Service Layer and Channel Layer
    C#数据结构(四)树和二叉树
    Python and django(四)详解python中的数字和序列
    Python and django(三)python中的对象
    IIS与ASP.NET Http Runtime Pipeline
    迈进程序员的大门
    实例学习SSIS(四)使用日志记录和错误流重定向
    DbUtility alpha1版本发布
    关于ref和out的详细区别。
  • 原文地址:https://www.cnblogs.com/Fly-Bob/p/7218006.html
Copyright © 2011-2022 走看看