最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot整合LocalDateTime的過程

 更新時(shí)間:2024年08月21日 09:57:33   作者:獨(dú)辟蹊徑的魚  
LocalDateTime 和 Date 是 Java 中處理日期和時(shí)間的兩種不同的類,在 JDK8 中引入了 java.time 包,這篇文章主要介紹了SpringBoot整合LocalDateTime的過程,需要的朋友可以參考下

一、為什么使用LocalDateTime

        LocalDateTime 和 Date 是 Java 中處理日期和時(shí)間的兩種不同的類,在 JDK8 中引入了 java.time 包。LocalDateTime 相比 Date 有一些優(yōu)勢(shì),主要體現(xiàn)在以下幾個(gè)方面:

  • 不可變性:
    • LocalDateTime 是不可變的類,一旦創(chuàng)建就不能被修改。任何對(duì) LocalDateTime 的操作都會(huì)返回一個(gè)新的對(duì)象,而不會(huì)修改原始對(duì)象。這有助于避免在多線程環(huán)境中的并發(fā)問題。
  • 線程安全性:
    • 由于 LocalDateTime 是不可變的,因此它天然具有線程安全性,可以在多線程環(huán)境中安全使用。
  • 可讀性和易用性:
    • LocalDateTime 提供了更加清晰和直觀的API,使得處理日期和時(shí)間更加易讀、易用。例如,通過使用方法鏈?zhǔn)秸{(diào)用,可以輕松地執(zhí)行各種操作,而不需要復(fù)雜的日期格式化和解析。
  • 更好的API設(shè)計(jì):
    • LocalDateTime 提供了更豐富、靈活和易用的API,允許進(jìn)行各種日期和時(shí)間的操作,例如增減天數(shù)、小時(shí)、分鐘等。而 Date 的 API相對(duì)較為古老和不夠直觀。
  • 時(shí)區(qū)處理:
    • LocalDateTime 能夠更好地處理時(shí)區(qū)信息,通過 ZonedDateTime 類可以輕松轉(zhuǎn)換到不同的時(shí)區(qū)。而 Date 類在處理時(shí)區(qū)時(shí)較為復(fù)雜,通常需要使用 Calendar 類。

總的來說,LocalDateTime 提供了更現(xiàn)代、清晰和強(qiáng)大的日期和時(shí)間處理功能,使得開發(fā)者更容易編寫可讀性高且可維護(hù)性強(qiáng)的代碼。在新的代碼中,特別是在使用 JDK 8 及更新版本的項(xiàng)目中,推薦使用 LocalDateTime 替代 Date。

二、使用LocalDateTime遇到的問題

        眾所周知,SpringBoot會(huì)自動(dòng)對(duì)前端的傳值進(jìn)行解析,將 HttpServletRequest 中的請(qǐng)求內(nèi)容,轉(zhuǎn)換成后端 Controoler 控制器中的實(shí)體類參數(shù),但在實(shí)際使用 LocalDateTime 作為參數(shù)時(shí),當(dāng)前端傳入日期格式為 yyyy-MM-dd HH:mm:ss 時(shí),我們會(huì)發(fā)現(xiàn) SpringBoot 好像不能正常工作了,下面是兩個(gè)問題例子。

GET請(qǐng)求使用 LocalDateTime 作為參數(shù)

下面是使用 @RequestParam 和 @PathVariable 兩種最常見的用法示例

@RestController
public class LocalDateTimeController {
    @GetMapping("/resolveRequestParamDateTime")
    public void resolveRequestParamDateTime(@RequestParam LocalDateTime dateTime) {
        System.out.println("ok");
    }
?
    @GetMapping("/resolvePathVariableDateTime/{dateTime}")
    public void resolvePathVariableDateTime(@PathVariable LocalDateTime dateTime) {
        System.out.println("ok");
    }
}

點(diǎn)擊運(yùn)行,無論是第一個(gè)還是第二個(gè)方法,都會(huì)出現(xiàn)如下異常

org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDateTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.PathVariable java.time.LocalDateTime] for value '2023-01-01 12:12:12'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2023-01-01 12:12:12]
  at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:133)
  at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
?
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.PathVariable java.time.LocalDateTime] for value '2023-01-01 12:12:12'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2023-01-01 12:12:12]
  at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
  at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:191)
