SpringBoot如何對(duì)LocalDateTime進(jìn)行格式化并解析
【1】格式化后臺(tái)傳給前端的日期
首先第一點(diǎn)需要知道的是springboot默認(rèn)依賴的json框架是jackson。
當(dāng)使用@ResponseBody注解返回json格式數(shù)據(jù)時(shí)就是該框架在起作用。

SpringBoot對(duì)Date/DateTime配置
如果字段屬性是Date而非LocalDateTime時(shí),通常我們會(huì)在application.properties里面配置如下:
spring.mvc.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.time-zone=GMT+8 spring.jackson.serialization.write-dates-as-timestamps=false
如下圖所示,spring.jackson開頭的配置會(huì)被JacksonProperties類獲取進(jìn)行使用。
當(dāng)返回json格式的時(shí)候,Jackson就會(huì)根據(jù)配置文件中日期格式化的配置對(duì)結(jié)果進(jìn)行處理。

但是如果字段屬性為L(zhǎng)ocalDateTime呢?這種配置就失去了作用。
第一種方式:配置localDateTimeSerializer
這時(shí)候建議配置如下:
/**
* Created by jianggc at 2020/7/1.
*/
@Configuration
public class LocalDateTimeSerializerConfig {
@Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
private String pattern;
// localDateTime 序列化器
@Bean
public LocalDateTimeSerializer localDateTimeSerializer() {
return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern));
}
// localDateTime 反序列化器
@Bean
public LocalDateTimeDeserializer localDateTimeDeserializer() {
return new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(pattern));
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
// return new Jackson2ObjectMapperBuilderCustomizer() {
// @Override
// public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// jacksonObjectMapperBuilder.serializerByType(LocalDateTime.class, localDateTimeSerializer());
// jacksonObjectMapperBuilder.deserializerByType(LocalDateTime.class,localDateTimeDeserializer());
// }
// };
//這種方式同上
return builder -> {
builder.serializerByType(LocalDateTime.class, localDateTimeSerializer());
builder.deserializerByType(LocalDateTime.class,localDateTimeDeserializer());
builder.simpleDateFormat(pattern);
};
}
}
第二種方式:@JsonFormat
這種配置方式自然是全局的,如果想針對(duì)某個(gè)字段特殊處理,可以在類字段上面添加注解@JsonFormat:
@JsonFormat( pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date createdDate;
@JsonFormat( pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createdTime;
【2】前臺(tái)傳String格式日期給后臺(tái)
如下所示,前臺(tái)傳參2020-08-30 11:11:11,后臺(tái)使用LocalDateTime 接收。
通常會(huì)報(bào)錯(cuò)類似如下:
nested exception is org.springframework.core.convert.ConversionFailedException:
Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime ]
很顯然是在參數(shù)綁定的時(shí)候沒有找到合適的轉(zhuǎn)換器把String轉(zhuǎn)換為對(duì)應(yīng)的格式。
① 配置全局的日期轉(zhuǎn)換器localDateTimeConvert
@Bean
public Converter<String, LocalDateTime> localDateTimeConvert() {
return new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String source) {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = null;
try {
//2020-01-01 00:00:00
switch (source.length()){
case 10:
logger.debug("傳過來的是日期格式:{}",source);
source=source+" 00:00:00";
break;
case 13:
logger.debug("傳過來的是日期 小時(shí)格式:{}",source);
source=source+":00:00";
break;
case 16:
logger.debug("傳過來的是日期 小時(shí):分鐘格式:{}",source);
source=source+":00";
break;
}
dateTime = LocalDateTime.parse(source, df);
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
return dateTime;
}
};
}
實(shí)現(xiàn)原理簡(jiǎn)要描述
在進(jìn)行參數(shù)綁定的時(shí)候,會(huì)使用WebDataBinder對(duì)象。而創(chuàng)建WebDataBinder對(duì)象時(shí),會(huì)遍歷DefaultDataBinderFactory.initializer,使用其WebBindingInitializer initializer對(duì)WebDataBinder對(duì)象進(jìn)行初始化。
初始化方法具體可見ConfigurableWebBindingInitializer.initBinder(WebDataBinder binder),源碼如下:
public void initBinder(WebDataBinder binder) {
binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
if (this.directFieldAccess) {
binder.initDirectFieldAccess();
}
//設(shè)置messageCodesResolver
if (this.messageCodesResolver != null) {
binder.setMessageCodesResolver(this.messageCodesResolver);
}
//設(shè)置bindingErrorProcessor
if (this.bindingErrorProcessor != null) {
binder.setBindingErrorProcessor(this.bindingErrorProcessor);
}
//設(shè)置validator
if (this.validator != null && binder.getTarget() != null && this.validator.supports(binder.getTarget().getClass())) {
binder.setValidator(this.validator);
}
//設(shè)置conversionService
if (this.conversionService != null) {
binder.setConversionService(this.conversionService);
}
if (this.propertyEditorRegistrars != null) {
PropertyEditorRegistrar[] var2 = this.propertyEditorRegistrars;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
PropertyEditorRegistrar propertyEditorRegistrar = var2[var4];
propertyEditorRegistrar.registerCustomEditors(binder);
}
}
}
而conversionService中包含了許多的convert-類型格式化器。在WebDataBinder進(jìn)行參數(shù)綁定的時(shí)候就會(huì)使用不同的格式化器即不同的convert進(jìn)行參數(shù)類型轉(zhuǎn)換。
關(guān)于參數(shù)綁定的過程,有興趣的可以跟蹤DataBinder.doBind方法,在這個(gè)過程中會(huì)對(duì)前臺(tái)傳輸?shù)闹颠M(jìn)行類型轉(zhuǎn)換為目標(biāo)參數(shù)需要的類型。自定義的localDateTimeConvert也是在這里被用到的。
如下所示前臺(tái)傳String格式給后臺(tái)參數(shù)endDate,參數(shù)類型為java.time.LocalDateTime。

