Heim > Java > javaLernprogramm > Umgang mit Spring Boot-Datum und -Uhrzeit

Umgang mit Spring Boot-Datum und -Uhrzeit

PHPz
Freigeben: 2023-05-18 14:22:06
nach vorne
1006 Leute haben es durchsucht

GET-Anfrage und POST-Formular-Datums- und Uhrzeit-String-Formatkonvertierung

Diese Situation sollte anders behandelt werden, als wenn die Zeit als Json-String verwendet wird, da die unterste Ebene des Front-End-JSON zum Back-End-Pojo die Json-Serialisierung Jackson verwendet Tool (HttpMessgeConverter); wenn die Zeitzeichenfolge als normaler Anforderungsparameter übergeben wird, wird <code>Converter für die Konvertierung verwendet, und es gibt Unterschiede in den Verarbeitungsmethoden zwischen den beiden. 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"));
            }
        };
    }
}
Nach dem Login kopieren

点评:以上两个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));
    }
Nach dem Login kopieren

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

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());
Nach dem Login kopieren

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);
    }
}
Nach dem Login kopieren

添加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);
}
Nach dem Login kopieren

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

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

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

@Bean
@ConditionalOnBean(name = "requestMappingHandlerAdapter")
public Converter<String, LocalDateTime> localDateTimeConverter() {
  return source -> LocalDateTime.parse(source, DateTimeUtils.DEFAULT_FORMATTER);
}
Nach dem Login kopieren

还可以对前端传递的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());
    }
}
Nach dem Login kopieren

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

<!--hu tool 工具类-->
<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>5.1.3</version>
</dependency>
Nach dem Login kopieren

使用Spring注解

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

@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;
Nach dem Login kopieren

如果使用了自定义参数转化器,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")));
            }
        });
    }
}
Nach dem Login kopieren

从名字就可以看出来,这是在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

Verwenden Sie einen benutzerdefinierten Parameterkonverter (Converter)

, um org.springframework.core.convert.converter.Converter, einen benutzerdefinierten Parameterkonverter, wie folgt zu implementieren: 🎜
@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;
    }
}
Nach dem Login kopieren
🎜Kommentare: Die beiden oben genannten Beans Es wird in den Parameterparser von Spring MVC eingefügt (es scheint ParameterConversionService zu heißen). Wenn die eingehende Zeichenfolge in die LocalDateTime-Klasse konvertiert werden soll, ruft Spring den Konverter auf, um den Eingabeparameter zu konvertieren . 🎜🎜Hinweis: Beim benutzerdefinierten Parameterkonverter Converter gibt es eine Gefahr, wenn die obige anonyme innere Klasse in einen Lambda-Ausdruck vereinfacht wird: 🎜rrreee🎜Eine Ausnahme tritt auf, wenn das Projekt erneut gestartet wird: 🎜
🎜Verursacht durch : java.lang.IllegalArgumentException: Quelltyp konnte für Ihren Konverter nicht ermittelt werden [com.example.demo126.config.MappingConverterAdapter$$Lambda$522/817994751]; ?🎜
🎜 liegt daran: 🎜🎜Wenn das Webprojekt mit der Registrierung von requestMappingHandlerAdapter beginnt, werden WebBindingInitializer🎜rrreee🎜und ConfigurableWebBindingInitializer initialisiert >Erfordert FormattingConversionService und FormattingConversionService. Beim Hinzufügen müssen Sie allgemeine Informationen abrufen: 🎜rrreee🎜Konverter hinzufügen Erhält die spezifischen Typen von zwei Generika über die Schnittstelle li>🎜Der einfachste Weg besteht darin, keine Lambda-Ausdrücke und anonyme innere Klassen zu verwenden, damit die oben genannten Probleme nicht auftreten🎜
  • 🎜Warten Sie einfach, bis die requestMappingHandlerAdapterbean-Registrierung abgeschlossen ist Wenn Sie später Ihren eigenen Konverter hinzufügen, wird dieser nicht in FormattingConversionService registriert🎜
  • rrreee🎜Sie können auch einen regulären Abgleich für die vom Frontend übergebene Zeichenfolge durchführen, z jjjj-MM-tt HH: mm:ss, jjjj-MM-tt, HH:mm:ss usw. für den Abgleich. um sich an verschiedene Szenarien anzupassen. 🎜rrreee🎜Hinweis: Hutool wird direkt beim Anpassen des Datumsformats verwendet. Es handelt sich um die Parsing-Tool-Klasse, die wir hier nicht neu erfinden. Die folgende Methode verwendet diese Tool-Klasse In Ihrem eigenen Projekt ist die Verwendung dieser Tool-Klasse ebenfalls sehr einfach. Fügen Sie einfach die Hutool-Abhängigkeit wie folgt in die Projekt-POM-Datei ein: 🎜rrreee🎜Verwenden Sie Spring-Anmerkungen🎜🎜Verwenden Sie Spring-eigene Anmerkungen @DateTimeFormat(pattern = "yyyy-". MM- dd"), wie folgt: 🎜rrreee🎜Wenn ein benutzerdefinierter Parameterkonverter verwendet wird, verwendet Spring diese Methode vorzugsweise zur Verarbeitung, d. h. Spring-Anmerkungen werden nicht wirksam. 🎜🎜Verwenden Sie ControllerAdvice mit initBinder🎜rrreee🎜Wie Sie dem Namen entnehmen können, erfolgt dies im Controller (es ist auch eine globale Ausnahmeerfassung möglich), und die Parameter werden vor der Eingabe in den Handler konvertiert. 🎜🎜JSON-Eingabeparameter und Rückgabewerte werden global verarbeitet🎜🎜Der Anforderungstyp ist: post,content-type=application/json und wird im Hintergrund mit @RequestBody, der standardmäßig empfangen und zurückgegeben wird. Das Wertformat ist: <code>jjjj-MM-tt HH:mm:ss🎜🎜Ändern Sie die Datei „application.yml“🎜🎜Fügen Sie der Anwendung den folgenden Inhalt hinzu .properties file:🎜
    🎜spring:
    jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8🎜
    🎜supports(content-type=application/json)Die Zeichenfolge im Format yyyy-MM-dd HH:mm:ss wird im Hintergrund mit @RequestBody, und das Rückgabewertdatum wird in yyyy-MM-dd HH:mm:ssFormatzeichenfolge 🎜🎜Nicht unterstützt (content-type=application/ json) Die Anforderung von yyyy-MM-dd und anderen Arten von Zeichenfolgen wird in <code>date; java8 date api wird nicht unterstützt; 🎜🎜Verwenden Sie Jacksons JSON-Serialisierungs- und Deserialisierungschemie🎜rrreee

    Das obige ist der detaillierte Inhalt vonUmgang mit Spring Boot-Datum und -Uhrzeit. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Verwandte Etiketten:
    Quelle:yisu.com
    Erklärung dieser Website
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
    Beliebte Tutorials
    Mehr>
    Neueste Downloads
    Mehr>
    Web-Effekte
    Quellcode der Website
    Website-Materialien
    Frontend-Vorlage