SpringBoot 기본 json 파서 세부 정보 및 필드 직렬화 사용자 정의

머리말

프로젝트의 API 인터페이스를 개발할 때 데이터가 없는 일부 필드는 기본적으로 NULL을 반환하고 숫자 유형도 NULL이 됩니다. 이때 프런트 엔드는 문자열이 균일하게 null 문자를 반환할 수 있기를 희망하며 숫자 기본적으로 0을 반환합니다. 그런 다음 json 직렬화를 사용자 지정해야 합니다.

SpringBoot의 기본 json 구문 분석 체계

우리는 springboot에 기본 json 파서가 있고 Spring Boot에서 기본적으로 사용되는 Json 파싱 기술 프레임워크가 jackson. pom.xml에서 종속성을 클릭하면 종속성을 spring-boot-starter-web볼 수 있습니다 spring-boot-starter-json.

 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
      <version>2.4.7</version>
      <scope>compile</scope>
    </dependency>

Spring Boot에는 Dependencies가 잘 캡슐화되어 있습니다.spring-boot-starter-xxx 시리즈의 많은 의존성을 볼 수 있습니다.이것은 Spring Boot의 특징 중 하나입니다.수동으로 많은 관련 의존성을 소개할 필요가 없습니다.starter- xxx 시리즈 필요한 종속성을 직접 포함하므로 위의 종속성을 다시 클릭하면 spring-boot-starter-json다음을 볼 수 있습니다.

 <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.11.4</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-jdk8</artifactId>
      <version>2.11.4</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-jsr310</artifactId>
      <version>2.11.4</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-module-parameter-names</artifactId>
      <version>2.11.4</version>
      <scope>compile</scope>
    </dependency>

컨트롤러에서 json을 반환할 때 @ResponseBody서버에서 반환한 객체를 주석을 통해 자동으로 json 문자열로 직렬화할 수 있으며, json body 매개변수를 전달할 때 객체에 주석을 달아 @RequestBody프런트 엔드에서 전달된 json 문자를 자동으로 전달할 수 있습니다. 매개변수. 자바 객체로의 문자열 역직렬화

이러한 기능은 HttpMessageConverter이 메시지 변환 도구 클래스를 통해 구현 됩니다.

SpringMVC는 HttpMessageConverter를 자동으로 구성 Jackson하고 GsonSpringBoot는 이에 대한 자동 구성을 수행합니다.

JacksonHttpMessageConverters구성

org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(ObjectMapper.class)
	@ConditionalOnBean(ObjectMapper.class)
	@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY,
			havingValue = "jackson", matchIfMissing = true)
	static class MappingJackson2HttpMessageConverterConfiguration {
    
    

		@Bean
		@ConditionalOnMissingBean(value = MappingJackson2HttpMessageConverter.class,
				ignoredType = {
    
    
						"org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter",
						"org.springframework.data.rest.webmvc.alps.AlpsJsonHttpMessageConverter" })
		MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
    
    
			return new MappingJackson2HttpMessageConverter(objectMapper);
		}

	}

잭슨 자동 구성

org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration

@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
	static class JacksonObjectMapperConfiguration {
    
    

		@Bean
		@Primary
		@ConditionalOnMissingBean
		ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
    
    
			return builder.createXmlMapper(false).build();
		}

	}

Gson의 자동 구성 클래스

org.springframework.boot.autoconfigure.http.GsonHttpMessageConvertersConfiguration

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(Gson.class)
	@Conditional(PreferGsonOrJacksonAndJsonbUnavailableCondition.class)
	static class GsonHttpMessageConverterConfiguration {
    
    

		@Bean
		@ConditionalOnMissingBean
		GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
    
    
			GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
			converter.setGson(gson);
			return converter;
		}

	}

SprinBoot의 JSON 구문 분석 사용자 지정

날짜 형식 구문 분석

기본적으로 타임스탬프 유형 형식이 반환되지만 타임스탬프는 하루 더 적고 다음과 같이 데이터베이스 연결 URL에 시간대를 추가해야 합니다.

spring.datasource.url=jdbc:p6spy:mysql://47.100.78.146:3306/mall?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&autoReconnect=true

  1. 주석을 사용한 @JsonFormat사용자 정의 서식 지정
	@JsonFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

그러나 이 주석은 각 엔티티 클래스의 날짜 필드에 이 주석을 추가할 만큼 유연하지 않습니다.

  1. 전체적으로 추가
    구성 파일에서 직접 추가spring.jackson.date-format=yyyy-MM-dd

NULL 필드는 반환되지 않습니다

  1. 인터페이스에서 null 필드를 반환할 필요가 없는 경우 @JsonInclude주석을 사용할 수 있습니다.
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String title;