找到我們自定義的converter


調(diào)用convert進(jìn)行類型轉(zhuǎn)換:

可以看到轉(zhuǎn)換后的結(jié)果為:

② 配置日期格式化器
/**
* yyyy-MM-dd HH:mm:ss String-localDateTime
* @return
*/
@Bean
public Formatter<LocalDateTime> localDateTimeFormatter() {
return new Formatter<LocalDateTime>() {
@Override
public LocalDateTime parse(String text, Locale locale) throws ParseException {
return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
@Override
public String print(LocalDateTime localDateTime, Locale locale) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return formatter.format(localDateTime);
}
};
}
自定義的格式化器會(huì)在SpringBoot啟動(dòng)時(shí)自動(dòng)化配置過程中被加入,具體可以參考如下代碼。
WebMvcAutoConfiguration.mvcConversionService:
@Bean
@Override
public FormattingConversionService mvcConversionService() {
WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
addFormatters(conversionService);
return conversionService;
}
【3】convert是什么時(shí)候添加到ConversionService中的?
① SpringBoot啟動(dòng)的時(shí)候運(yùn)行run方法
其會(huì)走到SpringApplication.configureEnvironment方法處:
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
//從這里跟蹤
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService)conversionService);
}
this.configurePropertySources(environment, args);
this.configureProfiles(environment, args);
}
② 嘗試獲取ConversionService
ApplicationConversionService.getSharedInstance如下所示,這里可以看到其使用了設(shè)計(jì)模式中的懶漢式之雙重校驗(yàn)鎖來獲取單例。
public static ConversionService getSharedInstance() {
ApplicationConversionService sharedInstance = sharedInstance;
if (sharedInstance == null) {
Class var1 = ApplicationConversionService.class;
synchronized(ApplicationConversionService.class) {
sharedInstance = sharedInstance;
if (sharedInstance == null) {
sharedInstance = new ApplicationConversionService();
sharedInstance = sharedInstance;
}
}
}
return sharedInstance;
}
③ 獲取ApplicationConversionService
繼續(xù)對(duì)象創(chuàng)建過程會(huì)發(fā)現(xiàn)其走到了configure處:
public ApplicationConversionService(StringValueResolver embeddedValueResolver) {
if (embeddedValueResolver != null) {
this.setEmbeddedValueResolver(embeddedValueResolver);
}
//我們從這里繼續(xù)跟進(jìn)
configure(this);
}
這里我們順帶看一下ApplicationConversionService的類繼承示意圖(其不只是可以作為ConversionService還可以作為ConverterRegistry與FormatterRegistry):

