從零開始改造spring項目-定製rest接口返回格式

本次改造主要解決以下問題:spring

基礎篇json

  1. 若是參數爲空或者爲empty就不返回,節省網絡流量。
  2. 配置全局統一的時間格式
  3. char[] 數組返回String問題

進階篇數組

  1. 如何設置當String爲null的時候,返回""

spring默認狀況下使用jackson做爲bean轉json處理工具,因此我就以spring的默認配置爲基礎,添加一些自定義的配置。由於定製rest接口沒啥邏輯可言,主要就是熟悉一下各個配置在那邊設置,因此先給出最終的配置文件bash

@Configuration
public class RestResponseConfig {

    @Autowired(required = false)
    private List<BeanSerializerModifier> modifierList;

    @Bean
    public HttpMessageConverters message() {
        return new HttpMessageConverters(getHttpMessageConverter());
    }

    private HttpMessageConverter getHttpMessageConverter() {
        if (modifierList != null && modifierList.size() > 0) {
            return new MappingJackson2HttpMessageConverter(wrapper());
        }
        return new MappingJackson2HttpMessageConverter(getObjectMapper());
    }

    private ObjectMapper wrapper() {
        ObjectMapper objectMapper = getObjectMapper();
        objectMapper.setSerializerFactory(getSerializerFactory(objectMapper));
        return objectMapper;
    }

    private SerializerFactory getSerializerFactory(ObjectMapper objectMapper) {
        SerializerFactory factory = objectMapper.getSerializerFactory();
        for (BeanSerializerModifier modifier : modifierList) {
            factory = factory.withSerializerModifier(modifier);
        }
        return factory;
    }

    private ObjectMapper getObjectMapper() {
        return Jackson2ObjectMapperBuilder.json()
                                          .modules(getModule())
                                          .featuresToEnable(enableFeature())
                                          .featuresToDisable(disableFeature())
                                          .serializationInclusion(JsonInclude.Include.NON_EMPTY)
                                          .timeZone(TimeZone.getTimeZone(ZoneId.of("GMT+8")))
                                          .build();
    }

    private Module getModule() {
        SimpleModule module = new SimpleModule();
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        module.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        return module;
    }

    private Object[] enableFeature() {
        return new Object[]{
                SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS
//                , JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS
        };
    }

    private Object[] disableFeature() {
        return new Object[]{SerializationFeature.WRITE_DATES_AS_TIMESTAMPS};
    }
}
複製代碼

基礎篇問題網絡

  1. 若是參數爲空或者爲empty就不返回,節省網絡流量。

在getObjectMapper方法下面serializationInclusion屬性,jackson提供了以下集中選擇經常使用的就是ALWAYS,NON_NULL,NON_EMPTYapp

ALWAYS,
NON_NULL,
NON_ABSENT,
NON_EMPTY,
NON_DEFAULT,
CUSTOM,
USE_DEFAULTS;
複製代碼

舉個例子,如今有一個pojoide

public class Pojo {
    private String name;
}
複製代碼

當他做爲返回值的時候,若是你的配置爲ALWAYS,那麼即使name爲null,你也會收到返回值。工具

{
    "name":null
}
複製代碼

可是當選擇NON_NULL的時候,若是name爲null的話,咱們就不會收到這個屬性了。post

{
    
}
複製代碼

若是name不爲null,而是"",這樣的話接口仍是會收到返回ui

{
    "name":""
}
複製代碼

若是選擇NON_EMPTY,那麼只有當那麼不爲null,且不爲"",接口才會收到返回值。

  1. 配置全局統一的時間格式

在默認配置下 LocalDateTime 類的格式是這樣的

"time":"2019-10-21T12:29:34"
複製代碼

其實這個到不是說必定要改,而是各類需求的變化層出不窮,我遇到過有的地方專門以 yyyyMMddHHmmss 這種格式來傳遞時間的。因此咱們仍是須要掌握一下自定義的方法。

private Module getModule() {
        SimpleModule module = new SimpleModule();
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        module.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        return module;
    }
複製代碼

方法就在getModule這兒。SimpleModule這個類,咱們這樣配置的意思就是若是遇到LocalDateTime類,就以 LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))來處理該類的序列化,反序列化也同樣。因此在這邊指定日期的格式就能夠了。

  1. char[] 數組返回String問題

在默認狀況下 char[] 數組序列化的時候會變爲字符串

private char[] chars;
//輸入
"chars":["a","b"]
//輸出
"chars": "ab"
複製代碼

該配置在enableFeature方法中

SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS
複製代碼

只要設置了WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS這個屬性,char[] 數組,即可以以數組的形式序列化了。

基礎篇到這兒就結束了,已經差很少夠解決通常性的需求。

進階篇問題

  1. 如何設置當String爲null的時候,返回""

不要問我爲何要這樣返回,由於我遇到的下游廠家是這麼要求的。。。

要完成這個需求,首先得自定義一個序列化組件

@Component
public class NullStringSerializer extends StdSerializer<Object> {

    public NullStringSerializer() {
        super(Object.class);
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeString("");
    }
}
複製代碼

其次將該序列化組件設置爲String類的null序列化組件

public class CustomNullSerializerModifier extends BeanSerializerModifier {

    @Autowired
    private NullStringSerializer nullStringSerializer;

    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
        for (BeanPropertyWriter writer : beanProperties) {
            Class<?> rawClass = writer.getType().getRawClass();
            if(rawClass.isAssignableFrom(String.class)){
                writer.assignNullSerializer(nullStringSerializer);
            }
        }
        return beanProperties;
    }
}
複製代碼

這樣咱們上面的配置文件就能夠讀取到這個配置了。當String爲null的時候,接口就會返回""了。


返回目錄

相關文章
相關標籤/搜索