그러나 이러한 종류의 주석은 각 엔티티 클래스의 필드에 이 주석을 추가할 만큼 유연하지 않습니다.

  1. 전역 추가는 구성 파일에 직접 추가됩니다.spring.jackson.default-property-inclusion=non_null

사용자 정의 필드 직렬화

사용자 지정 null 字符串유형 필드는 null 문자 NullStringJsonSerializer직렬화를 반환합니다.

public class NullStringJsonSerializer extends JsonSerializer {
    
    
    @Override
    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
    
    
        if (o == null) {
    
    
            jsonGenerator.writeString("");
        }
    }
}

사용자 지정 null 数字유형 필드는 0 기본값 NullIntegerJsonSerializer직렬화를 반환합니다.

public class NullIntegerJsonSerializer extends JsonSerializer {
    
    
    @Override
    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
    
    
        if (o == null) {
    
    
            jsonGenerator.writeNumber(0);
        }
    }
}

사용자 정의 유형 4는 5로 반올림되고 浮点小数소수점 이하 2자리로 DoubleJsonSerialize직렬화됩니다 .

public class DoubleJsonSerialize extends JsonSerializer {
    
    
    private DecimalFormat df = new DecimalFormat("##.00");

    @Override
    public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
    
    
        if (value != null) {
    
    
            jsonGenerator.writeString(NumberUtil.roundStr(value.toString(), 2));
        }else{
    
    
            jsonGenerator.writeString("0.00");
        }

    }
}

맞춤 NullArrayJsonSerializer직렬화

public class NullArrayJsonSerializer extends JsonSerializer {
    
    


    @Override
    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
    
    
        if(o==null){
    
    
            jsonGenerator.writeStartArray();
        }else {
    
    
            jsonGenerator.writeObject(o);
        }
    }
}

BeanSerializerModifierbean 직렬화를 위해 자체 직렬 변환기를 사용자 지정 사용

public class MyBeanSerializerModifier extends BeanSerializerModifier {
    
    

    private JsonSerializer _nullArrayJsonSerializer = new NullArrayJsonSerializer();

    private JsonSerializer _nullStringJsonSerializer = new NullStringJsonSerializer();

    private JsonSerializer _nullIntegerJsonSerializer = new NullIntegerJsonSerializer();

    private JsonSerializer _doubleJsonSerializer = new DoubleJsonSerialize();

    @Override
    public List changeProperties(SerializationConfig config, BeanDescription beanDesc,
                                 List beanProperties) {
    
     // 循环所有的beanPropertyWriter
        for (int i = 0; i < beanProperties.size(); i++) {
    
    
            BeanPropertyWriter writer = (BeanPropertyWriter) beanProperties.get(i);
            // 判断字段的类型,如果是array,list,set则注册nullSerializer
            if (isArrayType(writer)) {
    
     //给writer注册一个自己的nullSerializer
                writer.assignNullSerializer(this.defaultNullArrayJsonSerializer());
            }
            if (isStringType(writer)) {
    
    
                writer.assignNullSerializer(this.defaultNullStringJsonSerializer());
            }
            if (isIntegerType(writer)) {
    
    
                writer.assignNullSerializer(this.defaultNullIntegerJsonSerializer());
            }
            if (isDoubleType(writer)) {
    
    
                writer.assignSerializer(this.defaultDoubleJsonSerializer());
            }
        }
        return beanProperties;
    } // 判断是什么类型

    protected boolean isArrayType(BeanPropertyWriter writer) {
    
    
        Class clazz = writer.getPropertyType();
        return clazz.isArray() || clazz.equals(List.class) || clazz.equals(Set.class);
    }

    protected boolean isStringType(BeanPropertyWriter writer) {
    
    
        Class clazz = writer.getPropertyType();
        return clazz.equals(String.class);
    }

    protected boolean isIntegerType(BeanPropertyWriter writer) {
    
    
        Class clazz = writer.getPropertyType();
        return clazz.equals(Integer.class) || clazz.equals(int.class) || clazz.equals(Long.class);
    }

    protected boolean isDoubleType(BeanPropertyWriter writer) {
    
    
        Class clazz = writer.getPropertyType();
        return clazz.equals(Double.class) || clazz.equals(BigDecimal.class);
    }


    protected JsonSerializer defaultNullArrayJsonSerializer() {
    
    
        return _nullArrayJsonSerializer;
    }

    protected JsonSerializer defaultNullStringJsonSerializer() {
    
    
        return _nullStringJsonSerializer;
    }

    protected JsonSerializer defaultNullIntegerJsonSerializer() {
    
    
        return _nullIntegerJsonSerializer;
    }