?
Caused by: java.lang.IllegalArgumentException: Parse attempt failed for value [2023-01-01 12:12:12]
  at org.springframework.format.support.FormattingConversionService$ParserConverter.convert(FormattingConversionService.java:223)
?
Caused by: java.time.format.DateTimeParseException: Text '2023-01-01 12:12:12' could not be parsed at index 2
  at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)

POST請(qǐng)求體中使用 LocalDateTime 作為參數(shù) 下面是使用 @RequestBody 的示例

@RestController
public class LocalDateTimeController {
?
    @PostMapping("/resolveBodyDateTime")
    public void resolveBodyDateTime(@RequestBody ResolveBody body) {
        System.out.println("ok");
    }
?
    @Data
    private static class ResolveBody {
        private LocalDateTime dateTime;
    }
}

點(diǎn)擊運(yùn)行,會(huì)出現(xiàn)如下異常

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Expected array or string.; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Expected array or string.
 at [Source: (PushbackInputStream); line: 1, column: 1]
  at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:245)
  at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:227)
  at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:205)
  at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:158)
  at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:131)
  at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
?
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Expected array or string.
 at [Source: (PushbackInputStream); line: 1, column: 1]
  at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
  at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1442)

簡(jiǎn)單分析

        觀察堆棧錯(cuò)誤信息,在使用 GET 請(qǐng)求時(shí)拋出的異常的 MethodArgumentTypeMismatchException ,而使用 POST請(qǐng)求時(shí)拋出的異常是 HttpMessageNotReadableException 。 二者最外層拋出的異常不一樣,但是我們繼續(xù)往下看最內(nèi)層拋出的異常, GET 請(qǐng)求的報(bào)錯(cuò)很明顯就是 String 類型不能被轉(zhuǎn)換為 LocalDateTime 類型拋出的異常,POST請(qǐng)求拋出的是 jackson 反序列化類型不匹配的異常。 通過分析可得,上述 GET 和 POST 請(qǐng)求的報(bào)錯(cuò),都是由于 SpringBoot 未能正常將參數(shù)中 String 類型轉(zhuǎn)換為 LocalDateTime 類型拋出的。

三、異常源碼分析

        通過堆棧信息可以看出,我們的請(qǐng)求鏈路在進(jìn)行參數(shù)解析,也就是走到spring mvc 的HandlerMethodArgumentResolverComposite.resolveArgument()這個(gè)方法時(shí)發(fā)生的異常,從這個(gè)方法入手debug打斷點(diǎn)依次往下執(zhí)行,一直走到最內(nèi)層的堆棧位置,也就是實(shí)際進(jìn)行參數(shù)解析的核心代碼,下面列出實(shí)際參數(shù)解析代碼。

GET請(qǐng)求

        第13行就是實(shí)際的轉(zhuǎn)換代碼,走到這里時(shí)spring拿到的converter是通過WebMvcAutoConfiguration類自動(dòng)裝配注入的FormattingConversionService對(duì)象 ,但是這個(gè)converter默認(rèn)情況下并不能將String轉(zhuǎn)換為L(zhǎng)ocalDateTime

GenericConversionService.java類源碼:
@Nullable
public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
    Assert.notNull(targetType, "Target type to convert to cannot be null");
    if (sourceType == null) {
        Assert.isTrue(source == null, "Source must be [null] if source type == [null]");
        return this.handleResult((TypeDescriptor)null, targetType, this.convertNullSource((TypeDescriptor)null, targetType));
    } else if (source != null && !sourceType.getObjectType().isInstance(source)) {
        throw new IllegalArgumentException("Source to convert from must be an instance of [" + sourceType + "]; instead it was a [" + source.getClass().getName() + "]");
    } else {
        GenericConverter converter = this.getConverter(sourceType, targetType);
        if (converter != null) {
            # 這里去做類型轉(zhuǎn)換
            Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
            return this.handleResult(sourceType, targetType, result);
        } else {
            return this.handleConverterNotFound(source, sourceType, targetType);
        }
    }
}

POST請(qǐng)求 在第11~12行就是實(shí)際的轉(zhuǎn)換代碼,走到這里時(shí)spring拿到的converter是 MappingJackson2HttpMessageConverter ,但是這個(gè)converter并不能將String轉(zhuǎn)換為L(zhǎng)ocalDateTime

