Полностью решить проблемы преобразования времени и сериализации в Spring mvc

Spring Boot

Болевые точки

При разработке с помощью Spring mvc мы часто сталкиваемся со строками времени в определенном формате из внешнего интерфейса, которые нельзя использовать с новыми функциями java8.java.timeПараметры определенного типа в пакете получаются напрямую. Мы используем содержащиеjava.timeТип упаковки Прием параметра также сообщит о проблеме с десериализацией, а также будут некоторые проблемы с форматированием в интерфейсе возврата с типом времени. Сегодня мы подошли к их полному решению.

предложение

На самом деле, наиболее научное предложение состоит в том, чтобы использовать временные метки для единообразного представления времени. Это наиболее совершенный вариант, позволяющий избежать проблем совместимости интерфейсных браузеров, а также избежать проблем с сериализацией/десериализацией некоторых других промежуточных программ. Но это может быть более ясно и семантически выражено во времени. У этих двух методов есть свои достоинства, и если мы настаиваем на использовании библиотеки классов времени java8, выхода нет. Ниже мыjava.time.LocalDateTimeРешайте эти проблемы одну за другой.

локальная аннотация

В Интернете есть много статей, в которых говорится, что аннотация направлена ​​из внешнего интерфейса в задний, то есть внешний интерфейс передает формат параметра времени на задний конец, что не является неправильным! Но есть небольшая проблема, этот метод можно использовать только в тех случаях, когда не задействована десериализация. То есть применяются следующие сценарии:

    @GetMapping("/local")
    public Map<String, String> data(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime localDateTime) {
        Map<String, String> map = new HashMap<>(1);
        map.put("data", localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        return map;
    }

Это не сработает, если вы используете его в следующем сценарии:


@Data
public class UserInfo {

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime birthday;
    private String name;
    private Integer age;
}


   @PostMapping("/user")
    public Object postData(@RequestBody UserInfo userInfo) {
        System.out.println("userInfo = " + userInfo);
        return userInfo;
    }

Причина в том, что параметры запроса Post находятся в теле и должны быть десериализованы в объекты. По умолчанию используется библиотека классов jackson для десериализации и не вызывает@DateTimeFormatМеханизм аннотации. Затем нам нужно использовать аннотации форматирования Джексона.@JsonFormat. мы будем классом сущностиUserInfoИзмените его на следующее:

@Data
public class UserInfo {

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime birthday;
    private String name;
    private Integer age;
}

Вышеупомянутые две аннотации могут сосуществовать, но должны быть четко указаны их соответствующие сценарии использования. Вот еще одна маленькая деталь: формат должен соответствовать типу времени. Напримерyyyy-MM-ddвести перепискуjava.time.LocalDate. Если вы можете персонализировать его немного больше@JsonFormatвозможно@JsonDeserializeа также@JsonSerializeзаменять. но ихusingПараметр должен быть реализован вами как соответствующий тип времени. если@JsonFormat,@JsonDeserializeа также@JsonSerializeодновременно существуют@JsonFormatприоритет выше.

Преимущества местного лечения

Преимущество местного лечения заключается в восьми словах: сто цветов расцветают, сто школ спорят. Разнообразие и персонализация могут быть сохранены. Но часть приносит новую проблему: нет единого стандарта и несовместимости. Это делает обслуживание неудобным. Поэтому иногда мы можем управлять им глобально в зависимости от потребностей бизнеса. Ниже мы объясним, как выполнить глобальную настройку.

Конфигурация глобального формата времени

Глобализация фактически основана на@DateTimeFormatа также@JsonFormatЕсть два сценария для настройки. за@DateTimeFormatВ сценарии мы реализуем интерфейс, предоставляемый Spring:

DateTimeFormatter :

     // 时间格式化
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.CHINA);

Интерфейс преобразования типов:

 org.springframework.core.convert.converter.Converter<S,T>

выполнить:

    @Bean
    public Converter<String, LocalDateTime> localDateConverter() {
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String source) {
                return LocalDateTime.parse(source, FORMATTER);
            }
        };
    }

Или отформатируйте интерфейс:

 org.springframework.format.Formatter<T>

выполнить :

    @Bean
    public Formatter<LocalDateTime> localDateFormatter() {
        return new Formatter<LocalDateTime>() {
            @Override
            public LocalDateTime parse(String text, Locale locale) throws ParseException {
                return LocalDateTime.parse(text, FORMATTER);
            }

            @Override
            public String print(LocalDateTime object, Locale locale) {
                return object.format(FORMATTER);
            }
        };
    }

Реализация вышеуказанных двух интерфейсов должна быть зарегистрирована как Spring Bean, и вы можете выбрать один из двух при настройке, где S — это источник, который на самом деле является временной строкой внешнего интерфейса. T - это Target, который является целью, которая представляет тип времени java, который вам нужно преобразовать или отформатировать.

Затем для сериализации и десериализации времени мы можем настроить следующим образом (на основе джексона по умолчанию, в качестве примера возьмем LocalDateTime):

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {

        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder
                 // 反序列化
                .deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(FORMATTER))
                 // 序列化
                .serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(FORMATTER));
    }

Точно так же пользовательский компоновщик jsonMapper должен быть зарегистрирован как Spring Bean.

Основы глобальной конфигурации

Некоторые преимущества и недостатки глобальной конфигурации были объяснены выше, здесь я все же хочу рассказать об основных моментах, чтобы вы не наступили на яму. Глобальная конфигурация аналогична локальной конфигурации. Такой же образец должен быть согласован. Это требует от нас быть глобально последовательными. Мы можем реализовать более одной глобальной конфигурации дляLocalDate,OffsetDateTimeприспособление. В то же время, если мы обращаемся к другому промежуточному ПО, которому необходимо использовать сериализацию/десериализацию, например, к Redis и RabbitMQ, мы также должны обратить внимание на адаптацию.

##Суммировать Благодаря приведенному выше введению в локальные и глобальные методы обработки формата времени я считаю, что проблема времени Spring mvc, которая вас беспокоит, больше не будет существовать. Если вы считаете, что написали это правильно, пожалуйста, перешлите это другим учащимся, поставьте лайк и подпишитесь на них.

关注公众号:码农小胖哥,获取更多资讯