Web 開發中,HTTP 參數全是 String,但 Controller 方法參數卻是 Integer、Date、Enum、自定義對象等。Spring 的 ConversionService 體系將「字符串 → 目標類型」的轉換邏輯標準化、集中化、可擴展化,避免 Controller 充斥解析代碼。
// 核心轉換器接口(S -> T)
public interface Converter<S, T> {
T convert(S source);
}
// 統一服務入口
public interface ConversionService {
boolean canConvert(Class<?> sourceType, Class<?> targetType);
<T> T convert(Object source, Class<T> targetType);
// ...
}
// 格式化接口(雙向:對象 ↔ 字符串,帶 Locale)
public interface Formatter<T> extends Printer<T>, Parser<T> {}
public class StringToDateConverter implements Converter<String, Date> {
private String pattern = "yyyy-MM-dd"; // 默認格式
public void setPattern(String pattern) { this.pattern = pattern; }
@Override
public Date convert(String source) {
try {
return new SimpleDateFormat(pattern).parse(source);
} catch (ParseException e) {
throw new ConversionFailedException(
TypeDescriptor.valueOf(String.class),
TypeDescriptor.valueOf(Date.class),
source, e);
}
}
}
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.example.converter.StringToDateConverter">
<property name="pattern" value="yyyy-MM-dd HH:mm:ss"/>
</bean>
<!-- 其他自定義轉換器 -->
</set>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService" />
現在 Controller 直接接收 Date 參數:
@GetMapping("/search")
public List<Order> search(@RequestParam("startDate") Date startDate) {
// 自動轉換 "2024-01-15" → Date
return orderService.findByDate(startDate);
}
public class DateFormatter implements Formatter<Date> {
private String pattern = "yyyy-MM-dd";
@Override // 對象 → 字符串(顯示)
public String print(Date date, Locale locale) {
return new SimpleDateFormat(pattern, locale).format(date);
}
@Override // 字符串 → 對象(解析)
public Date parse(String text, Locale locale) throws ParseException {
return new SimpleDateFormat(pattern, locale).parse(text);
}
}
註冊:
<bean id="conversionService" class="...ConversionServiceFactoryBean">
<property name="formatters">
<set><bean class="com.example.format.DateFormatter"/></set>
</property>
</bean>
| 轉換器 | 來源 → 目標 | 說明 |
|---|---|---|
| StringToNumberConverterFactory | String → Number 子類 | Integer、Long、Double、BigDecimal 等 |
| StringToBooleanConverter | String → Boolean | "true"/"false", "yes"/"no", "on"/"off" |
| StringToEnumConverterFactory | String → Enum | 按 name() 或 toString() 匹配 |
| ObjectToObjectConverter | 任意 → 任意 | 通過 toString/valueOf 兜底 |
| Collection/Array/Map 轉換器 | String ↔ Collection | 逗號分隔字符串 ↔ List/Set |
@DateTimeFormat、@NumberFormat 註解直接標註字段/參數ConversionServiceFactoryBean + mvc:annotation-drivenConversionFailedException,配合 @ControllerAdvice 統一返回友好錯誤Spring 類型轉換體系將「解析邏輯」從業務代碼中剝離,形成可複用、可測試、可擴展的基礎設施。掌握 Converter(單向)、Formatter(雙向+Locale)、ConversionService(統一入口)三層架構,能讓 Controller 保持乾淨專注於業務流轉。