AbstractMessageConverterMethodArgumentResolver類源碼:
for (HttpMessageConverter<?> converter : this.messageConverters) {
    Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
    GenericHttpMessageConverter<?> genericConverter =
    (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
    if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
        (targetClass != null && converter.canRead(targetClass, contentType))) {
        if (message.hasBody()) {
            HttpInputMessage msgToUse =
            getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
            # 這里去做類型轉(zhuǎn)換
            body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
                    ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
            body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
        }
        else {
            body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
        }
        break;
    }
}

        MappingJackson2HttpMessageConverter的read解析方法繼續(xù)往后走,調(diào)用的是父類AbstractJackson2HttpMessageConverter的read方法,實(shí)際的解析方法就是第18行的ObjectMapper類的readValue方法

AbstractJackson2HttpMessageConverter類源碼:
@Override
  public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
      throws IOException, HttpMessageNotReadableException {
?
    JavaType javaType = getJavaType(type, contextClass);
    return readJavaType(javaType, inputMessage);
  }
?
  private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
    try {
      if (inputMessage instanceof MappingJacksonInputMessage) {
        Class<?> deserializationView = ((MappingJacksonInputMessage) inputMessage).getDeserializationView();
        if (deserializationView != null) {
          return this.objectMapper.readerWithView(deserializationView).forType(javaType).
              readValue(inputMessage.getBody());
        }
      }
            # jackson實(shí)際解析
      return this.objectMapper.readValue(inputMessage.getBody(), javaType);
    }
    catch (InvalidDefinitionException ex) {
      throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
    }
    catch (JsonProcessingException ex) {
      throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex, inputMessage);
    }
  }

問題分析

        SpringBoot GET請(qǐng)求參數(shù)類型轉(zhuǎn)換使用的是GenericConversionService類里注冊(cè)的一個(gè)個(gè)GenericConverter;String轉(zhuǎn)LocalDateTime類型默認(rèn)情況下的StringToLocalDateTimeConverter不能正常解析。                

  •         SpringBoot POST請(qǐng)求參數(shù)類型轉(zhuǎn)換使用的是AbstractMessageConverterMethodArgumentResolver類里L(fēng)ist<HttpMessageConverter<?>> messageConverters里注冊(cè)的一個(gè)個(gè)HttpMessageConverter;
  • String轉(zhuǎn)LocalDateTime類型默認(rèn)情況下的MappingJackson2HttpMessageConverter不能正常解析,也就是默認(rèn)的ObjectMapper不能正常解析。

四、解決思路

        通過上述問題分析,下面有兩種解決思路(推薦第二種)

通過配置使得默認(rèn)的StringToLocalDateTimeConverter支持GET請(qǐng)求String轉(zhuǎn)LocalDateTime類型,默認(rèn)的MappingJackson2HttpMessageConverter支持POST請(qǐng)求String轉(zhuǎn)LocalDateTime類型

spring注入GenericConverter類型的Bean支持GET請(qǐng)求String轉(zhuǎn)LocalDateTime類型,注入ObjectMapper類型的Bean支持POST請(qǐng)求String轉(zhuǎn)LocalDateTime類型

4.1、GET請(qǐng)求解決思路

         GET請(qǐng)求解決思路:通過閱讀源碼,可以發(fā)現(xiàn)以下三種springboot為用戶預(yù)留的實(shí)現(xiàn)方式:  

application.yml配置

        在2.3.x以上版本,springmvc增加了日期時(shí)間格式配置,并且可以將格式注冊(cè)到對(duì)應(yīng)的日期解析器中

