從 Spring 3.x 之後,提供了 org.springframework.core.convert
定義了通用的型態轉換介面等機制,在 Spring MVC 中,可做為 PropertyEditor
的替代機制。
型態轉換的邏輯,主要可實作 Converter
介面來達成:
package org.springframework.core.convert.converter;
public interface Converter<S, T> {
T convert(S source);
}
S
是來源型態,T
是目標型態,例如,若想將 String
轉換為 LocalDateTime
:
package cc.openhome.aspect;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import org.springframework.core.convert.converter.Converter;
public class StringToLocalDateTimeConvertor implements Converter<String, LocalDateTime> {
@Override
public LocalDateTime convert(String millis) {
System.out.println("converter");
return Instant.ofEpochMilli(Long.parseLong(millis))
.atZone(ZoneId.of("Asia/Taipei"))
.toLocalDateTime();
}
}
WebDataBinder
內部會使用一些 Converter
來進行型態轉換,例如,若請求參數值實際上代表某個整數值,在處理器的參數為 Long
的話,就會自動將之剖析為 Long
(透過 StringToNumberConverterFactory
);如果要加入自定義的 Converter
實例,可以在 WebConfig
中定義:
... 略
public class WebConfig implements WebMvcConfigurer, ApplicationContextAware {
...
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToLocalDateTimeConvertor());
}
}
這麼一來,若有個控制器中有處理器被標示為:
@PostMapping("do_foo")
protected String doFoo(@RequestParam("millis") LocalDateTime localDateTime) {
/// ...做點事
}
就會使用以上定義的 LocalDateTimeConvertor
將字串轉換為 LocalDateTime
實例。
如上所述,Spring 內建了一些轉換器,例如,Spring 可使用請求參數值中的 ,
來切割請求參數值,視你處理器上的參數而定,若為 String[] millis
,就會使用 StringToArrayConverter
將 millis=1234,5678
轉換為陣列,若為 List<String> millis
,就會使用 StringToCollectionConverter
轉換。
PropertyEditor
仍然適用於簡單的場合,然而,使用 Converter
的好處在於可以彼此銜接,如果你定義了上面的 StringToLocalDateTimeConvertor
,而處理器參數為 List<LocalDateTime> millis
,millis=1234,5678
這樣的請求參數,就會被轉換為 List<LocalDateTime>
實例。
如果請求參數已經被 PropertyEditor
編輯過了,那麼就不會套用 Converter
的機制。