④ ApplicationConversionService.configure
創(chuàng)建ApplicationConversionService時(shí)會(huì)對(duì)其進(jìn)行配置,這里很重要。其會(huì)注入默認(rèn)的Converter和Formatter:
public static void configure(FormatterRegistry registry) {
DefaultConversionService.addDefaultConverters(registry);
DefaultFormattingConversionService.addDefaultFormatters(registry);
addApplicationFormatters(registry);
addApplicationConverters(registry);
}
⑤ DefaultConversionService.addDefaultConverters
該方法執(zhí)行完,會(huì)添加52個(gè)類型轉(zhuǎn)換器:
public static void addDefaultConverters(ConverterRegistry converterRegistry) {
addScalarConverters(converterRegistry);
addCollectionConverters(converterRegistry);
converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new StringToTimeZoneConverter());
converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());
converterRegistry.addConverter(new ObjectToObjectConverter());
converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new FallbackObjectToStringConverter());
converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
}
addScalarConverters(converterRegistry);如下所示:
private static void addScalarConverters(ConverterRegistry converterRegistry) {
converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCharacterConverter());
converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new NumberToCharacterConverter());
converterRegistry.addConverterFactory(new CharacterToNumberFactory());
converterRegistry.addConverter(new StringToBooleanConverter());
converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry));
converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory());
converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new StringToLocaleConverter());
converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCharsetConverter());
converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCurrencyConverter());
converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToPropertiesConverter());
converterRegistry.addConverter(new PropertiesToStringConverter());
converterRegistry.addConverter(new StringToUUIDConverter());
converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
}
這里會(huì)添加23個(gè)類型轉(zhuǎn)換器:

添加集合處理的類型轉(zhuǎn)換器(這里會(huì)添加17個(gè)類型轉(zhuǎn)換器):
public static void addCollectionConverters(ConverterRegistry converterRegistry) {
ConversionService conversionService = (ConversionService) converterRegistry;
converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
converterRegistry.addConverter(new MapToMapConverter(conversionService));
converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
converterRegistry.addConverter(new StringToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToStringConverter(conversionService));
converterRegistry.addConverter(new StringToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));
converterRegistry.addConverter(new StreamConverter(conversionService));
}
⑥ addDefaultFormatters添加格式化器
/**
* Add formatters appropriate for most environments: including number formatters,
* JSR-354 Money & Currency formatters, JSR-310 Date-Time and/or Joda-Time formatters,
* depending on the presence of the corresponding API on the classpath.
* @param formatterRegistry the service to register default formatters with
*/
public static void addDefaultFormatters(FormatterRegistry formatterRegistry) {
// Default handling of number values
formatterRegistry.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
// Default handling of monetary values
if (jsr354Present) {
formatterRegistry.addFormatter(new CurrencyUnitFormatter());
formatterRegistry.addFormatter(new MonetaryAmountFormatter());
formatterRegistry.addFormatterForFieldAnnotation(new Jsr354NumberFormatAnnotationFormatterFactory());
}
// Default handling of date-time values
// just handling JSR-310 specific date and time types
new DateTimeFormatterRegistrar().registerFormatters(formatterRegistry);
if (jodaTimePresent) {
// handles Joda-specific types as well as Date, Calendar, Long
new JodaTimeFormatterRegistrar().registerFormatters(formatterRegistry);
}
else {
// regular DateFormat-based Date, Calendar, Long converters
new DateFormatterRegistrar().registerFormatters(formatterRegistry);
}
}
DateTimeFormatterRegistrar.registerFormatters
@Override
public void registerFormatters(FormatterRegistry registry) {
DateTimeConverters.registerConverters(registry);
DateTimeFormatter df = getFormatter(Type.DATE);
DateTimeFormatter tf = getFormatter(Type.TIME);
DateTimeFormatter dtf = getFormatter(Type.DATE_TIME);
// Efficient ISO_LOCAL_* variants for printing since they are twice as fast...
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));
registry.addFormatterForFieldType(ZonedDateTime.class,
new TemporalAccessorPrinter(dtf),
new TemporalAccessorParser(ZonedDateTime.class, dtf));
registry.addFormatterForFieldType(OffsetDateTime.class,
new TemporalAccessorPrinter(dtf),
new TemporalAccessorParser(OffsetDateTime.class, dtf));
registry.addFormatterForFieldType(OffsetTime.class,
new TemporalAccessorPrinter(tf),
new TemporalAccessorParser(OffsetTime.class, tf));
registry.addFormatterForFieldType(Instant.class, new InstantFormatter());
registry.addFormatterForFieldType(Period.class, new PeriodFormatter());
registry.addFormatterForFieldType(Duration.class, new DurationFormatter());
registry.addFormatterForFieldType(Year.class, new YearFormatter());
registry.addFormatterForFieldType(Month.class, new MonthFormatter());
registry.addFormatterForFieldType(YearMonth.class, new YearMonthFormatter());
registry.addFormatterForFieldType(MonthDay.class, new MonthDayFormatter());
registry.addFormatterForFieldAnnotation(new Jsr310DateTimeFormatAnnotationFormatterFactory());
}
DateTimeConverters.registerConverters
public static void registerConverters(ConverterRegistry registry) {
DateFormatterRegistrar.addDateConverters(registry);
registry.addConverter(new LocalDateTimeToLocalDateConverter());
registry.addConverter(new LocalDateTimeToLocalTimeConverter());
registry.addConverter(new ZonedDateTimeToLocalDateConverter());
registry.addConverter(new ZonedDateTimeToLocalTimeConverter());
registry.addConverter(new ZonedDateTimeToLocalDateTimeConverter());
registry.addConverter(new ZonedDateTimeToOffsetDateTimeConverter());
registry.addConverter(new ZonedDateTimeToInstantConverter());
registry.addConverter(new OffsetDateTimeToLocalDateConverter());
registry.addConverter(new OffsetDateTimeToLocalTimeConverter());
registry.addConverter(new OffsetDateTimeToLocalDateTimeConverter());
registry.addConverter(new OffsetDateTimeToZonedDateTimeConverter());
registry.addConverter(new OffsetDateTimeToInstantConverter());
registry.addConverter(new CalendarToZonedDateTimeConverter());
registry.addConverter(new CalendarToOffsetDateTimeConverter());
registry.addConverter(new CalendarToLocalDateConverter());
registry.addConverter(new CalendarToLocalTimeConverter());
registry.addConverter(new CalendarToLocalDateTimeConverter());
registry.addConverter(new CalendarToInstantConverter());
registry.addConverter(new LongToInstantConverter());
registry.addConverter(new InstantToLongConverter());
}
DateFormatterRegistrar.addDateConverters
public static void addDateConverters(ConverterRegistry converterRegistry) {
converterRegistry.addConverter(new DateToLongConverter());
converterRegistry.addConverter(new DateToCalendarConverter());
converterRegistry.addConverter(new CalendarToDateConverter());
converterRegistry.addConverter(new CalendarToLongConverter());
converterRegistry.addConverter(new LongToDateConverter());
converterRegistry.addConverter(new LongToCalendarConverter());
}
⑦ addApplicationFormatters(registry)
添加全局格式化器:
public static void addApplicationFormatters(FormatterRegistry registry) {
registry.addFormatter(new CharArrayFormatter());
registry.addFormatter(new InetAddressFormatter());
registry.addFormatter(new IsoOffsetFormatter());
}
⑧ addApplicationConverters(registry)
添加全局類型轉(zhuǎn)換器:
public static void addApplicationConverters(ConverterRegistry registry) {
addDelimitedStringConverters(registry);
registry.addConverter(new StringToDurationConverter());
registry.addConverter(new DurationToStringConverter());
registry.addConverter(new NumberToDurationConverter());
registry.addConverter(new DurationToNumberConverter());
registry.addConverter(new StringToDataSizeConverter());
registry.addConverter(new NumberToDataSizeConverter());
registry.addConverter(new StringToFileConverter());
registry.addConverterFactory(new LenientStringToEnumConverterFactory());
registry.addConverterFactory(new LenientBooleanToEnumConverterFactory());
}
public static void addDelimitedStringConverters(ConverterRegistry registry) {
ConversionService service = (ConversionService)registry;
registry.addConverter(new ArrayToDelimitedStringConverter(service));
registry.addConverter(new CollectionToDelimitedStringConverter(service));
registry.addConverter(new DelimitedStringToArrayConverter(service));
registry.addConverter(new DelimitedStringToCollectionConverter(service));
}
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Cloud 服務(wù)網(wǎng)關(guān)Zuul的實(shí)現(xiàn)
這篇文章主要介紹了Spring Cloud 服務(wù)網(wǎng)關(guān)Zuul的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
SpringBoot使用Feign進(jìn)行服務(wù)間通信的實(shí)現(xiàn)示例代碼
Feign是一個(gè)開源的Java HTTP客戶端,可以幫助我們?cè)赟pringBoot應(yīng)用中快速構(gòu)建和使用HTTP客戶端,方便實(shí)現(xiàn)服務(wù)間的通信,本文就來介紹一下SpringBoot使用Feign進(jìn)行服務(wù)間通信的實(shí)現(xiàn)示例代碼,感興趣的可以了解一下2024-01-01
Java實(shí)現(xiàn)Android拼圖游戲設(shè)計(jì)過程解析
這篇文章主要介紹了Java實(shí)現(xiàn)Android拼圖游戲設(shè)計(jì)過程解析,下面文章要接受的這是一款基于 Java 開發(fā)的移動(dòng)端安卓小游戲,可以作為大家在學(xué)習(xí)期間的一個(gè)小練習(xí),接下來和小編一起進(jìn)入文章學(xué)習(xí)具體內(nèi)容吧2022-02-02
SpringBoot實(shí)現(xiàn)OneDrive文件上傳的詳細(xì)步驟
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)OneDrive文件上傳的詳細(xì)步驟,文中通過代碼示例和圖文講解的非常詳細(xì),對(duì)大家實(shí)現(xiàn)OneDrive文件上傳有一定的幫助,需要的朋友可以參考下2024-02-02
Java實(shí)現(xiàn)可視化走迷宮小游戲的示例代碼
這篇文章主要介紹了Java如何實(shí)現(xiàn)可視化走迷宮小游戲。本程序適用于java程序員鞏固類與對(duì)象、文件讀取、事件響應(yīng)、awt包中各種工具的相關(guān)概念以及對(duì)邏輯能力的鍛煉,需要的可以參考一下2022-11-11
可視化Swing中JTable控件綁定SQL數(shù)據(jù)源的兩種方法深入解析
以下是對(duì)可視化Swing中JTable控件綁定SQL數(shù)據(jù)源的兩種方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考一下2013-07-07
Java數(shù)據(jù)結(jié)構(gòu)中堆的向下和向上調(diào)整解析
堆是一顆完全二叉樹,在這棵樹中,所有父節(jié)點(diǎn)都滿足大于等于其子節(jié)點(diǎn)的堆叫大根堆,所有父節(jié)點(diǎn)都滿足小于等于其子節(jié)點(diǎn)的堆叫小根堆。堆雖然是一顆樹,但是通常存放在一個(gè)數(shù)組中,父節(jié)點(diǎn)和孩子節(jié)點(diǎn)的父子關(guān)系通過數(shù)組下標(biāo)來確定2021-11-11
如何解決SpringBoot啟動(dòng)時(shí)無(wú)法加載配置文件或環(huán)境變量問題
文章主要介紹了在Spring Boot項(xiàng)目中遇到配置文件加載失敗和資源目錄圖標(biāo)異常的問題,并提供了詳細(xì)的解決步驟,解決方法包括在pom.xml文件中添加特定配置,確保資源目錄順序正確,以及注意節(jié)點(diǎn)的正確使用,通過這些步驟,可以有效解決資源加載問題,提高開發(fā)效率2024-12-12

