参数绑定与类型转换(Converter/Formatter)
结论先行:Controller 入参绑定由 HandlerMethodArgumentResolver 驱动,不同类型走不同通道:标量参数(@RequestParam/@PathVariable 的字符串)经 ConversionService 转换成目标类型;POJO 表单走 WebDataBinder 数据绑定;@RequestBody JSON 走 HttpMessageConverter。类型转换体系的核心三件套:ConversionService(总入口)、Converter<S,T>(无状态通用转换)、Formatter<T>(parse + print,面向展示/可带 Locale);旧的 PropertyEditor 已不推荐。
一、绑定与转换对应关系
| 入参方式 | 处理组件 | 说明 |
|---|---|---|
| @RequestParam / @PathVariable | ConversionService | String → Integer/LocalDate/枚举等 |
| 表单 POJO 字段绑定 | WebDataBinder + Converter | 逐字段类型转换 + 校验 |
| @RequestBody JSON/XML | HttpMessageConverter | 字节流 ↔ 对象的消息级转换 |
| @DateTimeFormat/@NumberFormat | 格式化注解驱动 | 走 FormattingConversionService |
二、自定义 Converter
// 1) 实现 Converter:字符串 → 枚举/值对象
public class StringToStatusConverter implements Converter<String, OrderStatus> {
@Override
public OrderStatus convert(String source) { return OrderStatus.of(source); }
}
// 2) 注册进 MVC 的转换服务(WebMvcConfigurer)
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToStatusConverter());
}
// 3) 使用:请求参数 ?status=PAID 直接绑定成枚举
@GetMapping("/orders")
public Result<List<Order>> list(@RequestParam OrderStatus status) {
return orderService.list(status); // status 已被 Converter 转成枚举
}
常见追问 / 记忆点
- 追问 1:Converter 与 Formatter 区别?答:Converter 做任意 S→T 的无状态转换、与 UI 无关;Formatter 偏展示层,实现 parse(字符串→对象)与 print(对象→字符串),可结合注解与 Locale 使用。
- 追问 2:@RequestBody 走 Converter 吗?答:不走——那是 HttpMessageConverter 的消息级转换(JSON 序列化框架如 Jackson),与属性级 ConversionService 是两个层级。
- 追问 3:为什么不用 PropertyEditor?答:有状态、非线程安全、只处理 String↔对象,官方已用 Converter/Formatter 体系取代。
- 记忆点:"标量走 ConversionService、POJO 走 Binder、Body 走 MessageConverter;自定义转换优先 Converter/Formatter"。