Spring MVC自定义消息转换器(可解决Long类型数据传入前端精度丢失的问题)

简介: 对于Long 类型的数据,如果我们在Controller层通过@ResponseBody将返回数据自动转换成json时,不做任何处理,而直接传给前端的话,在Long长度大于17位时会出现精度丢失的问题。

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

 

相关文章
|
2月前
|
存储 监控 安全
前端框架的数据驱动方式如何保证数据的安全性?
总之,前端框架的数据驱动方式需要综合运用多种手段来保证数据的安全性。从传输、存储、访问控制到防范攻击等各个方面进行全面考虑和实施,以确保用户数据的安全可靠。同时,不断加强安全管理和技术创新,以应对不断变化的安全挑战。
112 60
|
11天前
|
XML Java 数据格式
使用idea中的Live Templates自定义自动生成Spring所需的XML配置文件格式
本文介绍了在使用Spring框架时,如何通过创建`applicationContext.xml`配置文件来管理对象。首先,在resources目录下新建XML配置文件,并通过IDEA自动生成部分配置。为完善配置,特别是添加AOP支持,可以通过IDEA的Live Templates功能自定义XML模板。具体步骤包括:连续按两次Shift搜索Live Templates,配置模板内容,输入特定前缀(如spring)并按Tab键即可快速生成完整的Spring配置文件。这样可以大大提高开发效率,减少重复工作。
使用idea中的Live Templates自定义自动生成Spring所需的XML配置文件格式
|
11天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
18天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
68 14
|
18天前
|
设计模式 前端开发 Java
步步深入SpringMvc DispatcherServlet源码掌握springmvc全流程原理
通过对 `DispatcherServlet`源码的深入剖析,我们了解了SpringMVC请求处理的全流程。`DispatcherServlet`作为前端控制器,负责请求的接收和分发,处理器映射和适配负责将请求分派到具体的处理器方法,视图解析器负责生成和渲染视图。理解这些核心组件及其交互原理,有助于开发者更好地使用和扩展SpringMVC框架。
30 4
|
2月前
|
前端开发 数据安全/隐私保护
.自定义认证前端页面
.自定义认证前端页面
14 1
.自定义认证前端页面
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
142 2
|
2月前
|
安全 Java 应用服务中间件
如何将Spring Boot应用程序运行到自定义端口
如何将Spring Boot应用程序运行到自定义端口
64 0
|
3月前
|
监控 JavaScript 前端开发
前端的混合之路Meteor篇(六):发布订阅示例代码及如何将Meteor的响应数据映射到vue3的reactive系统
本文介绍了 Meteor 3.0 中的发布-订阅模型,详细讲解了如何在服务器端通过 `Meteor.publish` 发布数据,包括简单发布和自定义发布。客户端则通过 `Meteor.subscribe` 订阅数据,并使用 MiniMongo 实现实时数据同步。此外,还展示了如何在 Vue 3 中将 MiniMongo 的 `cursor` 转化为响应式数组,实现数据的自动更新。
|
3月前
|
JSON 分布式计算 前端开发
前端的全栈之路Meteor篇(七):轻量的NoSql分布式数据协议同步协议DDP深度剖析
本文深入探讨了DDP(Distributed Data Protocol)协议,这是一种在Meteor框架中广泛使用的发布/订阅协议,支持实时数据同步。文章详细介绍了DDP的主要特点、消息类型、协议流程及其在Meteor中的应用,包括实时数据同步、用户界面响应、分布式计算、多客户端协作和离线支持等。通过学习DDP,开发者可以构建响应迅速、适应性强的现代Web应用。