WebMvcAutoConfiguration#EnableWebMvcConfiguration類源碼
// springboot自動(dòng)裝配WebConversionService對(duì)象
@Bean
public FormattingConversionService mvcConversionService() {
    WebMvcProperties.Format format = this.mvcProperties.getFormat();
    WebConversionService conversionService = new WebConversionService((new DateTimeFormatters()).dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
    // 這里允許用戶自定往容器中添加Converter
    this.addFormatters(conversionService);
    return conversionService;
}
WebConversionService類源碼:
private void addFormatters(DateTimeFormatters dateTimeFormatters) {
    // 這是默認(rèn)情況下springboot自動(dòng)注入的日期格式解析器
    this.registerJsr310(dateTimeFormatters);
    this.registerJavaDate(dateTimeFormatters);
}

使用@DateTimeFormat注解

DateTimeFormatterRegistrar類源碼:
    public void registerFormatters(FormatterRegistry registry) {
        // 這里可以拿到application.yml配置文件指定的格式
        DateTimeFormatter df = this.getFormatter(DateTimeFormatterRegistrar.Type.DATE);
        DateTimeFormatter tf = this.getFormatter(DateTimeFormatterRegistrar.Type.TIME);
        DateTimeFormatter dtf = this.getFormatter(DateTimeFormatterRegistrar.Type.DATE_TIME);
        registry.addFormatterForFieldType(LocalDate.class, new TemporalAccessorPrinter(df == DateTimeFormatter.ISO_DATE ? DateTimeFormatter.ISO_LOCAL_DATE : df), new TemporalAccessorParser(LocalDate.class, df));
        registry.addFormatterForFieldType(LocalTime.class, new TemporalAccessorPrinter(tf == DateTimeFormatter.ISO_TIME ? DateTimeFormatter.ISO_LOCAL_TIME : tf), new TemporalAccessorParser(LocalTime.class, tf));
        registry.addFormatterForFieldType(LocalDateTime.class, new TemporalAccessorPrinter(dtf == DateTimeFormatter.ISO_DATE_TIME ? DateTimeFormatter.ISO_LOCAL_DATE_TIME : dtf), new TemporalAccessorParser(LocalDateTime.class, dtf));
        // 使用@DateTimeFormat注解來幫忙完成LocalDateTime類型的解析
        registry.addFormatterForFieldAnnotation(new Jsr310DateTimeFormatAnnotationFormatterFactory());
    }

向容器中添加自定義Converter

        我們?cè)赪ebConversionService對(duì)象自動(dòng)裝配方法中看到了這行代碼:this.addFormatters(conversionService);這其實(shí)就是springboot為用戶預(yù)留的拓展方法,它支持用戶向容器中添加自定義Converter

// WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#addFormatters()方法
public void addFormatters(FormatterRegistry registry) {
    ApplicationConversionService.addBeans(registry, this.beanFactory);
}
// ApplicationConversionService#addBeans()方法
public static void addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory) {
    Set<Object> beans = new LinkedHashSet();
    beans.addAll(beanFactory.getBeansOfType(GenericConverter.class).values());
    beans.addAll(beanFactory.getBeansOfType(Converter.class).values());
    beans.addAll(beanFactory.getBeansOfType(Printer.class).values());
    beans.addAll(beanFactory.getBeansOfType(Parser.class).values());
    Iterator var3 = beans.iterator();
    // spirngboot會(huì)掃描ioc容器中以下所有類型的bean,并添加到WebConversionService中
    while(var3.hasNext()) {
        Object bean = var3.next();
        if (bean instanceof GenericConverter) {
            registry.addConverter((GenericConverter)bean);
        } else if (bean instanceof Converter) {
            registry.addConverter((Converter)bean);
        } else if (bean instanceof Formatter) {
            registry.addFormatter((Formatter)bean);
        } else if (bean instanceof Printer) {
            registry.addPrinter((Printer)bean);
        } else if (bean instanceof Parser) {
            registry.addParser((Parser)bean);
        }
    }
}

4.2、POST請(qǐng)求解決思路

通過異常源碼分析我們可以得知,由于jackson也就是ObjectMapper對(duì)象在默認(rèn)情況下并不能完成LocalDateTime類型的解析,所有需要對(duì)jackson進(jìn)行配置;通過閱讀源碼,以下有兩種解決方式:

配置類注入Jackson2ObjectMapperBuilderCustomizer類型的Bean對(duì)jackson進(jìn)行配置(推薦)

JacksonAutoConfiguration#JacksonObjectMapperBuilderConfiguration類源碼:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
static class JacksonObjectMapperBuilderConfiguration {
    @Bean
    @Scope("prototype")
    @ConditionalOnMissingBean
    Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(ApplicationContext applicationContext,
            List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.applicationContext(applicationContext);
        // ioc容器中獲取所有Jackson2ObjectMapperBuilderCustomizer類型的bean, 調(diào)用customize方法配置Jackson2ObjectMapperBuilder
        customize(builder, customizers);
        return builder;
    }
    private void customize(Jackson2ObjectMapperBuilder builder,
            List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
        for (Jackson2ObjectMapperBuilderCustomizer customizer : customizers) {
            customizer.customize(builder);
        }
    }
}

