自定义JackSon配置

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

先看代码:

 /*
    * 根据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() 后就精度丢了!

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

{
  "orderId": "9223372036854775807"
}

前端拿到字符串后,自己解析或展示,不会丢精度!
因此我们要创建自定义模块来注册,序列化器,反序列化器

自定义Jackson ObjectMapper

SimpleModule simpleModule = new SimpleModule()
序列化器

这个是反序列化器(json->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):

.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架构信息转换器
具体代码如下:

/*
    * 扩展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默认的静态资源映射失效了。
重写静态资源映射就可以了:

/*
    * 设置静态资源映射*/
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        log.info("开始进行静态资源映射...");
        registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/static/backend/");
        registry.addResourceHandler("/front/**").addResourceLocations("classpath:/static/front/");
    }
在Spring Boot中,可以通过自定义Jackson来实现自定义序列化和反序列化的需求。以下是一个简单的示例,演示了如何自定义Jackson。 首先,我们需要创建一个Jackson的ObjectMapper Bean,并指定我们自定义的序列化器和反序列化器。示例中,我们自定义了一个格式化日期的序列化器和反序列化器。 ```java @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(Date.class, new CustomDateSerializer()); module.addDeserializer(Date.class, new CustomDateDeserializer()); objectMapper.registerModule(module); return objectMapper; } } ``` 然后,我们需要实现自定义的序列化器和反序列化器。示例中,我们自定义了一个格式化日期的序列化器和反序列化器。 ```java public class CustomDateSerializer extends JsonSerializer<Date> { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(dateFormat.format(value)); } } public class CustomDateDeserializer extends JsonDeserializer<Date> { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String dateValue = p.getText(); try { return dateFormat.parse(dateValue); } catch (ParseException e) { throw new RuntimeException(e); } } } ``` 现在,我们已经完成了自定义Jackson配置。在使用时,我们可以直接使用@Autowired注解注入ObjectMapper Bean,或者使用@JsonComponent注解来标识我们的自定义序列化器和反序列化器。 ```java @RestController public class UserController { @Autowired private ObjectMapper objectMapper; @PostMapping("/user") public User addUser(@RequestBody User user) throws JsonProcessingException { String json = objectMapper.writeValueAsString(user); System.out.println(json); return user; } } @JsonComponent public class DateJsonComponent { public static class Serializer extends JsonSerializer<Date> { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(dateFormat.format(value)); } } public static class Deserializer extends JsonDeserializer<Date> { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String dateValue = p.getText(); try { return dateFormat.parse(dateValue); } catch (ParseException e) { throw new RuntimeException(e); } } } } ``` 以上就是自定义Jackson的简单示例。通过自定义Jackson,我们可以轻松实现自定义的序列化和反序列化需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值