Maison > Java > javaDidacticiel > le corps du texte

Comment gérer la date et l'heure de Spring Boot

PHPz
Libérer: 2023-05-18 14:22:06
avant
968 Les gens l'ont consulté

Requête GET et conversion du format de chaîne de date et d'heure du formulaire POST

Cette situation doit être traitée différemment lorsque l'heure est utilisée comme chaîne Json, car la couche inférieure du json frontal doit le pojo back-end utilise un outil Jackson de séquence Json (HttpMessageConverter) ; lorsque la chaîne d'heure est transmise en tant que paramètre de requête normal, Converter est utilisé pour la conversion, et il y a différences dans les méthodes de traitement entre les deux. HttpMessgeConverter);而时间字符串作为普通请求参数传入时,转换用的是Converter,两者在处理方式上是有区别。

使用自定义参数转换器(Converter)

实现 org.springframework.core.convert.converter.Converter,自定义参数转换器,如下:

@Configuration
public class DateConverterConfig {
    @Bean
    public Converter<String, LocalDate> localDateConverter() {
       return new Converter<String, LocalDate>() {
            @Override
            public LocalDate convert(String source) {
                return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            }
        };
    }
    @Bean
    public Converter<String, LocalDateTime> localDateTimeConverter() {
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String source) {
                return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
        };
    }
}
Copier après la connexion

点评:以上两个bean会注入到spring mvc的参数解析器(好像叫做ParameterConversionService),当传入的字符串要转为LocalDateTime类时,spring会调用该Converter对这个入参进行转换。

注意:关于自定义的参数转换器 Converter,这有个坑,若将上面匿名内部类的写法精简成lambda表达式的方式:

   @Bean
    @ConditionalOnBean(name = "requestMappingHandlerAdapter")
    public Converter<String, LocalDate> localDateConverter() {
        return source -> LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
    }
Copier après la connexion

当再次启动项目时会出现异常:

Caused by: java.lang.IllegalArgumentException: Unable to determine source type and target type for your Converter [com.example.demo126.config.MappingConverterAdapter$$Lambda2/817994751]; does the class parameterize those types?

是由于:

web项目启动注册requestMappingHandlerAdapter的时候会初始化WebBindingInitializer

adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
Copier après la connexion

ConfigurableWebBindingInitializer需要FormattingConversionService,FormattingConversionService会将所有的Converter添加进来,添加的时候需要获取泛型信息:

@Override
public void addFormatters(FormatterRegistry registry) {
    for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
       registry.addConverter(converter);
    }
    for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
       registry.addConverter(converter);
    }
    for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
       registry.addFormatter(formatter);
    }
}
Copier après la connexion

添加Converter.class 一般是通过接口获取两个泛型的具体类型

public ResolvableType as(Class<?> type) {
    if (this == NONE) {
      return NONE;
    }
    Class<?> resolved = resolve();
    if (resolved == null || resolved == type) {
      return this;
    }
    for (ResolvableType interfaceType : getInterfaces()) {
      ResolvableType interfaceAsType = interfaceType.as(type);
      if (interfaceAsType != NONE) {
        return interfaceAsType;
      }
    }
    return getSuperType().as(type);
}
Copier après la connexion

Lambda表达式的接口是Converter,并不能得到具体的类型,既然如此,那解决办法:

  • 最简单的方法就是不适用Lambda表达式,还使用匿名内部类,这样就不会存在上述问题

  • 就是等requestMappingHandlerAdapterbean注册完成之后再添加自己的converter就不会注册到FormattingConversionService

@Bean
@ConditionalOnBean(name = "requestMappingHandlerAdapter")
public Converter<String, LocalDateTime> localDateTimeConverter() {
  return source -> LocalDateTime.parse(source, DateTimeUtils.DEFAULT_FORMATTER);
}
Copier après la connexion

还可以对前端传递的string进行正则匹配,如yyyy-MM-dd HH:mm:ss、yyyy-MM-dd、 HH:mm:ss等,进行匹配。以适应多种场景。