    protected JsonSerializer defaultDoubleJsonSerializer() {
    
    
        return _doubleJsonSerializer;
    }
}

자체 Bean 직렬화를 적용하여 효과적으로 만들기 MappingJackson2HttpMessageConverter 클래스 제공
구성 클래스에 MappingJackson2HttpMessageConverter 클래스 제공, 전역 직렬화에 ObjectMapper 사용

@Configuration
public class ClassJsonConfiguration {
    
    
    @Bean
    public MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter() {
    
    
        final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();

        ObjectMapper mapper = converter.getObjectMapper();

        // 为mapper注册一个带有SerializerModifier的Factory,此modifier主要做的事情为:判断序列化类型,根据类型指定为null时的值

        mapper.setSerializerFactory(mapper.getSerializerFactory().withSerializerModifier(new MyBeanSerializerModifier()));

        return converter;
    }
}

이 클래스는 SpringBoot의 기본 json 구문 분석 체계를 대체합니다. 사실 이 클래스에서 작동하는 것이 ObjectMapper클래스이므로 이 클래스도 직접 구성할 수 있습니다.

 @Bean
    public ObjectMapper om() {
    
    
        ObjectMapper mapper = new ObjectMapper();
        // 为mapper注册一个带有SerializerModifier的Factory,此modifier主要做的事情为:判断序列化类型,根据类型指定为null时的值

        mapper.setSerializerFactory(mapper.getSerializerFactory().withSerializerModifier(new MyBeanSerializerModifier()));
        return mapper;
    }

위의 방법을 통해 직렬화를 사용자 정의하고 @JsonSerialize다음과 같은 주석을 통해 직렬화를 사용자 정의할 수도 있습니다.

@Component
public class DoubleSerialize extends JsonSerializer<Double> {
    
    
 
    private DecimalFormat df = new DecimalFormat("##.00");  
 
    @Override
    public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers)
            throws IOException, JsonProcessingException {
    
    
        if(value != null) {
    
    
            gen.writeString(df.format(value));  
        }
    }
}

그런 다음 필드를 사용하여 추가해야 합니다.

 @JsonSerialize(using = DoubleJsonSerialize.class)
    private BigDecimal price;

구성 파일 jackson 세부 구성

  spring:
    jackson:
      # 设置属性命名策略,对应jackson下PropertyNamingStrategy中的常量值,SNAKE_CASE-返回的json驼峰式转下划线,json body下划线传到后端自动转驼峰式
      property-naming-strategy: SNAKE_CASE
      # 全局设置@JsonFormat的格式pattern
      date-format: yyyy-MM-dd HH:mm:ss
      # 当地时区
      locale: zh
      # 设置全局时区
      time-zone: GMT+8
      # 常用,全局设置pojo或被@JsonInclude注解的属性的序列化方式
      default-property-inclusion: NON_NULL #不为空的属性才会序列化,具体属性可看JsonInclude.Include
      # 常规默认,枚举类SerializationFeature中的枚举属性为key,值为boolean设置jackson序列化特性,具体key请看SerializationFeature源码
      serialization:
        WRITE_DATES_AS_TIMESTAMPS: true # 返回的java.util.date转换成timestamp
        FAIL_ON_EMPTY_BEANS: true # 对象为空时是否报错,默认true
      # 枚举类DeserializationFeature中的枚举属性为key,值为boolean设置jackson反序列化特性,具体key请看DeserializationFeature源码
      deserialization:
        # 常用,json中含pojo不存在属性时是否失败报错,默认true
        FAIL_ON_UNKNOWN_PROPERTIES: false
      # 枚举类MapperFeature中的枚举属性为key,值为boolean设置jackson ObjectMapper特性
      # ObjectMapper在jackson中负责json的读写、json与pojo的互转、json tree的互转,具体特性请看MapperFeature,常规默认即可
      mapper:
        # 使用getter取代setter探测属性,如类中含getName()但不包含name属性与setName(),传输的vo json格式模板中依旧含name属性
        USE_GETTERS_AS_SETTERS: true #默认false
      # 枚举类JsonParser.Feature枚举类中的枚举属性为key,值为boolean设置jackson JsonParser特性
      # JsonParser在jackson中负责json内容的读取,具体特性请看JsonParser.Feature,一般无需设置默认即可
      parser:
        ALLOW_SINGLE_QUOTES: true # 是否允许出现单引号,默认false
      # 枚举类JsonGenerator.Feature枚举类中的枚举属性为key,值为boolean设置jackson JsonGenerator特性,一般无需设置默认即可
      # JsonGenerator在jackson中负责编写json内容,具体特性请看JsonGenerator.Feature
 

추천

출처blog.csdn.net/u011738045/article/details/119392207