基于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> 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 map = new HashMap<>();
              map.put("name", "张三");
              map.put("age", 18L);
              return map;
          }
      }
      • 不添加转换器

        • 添加转换器