@Component
public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String value) {
        /**
         * 可对value进行正则匹配,支持日期、时间等多种类型转换
         * 这里在匹配Date日期格式时直接使用了 hutool 为我们已经写好的解析工具类,这里就不重复造轮子了
         * cn.hutool.core.date.DateUtil
         * @param value
         * @return
         */
        return DateUtil.parse(value.trim());
    }
}
Copier après la connexion

注:这里在匹配Date日期格式时直接使用了 hutool 为我们已经写好的解析工具类,这里就不重复造轮子了,下面的方法同样使用了该工具类,想要在自己的项目中使用该工具类也很简单,在项目pom文件中引入hutool的依赖就可以了,如下:

<!--hu tool 工具类-->
<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>5.1.3</version>
</dependency>
Copier après la connexion

使用Spring注解

使用spring自带注解@DateTimeFormat(pattern = "yyyy-MM-dd"),如下:

@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;
Copier après la connexion

如果使用了自定义参数转化器,Spring会优先使用该方式进行处理,即Spring注解不生效。

使用ControllerAdvice配合initBinder

@ControllerAdvice
public class GlobalExceptionHandler {
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) throws IllegalArgumentException {
                setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            }
        });
        binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) throws IllegalArgumentException {
                setValue(LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            }
        });
        binder.registerCustomEditor(LocalTime.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) throws IllegalArgumentException {
                setValue(LocalTime.parse(text, DateTimeFormatter.ofPattern("HH:mm:ss")));
            }
        });
    }
}
Copier après la connexion

从名字就可以看出来,这是在controller做环切(这里面还可以全局异常捕获),在参数进入handler之前进行转换;转换为我们相应的对象。

JSON入参及返回值全局处理

请求类型为:post,content-type=application/json, 后台用@RequestBody接收,默认接收及返回值格式为: yyyy-MM-dd HH:mm:ss

修改 application.yml 文件

在application.propertities文件中增加如下内容:

spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8

支持(content-type=application/json)请求中格式为 yyyy-MM-dd HH:mm:ss的字符串,后台用@RequestBody接收,及返回值date转为yyyy-MM-dd HH:mm:ss格式string;

不支持(content-type=application/json)请求中yyyy-MM-dd等类型的字符串转为date; 不支持java8日期api

Utiliser un convertisseur de paramètres personnalisés (Converter)

Implémentez org.springframework.core.convert.converter.Converter, un convertisseur de paramètres personnalisés, comme suit : #🎜🎜#
@Configuration
public class JacksonConfig {
    /** 默认日期时间格式 */
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    /** 默认日期格式 */
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    /** 默认时间格式 */
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        // 忽略json字符串中不识别的属性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 忽略无法转换的对象
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // PrettyPrinter 格式化输出
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        // NULL不参与序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 指定时区
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
        // 日期类型字符串处理
        objectMapper.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT));
        // java8日期日期处理
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        objectMapper.registerModule(javaTimeModule);
        converter.setObjectMapper(objectMapper);
        return converter;
    }
}
Copier après la connexion
#🎜🎜# Commentaire : Les deux beans ci-dessus seront injectés dans l'analyseur de paramètres de spring mvc (il semble s'appeler ParameterConversionService), lorsque la chaîne entrante est convertie en classe LocalDateTime , Spring appellera le Converter pour convertir ce paramètre d'entrée. #🎜🎜##🎜🎜#Remarque : concernant le convertisseur de paramètres personnalisé Converter, il existe un piège si la classe interne anonyme ci-dessus est simplifiée en une expression lambda : #🎜🎜#rrreee#🎜🎜#Quand Une exception se produira lorsque. redémarrer le projet : #🎜🎜#
#🎜🎜#Causé par : java.lang.IllegalArgumentException : Impossible de déterminer le type de source et le type de cible .config.MappingConverterAdapter$$Lambda$522/817994751] ; la classe paramètre-t-elle ces types ?#🎜🎜#
#🎜🎜# est due à : #🎜🎜##🎜🎜#enregistrement de démarrage du projet Web requestMappingHandlerAdapter initialisera WebBindingInitializer#🎜🎜#rrreee#🎜🎜# et ConfigurableWebBindingInitializer nécessite FormattingConversionService, et FormattingConversionService code> ajoutera tous les <code>Converter Lors de l'ajout, vous devez obtenir les informations génériques : #🎜🎜#rrreee#🎜🎜#Add Converter.class, en obtenez généralement deux via l'interface Le type spécifique de générique. #🎜🎜#rrreee#🎜🎜#L'interface de l'expression Lambda est Converter, et le type spécifique ne peut pas être obtenu dans ce cas, la solution : #🎜🎜#
    #🎜🎜#Le moyen le plus simple est de ne pas utiliser d'expressions Lambda et d'utiliser des classes internes anonymes, afin que les problèmes ci-dessus n'existent pas#🎜🎜#
  • #🎜🎜#Attendez simplement requestMappingHandlerAdapterbeanUne fois l'enregistrement terminé, si vous ajoutez votre propre convertisseur, il ne sera pas enregistré dans <code>FormattingConversionService#🎜🎜#