直接注入ObjectMapper類型的Bean進(jìn)行覆蓋

JacksonAutoConfiguration#JacksonObjectMapperConfiguration類源碼
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
static class JacksonObjectMapperConfiguration {
    @Bean
    @Primary
    @ConditionalOnMissingBean
    ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        // 通過Jackson2ObjectMapperBuilder構(gòu)建出ObjectMapper
        return builder.createXmlMapper(false).build();
    }
}

五、解決方案落地

5.1、GET請(qǐng)求解決方案

application.yml配置 SpringBoot2.3.x以及更高的版本,springmvc增加了日期時(shí)間格式配置,既可以解決LocalDateTime類型參數(shù)解析,也可以解決Date類型參數(shù)解析

spring:
  mvc:
    date: yyyy-MM-dd
    time: HH:mm:ss
    date-time: yyyy-MM-dd HH:mm:ss

注解配置 SpringBoot針對(duì)LocalDateTime類型解析增加了@DateTimeFormatter注解,可以在請(qǐng)求參數(shù)中加上這個(gè)注解完成解析

@RestController
public class LocalDateTimeController {
    @GetMapping("/resolveRequestParamDateTime")
    public void resolveRequestParamDateTime(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime dateTime) {
        System.out.println("ok");
    }
    @GetMapping("/resolvePathVariableDateTime/{dateTime}")
    public void resolvePathVariableDateTime(@PathVariable @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime dateTime) {
        System.out.println("ok");
    }
}

Java Config注入Bean

在Spring IOC容器中注入Converter,SpringBoot會(huì)自動(dòng)將IOC容器中的Converter放到GenericConversionService中

@Configuration
public class LocalDateTimeConfig {
    @Bean
    public Converter<String, LocalDateTime> stringToLocalDateTimeConverter() {
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String source) {
                return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
        };
    }
    @Bean
    public Converter<String, LocalDate> stringToLocalDateConverter() {
        return new Converter<String, LocalDate>() {
            @Override
            public LocalDate convert(String source) {
                return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            }
        };
    }
    @Bean
    public Converter<String, LocalTime> stringToLocalTimeConverter() {
        return new Converter<String, LocalTime>() {
            @Override
            public LocalTime convert(String source) {
                return LocalTime.parse(source, DateTimeFormatter.ofPattern("HH:mm:ss"));
            }
        };
    }
}

5.2、POST請(qǐng)求解決方案

注解配置 在實(shí)體類的字段上使用@JsonFormat注解配置格式,使用 @JsonSerialize注解配置序列化器,使用 @JsonDeserialize注解配置反序列化器

@RestController
public class LocalDateTimeController {
    @PostMapping("/resolveBodyDateTime")
    public void resolveBodyDateTime(@RequestBody ResolveBody body) {
        System.out.println("ok");
    }
    @Data
    private static class ResolveBody {
        @JsonSerialize(using = LocalDateTimeSerializer.class)
        @JsonDeserialize(using = LocalDateTimeDeserializer.class)
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime dateTime;
    }
}

Java Config注入Bean

在Spring IOC容器中注入Jackson2ObjectMapperBuilderCustomizer類型的Bean可以對(duì)Jackson進(jìn)行自定義配置;也可以直接注入一個(gè)ObjectMapper進(jìn)行替換

@Configuration
public class LocalDateTimeConfig {
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return new Jackson2ObjectMapperBuilderCustomizer() {
            @Override
            public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
                final JavaTimeModule javaTimeModule = new JavaTimeModule();
                javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
                javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
                jacksonObjectMapperBuilder
                        .modules(javaTimeModule)
                        .featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                        .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                        .simpleDateFormat("yyyy-MM-dd HH:mm:ss")
                        .timeZone(TimeZone.getTimeZone("GMT+8"))
                        .locale(Locale.CHINA);
            }
        };
    }
}

