SpringBoot配置LocalDateTime格式化方式
【1】格式化后臺(tái)傳給前端的日期
- SpringBoot對(duì)Date/DateTime配置
- 第一種方式:配置localDateTimeSerializer
- 第二種方式:@JsonFormat
【2】前臺(tái)傳String格式日期給后臺(tái)
- ① 配置全局的日期轉(zhuǎn)換器localDateTimeConvert
- ② 配置日期格式化器
【3】convert是什么時(shí)候添加到ConversionService中的?
- ① SpringBoot啟動(dòng)的時(shí)候運(yùn)行run方法
- ② 嘗試獲取ConversionService
- ③ 獲取ApplicationConversionService
- ④ ApplicationConversionService.configure
- ⑤ DefaultConversionService.addDefaultConverters
- ⑥ addDefaultFormatters添加格式化器
- ⑦ addApplicationFormatters(registry)
- ⑧ addApplicationConverters(registry)
【1】格式化后臺(tái)傳給前端的日期
首先第一點(diǎn)需要知道的是springboot默認(rèn)依賴(lài)的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開(kāi)頭的配置會(huì)被JacksonProperties類(lèi)獲取進(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è)字段特殊處理,可以在類(lèi)字段上面添加注解@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ò)類(lèi)似如下:
nested exception is org.springframework.core.convert.ConversionFailedException:
Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime ]
很顯然是在參數(shù)綁定的時(shí)候沒(méi)有找到合適的轉(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("傳過(guò)來(lái)的是日期格式:{}",source);
source=source+" 00:00:00";
break;
case 13:
logger.debug("傳過(guò)來(lái)的是日期 小時(shí)格式:{}",source);
source=source+":00:00";
break;
case 16:
logger.debug("傳過(guò)來(lái)的是日期 小時(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)行初始化。
初始化方法具體可見(jià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-類(lèi)型格式化器。在WebDataBinder進(jìn)行參數(shù)綁定的時(shí)候就會(huì)使用不同的格式化器即不同的convert進(jìn)行參數(shù)類(lèi)型轉(zhuǎn)換。
關(guān)于參數(shù)綁定的過(guò)程,有興趣的可以跟蹤DataBinder.doBind方法,在這個(gè)過(guò)程中會(huì)對(duì)前臺(tái)傳輸?shù)闹颠M(jìn)行類(lèi)型轉(zhuǎn)換為目標(biāo)參數(shù)需要的類(lèi)型。自定義的localDateTimeConvert也是在這里被用到的。
如下所示前臺(tái)傳String格式給后臺(tái)參數(shù)endDate,參數(shù)類(lèi)型為java.time.LocalDateTime。

找到我們自定義的converter


調(diào)用convert進(jìn)行類(lèi)型轉(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)化配置過(guò)程中被加入,具體可以參考如下代碼。
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)鎖來(lái)獲取單例。
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)建過(guò)程會(huì)發(fā)現(xiàn)其走到了configure處:
public ApplicationConversionService(StringValueResolver embeddedValueResolver) {
if (embeddedValueResolver != null) {
this.setEmbeddedValueResolver(embeddedValueResolver);
}
//我們從這里繼續(xù)跟進(jìn)
configure(this);
}
這里我們順帶看一下ApplicationConversionService的類(lèi)繼承示意圖(其不只是可以作為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è)類(lèi)型轉(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è)類(lèi)型轉(zhuǎn)換器:

添加集合處理的類(lèi)型轉(zhuǎn)換器(這里會(huì)添加17個(gè)類(lèi)型轉(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)
添加全局類(lèi)型轉(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));
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實(shí)現(xiàn)六邊形架構(gòu)的三種不同方式詳解
六邊形架構(gòu),也被稱(chēng)為端口與適配器架構(gòu)或洋蔥架構(gòu),是一種將業(yè)務(wù)邏輯與外部依賴(lài)解耦的架構(gòu)模式,本文將介紹在SpringBoot中實(shí)現(xiàn)六邊形架構(gòu)的三種不同方式2025-06-06
Java超詳細(xì)講解設(shè)計(jì)模式之一的單例模式
單例模式(Singleton Pattern)是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類(lèi)型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式2022-03-03
Springboot并發(fā)調(diào)優(yōu)之大事務(wù)和長(zhǎng)連接
這篇文章主要介紹了Springboot并發(fā)調(diào)優(yōu)之大事務(wù)和長(zhǎng)連接,重點(diǎn)分享長(zhǎng)事務(wù)以及長(zhǎng)連接導(dǎo)致的并發(fā)排查和優(yōu)化思路和示例,具有一定的參考價(jià)值,感興趣的可以了解一下2022-05-05
IDEA解決@Slf4j中l(wèi)og報(bào)紅問(wèn)題
在IntelliJ IDEA中使用log.info()時(shí),如果出現(xiàn)錯(cuò)誤,通常是因?yàn)槿鄙貺ombok插件,以下是解決方法:打開(kāi)IntelliJ IDEA,進(jìn)入設(shè)置(File > Settings 或者 Ctrl+Alt+S),在Plugins部分點(diǎn)擊Browse repositories,搜索Lombok并安裝,安裝完成后,問(wèn)題通??梢越鉀Q2024-12-12
springboot上傳文件,url直接訪問(wèn)資源問(wèn)題
這篇文章主要介紹了springboot上傳文件,url直接訪問(wèn)資源問(wèn)題。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
FeignClient支持運(yùn)行時(shí)動(dòng)態(tài)指定URL方式
在實(shí)際開(kāi)發(fā)中,我們經(jīng)常通過(guò)FeignClient接口調(diào)用三方API,當(dāng)面對(duì)不同的環(huán)境對(duì)應(yīng)不同的地址時(shí),可以通過(guò)配置文件和占位符來(lái)切換,但在同一個(gè)環(huán)境中需要調(diào)用不同地址的相同接口時(shí),這種方法就失效了,此時(shí),可以通過(guò)實(shí)現(xiàn)RequestInterceptor接口來(lái)動(dòng)態(tài)切換地址2024-11-11
Java 枚舉的基本使用方法及實(shí)際使用場(chǎng)景
枚舉是 Java 中一種特殊的類(lèi),用于定義一組固定的常量,枚舉類(lèi)型提供了更好的類(lèi)型安全性和可讀性,適用于需要定義一組有限且固定的值的場(chǎng)景,本文給大家介紹Java 枚舉的用法及實(shí)際使用場(chǎng)景,感興趣的朋友一起看看吧2025-06-06
MyBatis動(dòng)態(tài)標(biāo)簽詳解與應(yīng)用實(shí)踐舉例
MyBatis的動(dòng)態(tài)SQL功能通過(guò)一組強(qiáng)大的標(biāo)簽實(shí)現(xiàn),使得根據(jù)業(yè)務(wù)條件構(gòu)建靈活SQL查詢(xún)變得簡(jiǎn)單高效,這些標(biāo)簽基于OGNL表達(dá)式,能夠智能生成SQL,避免了手動(dòng)拼接SQL的復(fù)雜性和風(fēng)險(xiǎn),感興趣的朋友跟隨小編一起看看吧2026-01-01