rrreee#🎜🎜#De plus, vous can La chaîne transmise par le frontal est régulièrement mise en correspondance, par exemple aaaa-MM-jj HH:mm:ss, aaaa-MM-jj, HH:mm:ss, etc., pour la correspondance. pour s'adapter à différents scénarios. #🎜🎜#rrreee#🎜🎜#Remarque : Ici, hutool est utilisé directement lors de la correspondance du format de date Date. C'est la classe d'outil d'analyse que nous avons déjà écrite. Nous ne réinventerons pas la roue ici. Il est également très simple d'utiliser cette classe d'outils dans votre propre projet. Introduisez simplement la dépendance hutool dans le fichier pom du projet, comme suit : #🎜🎜#rrreee#🎜🎜#Utiliser les annotations Spring#🎜🎜##🎜🎜. # Utilisez la propre annotation de Spring @DateTimeFormat(pattern = "yyyy-MM-dd"), comme suit : #🎜🎜#rrreee#🎜🎜#Si un convertisseur de paramètres personnalisé est utilisé, Spring l'utilisera Cette méthode est d'abord utilisée, c'est-à-dire que les annotations Spring ne prennent pas effet. #🎜🎜##🎜🎜#Utiliser ControllerAdvice avec initBinder#🎜🎜#rrreee#🎜🎜#Comme vous pouvez le voir d'après le nom, il s'agit d'une boucle coupée dans le contrôleur (la capture d'exception globale peut également être utilisée ici), avant le les paramètres entrent dans le gestionnaire Convert ; convertissent en notre objet correspondant. #🎜🎜##🎜🎜#Traitement global des paramètres d'entrée JSON et des valeurs de retour#🎜🎜##🎜🎜#Le type de requête est : post,content-type=application/json, utilisez en arrière-plan que reçoit @RequestBody, le format par défaut des valeurs de réception et de retour est : aaaa-MM-jj HH:mm:ss#🎜🎜##🎜🎜#Modifier l'application. fichier yml#🎜🎜# #🎜🎜#Ajoutez le contenu suivant au fichier application.properties : #🎜🎜#
#🎜🎜#spring :
jackson :
format de date : aaaa- MM-jj HH:mm : ss
fuseau horaire : GMT+8#🎜🎜#
#🎜🎜#Support (content-type=application/json) Le format dans la requête est aaaa-MM-jj La chaîne de HH:mm:ss est reçue en arrière-plan à l'aide de @RequestBody, et la date de la valeur de retour est convertie en aaaa-MM-jj HH:mm:ss code>Format de chaîne ; #🎜🎜##🎜🎜# ne prend pas en charge (<code>content-type=application/json) les types de chaîne tels que aaaa-MM-jj dans la requête Convertir en date ; ne prend pas en charge la date java8 api ;#🎜🎜# #🎜🎜#Utilisation de la sérialisation et de la désérialisation JSON de Jackson# 🎜🎜 #rrreee

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal