基于Jackson自定义json数据的对象转换器

1、问题说明

后端数据表定义的id主键是Long类型,一共有20多位。 前端在接收到后端返回的json数据时,Long类型会默认当做数值类型进行处理。但前端处理20多位的数值会造成精度丢失,于是导致前端查询数据出现问题。

  • 测试前端Long类型的代码
  • 实际显示效果

2、解决方法

在SpringBoot项目中,默认使用Jackson 来序列化和反序列化 json数据,针对上面的问题,决定采用自定义对象转换器的方式,在后端将数据转为json数据时,将Long类型的数据,统一转换为String类型,再转为json数据返回,避免前端处理Long类型数据造成精度丢失。

3、具体代码实现

在将controller层的返回值数据转为json数据时,需要经过消息转换器MappingJackson2HttpMessageConverter的处理。因此,只需要在消息转换器中判断如果是Long类型的数据,就转换为String类型,再进行json数据的转换。 在代码中,只需要重写extendMessageConverters()方法,添加自定义的对象转换器即可。

  1. 编写JacksonObjectMapper对象转换器

该自定义的对象转换器, 主要指定了在进行json数据序列化及反序列化时, LocalDateTime、LocalDate、LocalTime的处理方式,以及BigInteger和Long类型数据,在序列化时直接转换为字符串。

复制代码
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;

/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
        //反序列化时,属性不存在的兼容处理
  this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        SimpleModule simpleModule = new SimpleModule()
            	// 反序列化时的处理 
                .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)))

            	// 序列化时的处理 
                // 处理 BigInteger 类型
                .addSerializer(BigInteger.class, ToStringSerializer.instance)
                // 处理 Long 类型
                .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)));
        //注册功能模块,添加自定义序列化与反序列化器
        this.registerModule(simpleModule);
    }
}

2)在WebMvcConfig中重写方法extendMessageConverters,添加自定义对象转换器

复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;


@Configuration
@Slf4j
public class WebMvcConfig implements WebMvcConfigurer {
    /**
     * 扩展mvc框架的消息转换器
     * @param converters
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器...");
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,底层使用Jackson将Java对象转为json
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //将上面的消息转换器对象追加到mvc框架的转换器集合中
        converters.add(0,messageConverter);
    }
}

4、测试

复制代码
@RestController
public class TestController {

    @GetMapping("/test")
    public Map test(){
        Map<String, Object> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", 18L);
        return map;
    }

}
  • 不添加转换器
  • 添加转换器
相关推荐
程序猿阿越7 小时前
Kafka源码(七)事务消息
java·后端·源码阅读
m0_748248027 小时前
C++20 协程:在 AI 推理引擎中的深度应用
java·c++·人工智能·c++20
笑我归无处7 小时前
强引用、软引用、弱引用、虚引用详解
java·开发语言·jvm
02苏_7 小时前
秋招Java面
java·开发语言
爱吃甜品的糯米团子8 小时前
详解 JavaScript 内置对象与包装类型:方法、案例与实战
java·开发语言·javascript
程序定小飞8 小时前
基于springboot的学院班级回忆录的设计与实现
java·vue.js·spring boot·后端·spring
攀小黑8 小时前
基于若依-内容管理动态修改,通过路由字典配置动态管理
java·vue.js·spring boot·前端框架·ruoyi
青云交9 小时前
Java 大视界 -- 基于 Java 的大数据可视化在城市空气质量监测与污染溯源中的应用
java·spark·lstm·可视化·java 大数据·空气质量监测·污染溯源
森语林溪9 小时前
大数据环境搭建从零开始(十七):JDK 17 安装与配置完整指南
java·大数据·开发语言·centos·vmware·软件需求·虚拟机
郝开10 小时前
Spring Boot 2.7.18(最终 2.x 系列版本)1 - 技术选型:连接池技术选型对比;接口文档技术选型对比
java·spring boot·spring