到此這篇關(guān)于SpringBoot整合LocalDateTime的文章就介紹到這了,更多相關(guān)SpringBoot整合LocalDateTime內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot 在項(xiàng)目啟動(dòng)之后執(zhí)行自定義方法的兩種方式小結(jié)

    SpringBoot 在項(xiàng)目啟動(dòng)之后執(zhí)行自定義方法的兩種方式小結(jié)

    這篇文章主要介紹了SpringBoot 在項(xiàng)目啟動(dòng)之后執(zhí)行自定義方法的兩種方式小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 在springboot中如何集成clickhouse進(jìn)行讀寫操作

    在springboot中如何集成clickhouse進(jìn)行讀寫操作

    本文介紹了在Spring Boot中集成ClickHouse的步驟,包括引入依賴、配置數(shù)據(jù)源、編寫實(shí)體類和Mapper類進(jìn)行CRUD操作,特別提到批量插入時(shí)需要在SQL語句中添加`FORMAT`以避免錯(cuò)誤,在實(shí)際應(yīng)用中,與MySQL的操作類似,只需將ClickHouse當(dāng)作MySQL使用
    2024-11-11
  • Java二分算法題目練習(xí)實(shí)戰(zhàn)教程

    Java二分算法題目練習(xí)實(shí)戰(zhàn)教程

    二分查找(Binary?Search)是一種非常高效的查找算法,它在有序數(shù)組或有序列表中通過反復(fù)將搜索范圍分為兩半來查找目標(biāo)元素,這篇文章主要介紹了Java二分算法題目練習(xí)的相關(guān)資料,需要的朋友可以參考下
    2025-11-11
  • SpringBoot多環(huán)境切換的靈活配置詳細(xì)教程

    SpringBoot多環(huán)境切換的靈活配置詳細(xì)教程

    在真實(shí)項(xiàng)目開發(fā)的時(shí)候,一定會(huì)有多個(gè)環(huán)境,下面這篇文章主要給大家介紹了關(guān)于SpringBoot多環(huán)境切換靈活配置的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-04-04
  • SpringDataJpa like查詢無效的解決

    SpringDataJpa like查詢無效的解決

    這篇文章主要介紹了SpringDataJpa like查詢無效的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 深入解析SpringBatch適配器

    深入解析SpringBatch適配器

    Spring Batch是Spring的一個(gè)子項(xiàng)目,使用Java語言并基于Spring框架為基礎(chǔ)開發(fā),使得已經(jīng)使用 Spring 框架的開發(fā)者或者企業(yè)更容易訪問和利用企業(yè)服務(wù),本文給大家介紹SpringBatch適配器的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2021-11-11
  • Java?泛型的上界和下界通配符示例詳解

    Java?泛型的上界和下界通配符示例詳解

    這篇文章主要為大家通過示例介紹了Java?泛型的上界和下界通配符,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Java設(shè)計(jì)模式 模板模式及應(yīng)用場(chǎng)景解析

    Java設(shè)計(jì)模式 模板模式及應(yīng)用場(chǎng)景解析

    這篇文章主要介紹了Java設(shè)計(jì)模式 模板模式及應(yīng)用場(chǎng)景解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • 詳解如何將JAVA程序制作成可以直接執(zhí)行的exe文件

    詳解如何將JAVA程序制作成可以直接執(zhí)行的exe文件

    這篇文章主要介紹了詳解如何將JAVA程序制作成可以直接執(zhí)行的exe文件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Spring實(shí)戰(zhàn)之緩存使用key操作示例

    Spring實(shí)戰(zhàn)之緩存使用key操作示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之緩存使用key操作,結(jié)合實(shí)例形式分析了Spring緩存使用key具體配置、屬性、領(lǐng)域模型等相關(guān)操作技巧,需要的朋友可以參考下
    2020-01-01

最新評(píng)論

买车| 西林县| 阿巴嘎旗| 乐昌市| 邹城市| 花莲市| 习水县| 武强县| 遂昌县| 庆城县| 哈尔滨市| 吉隆县| 台山市| 杭州市| 广州市| 大新县| 灵石县| 河东区| 台江县| 自治县| 崇阳县| 绥化市| 若羌县| 锦屏县| 株洲市| 安塞县| 长子县| 桑植县| 台湾省| 延寿县| 颍上县| 阿合奇县| 金乡县| 济阳县| 天全县| 宜君县| 盐山县| 镇平县| 沛县| 枞阳县| 海伦市|