自定义JackSon配置

避免前端(JavaScript)处理大数(如 Long、BigInteger)时发生精度丢失问题,所以引入了自定义 Jackson 配置。

先看代码:

java 复制代码
 /*
    * 根据id修改员工信息*/
    @PutMapping
    public R<String> update(HttpServletRequest request,@RequestBody Employee employee){
        log.info(employee.toString());

        Long empId = (Long)request.getSession().getAttribute("employee");
        employee.setUpdateTime(LocalDateTime.now());
        employee.setUpdateUser(empId);
        employeeService.updateById(employee);

        return R.success("员工信息修改成功");
    }

这里由于要修改的员工信息的id是通过mp雪花算法得到的超长数字,js前端在访问这个数据的时候会出现精度损失,导致后端拿不到这个id,因此无法更新数据

1. jackson 是什么?

Jackson 是一个功能强大的 Java 类库,主要用于在 Java 对象 和 JSON 数据之间做转换。

它可以:

把 Java 对象 转成 JSON 字符串(序列化)

把 JSON 字符串 解析成 Java 对象(反序列化)

你可以把 Jackson 理解为 Java 世界里的 "JSON翻译器"。

官网地址:https://github.com/FasterXML/jackson

在 Java 里常用的 JSON 处理库有:

Jackson (最流行)

Gson (Google出的,也挺常见)

Fastjson (阿里出的,国内有些公司用)

其中 Jackson 在 Spring Boot 里默认就是集成的(不用特地引)。

这里我们用json来处理

2. jackson 和 json 是什么关系?

JSON(JavaScript Object Notation) 是一种数据交换格式,本身跟 Jackson 没有直接关系。

Jackson 是处理 JSON 的工具,是帮你在 Java 中读写 JSON 的 实现库。

换句话说,JSON 是标准,Jackson 是工具。

就像:"水(JSON)是资源,桶(Jackson)是工具",你用 Jackson 来搬运、转换 JSON 数据。

为什么要特别处理 Long / BigInteger?

这个非常关键!

原因是 JavaScript 的 number 类型(双精度浮点数)在 2^53(大约 16位整数)之后就会失真。

在前端(特别是Vue、React)里,如果后端直接返回数字格式的 Long 或 BigInteger,前端 JSON.parse() 后就精度丢了!

所以你要在后端 把这些大整数转成字符串输出,前端才能安全处理,比如:

json 复制代码
{
  "orderId": "9223372036854775807"
}

前端拿到字符串后,自己解析或展示,不会丢精度!

因此我们要创建自定义模块来注册,序列化器,反序列化器

自定义Jackson ObjectMapper

java 复制代码
SimpleModule simpleModule = new SimpleModule()
序列化器

这个是反序列化器(json->java对象):

java 复制代码
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))

这里针对 Java 8 时间类型(LocalDateTime、LocalDate、LocalTime)指定了解析格式。

例如,遇到 "2025-04-28 12:00:00" 这样的字符串时,能正确反序列化成 LocalDateTime。

反序列化器

接着这里用反序列化器(java对象->json):

java 复制代码
.addSerializer(BigInteger.class, ToStringSerializer.instance)
.addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

将 BigInteger 和 Long 类型序列化为字符串(防止前端 JavaScript 解析大整数丢失精度问题)。

将 LocalDateTime、LocalDate、LocalTime 使用指定格式序列化成字符串。

jackson整体关系类图

处理 继承 <<interface>> JSON +数据格式标准 ObjectMapper +writeValueAsString(Object) : String +readValue(String, Class) : T JacksonObjectMapper +DEFAULT_DATE_FORMAT : String +DEFAULT_DATE_TIME_FORMAT : String +DEFAULT_TIME_FORMAT : String +JacksonObjectMapper()

jacksonObjectMapper结构图

注册模块 添加 添加 添加 添加 添加 添加 添加 JacksonObjectMapper +DEFAULT_DATE_FORMAT : String +DEFAULT_DATE_TIME_FORMAT : String +DEFAULT_TIME_FORMAT : String +JacksonObjectMapper() +configure(FAIL_ON_UNKNOWN_PROPERTIES, false) +registerModule(SimpleModule) SimpleModule +addDeserializer(Type, Deserializer) +addSerializer(Type, Serializer) LocalDateTimeDeserializer LocalDateDeserializer LocalTimeDeserializer LocalDateTimeSerializer LocalDateSerializer LocalTimeSerializer ToStringSerializer

扩展mvc架构的消息转换器

前面知识配置了jackson的信息,但是还没有完成实现,由于后端发给前端的信息的json格式的,而包装发送json数据是mvc设置的,所以我们还需要在mvc配置类中加入扩展mvc架构信息转换器

具体代码如下:

java 复制代码
/*
    * 扩展mvc框架的消息转换器
    * */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,底层使用jackson将java转成json
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //将上面的消息转换器对象追加到mvc框架的转换器集合中
        converters.add(0,messageConverter);
    }

但是这里由于我们扩展了 SpringMVC 配置,导致 Spring Boot 自动配置失效了。 我们继承了一个 MVC 配置类,打破了默认的静态资源映射规则,在 Spring Boot 中(比如用 spring-boot-starter-web):

默认情况下,Spring Boot 自动帮你配置好静态资源访问路径,比如:

/static/

/public/

/resources/

/META-INF/resources/

只要把 HTML、CSS、JS 放在 static 里,可以直接通过 URL 访问,无需自己写 addResourceHandlers()。但是!! 一旦手动继承了 SpringMVC 配置,即使你只是重写 extendMessageConverters(),Spring Boot会认为你要接管整个SpringMVC配置!

于是,Spring Boot默认的静态资源映射失效了。

重写静态资源映射就可以了:

java 复制代码
/*
    * 设置静态资源映射*/
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        log.info("开始进行静态资源映射...");
        registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/static/backend/");
        registry.addResourceHandler("/front/**").addResourceLocations("classpath:/static/front/");
    }
相关推荐
柯34938 分钟前
JVM-类加载机制
java·开发语言·jvm
风雨无阻fywz42 分钟前
java 类的实例化过程,其中的相关顺序 包括有继承的子类等复杂情况,静态成员变量的初始化顺序,这其中jvm在干什么
java·开发语言·jvm
沃野_juededa1 小时前
关于uniapp 中uview input组件设置为readonly 或者disabled input区域不可点击问题
java·前端·uni-app
红烧柯基4 小时前
解决redis序列号和反序列化问题
java·数据库·redis
运维@小兵5 小时前
SpringBoot获取用户信息常见问题(密码屏蔽、驼峰命名和下划线命名的自动转换)
java·spring boot·后端
新时代苦力工5 小时前
Java实现使用EasyExcel按模板导出文件
java
小陈096 小时前
Java后端图形验证码的使用
java·开发语言·状态模式
27669582926 小时前
得物 小程序 6宫格 分析
java·python·小程序·得物·得物小程序·得物六宫格·六宫格验证码
知了一笑6 小时前
通过IP计算分析归属地
java·ip·ip定位·ip计算