类图
底层第一套转换接口与实现
- Printer 把其它类型转为 String
- Parser 把 String 转为其它类型
- Formatter 综合 Printer 与 Parser 功能
- Converter 把类型 S 转为类型 T
- Printer、Parser、Converter 经过适配转换成 GenericConverter 放入 Converters 集合
- FormattingConversionService 利用其它们实现转换
底层第二套转换接口
- PropertyEditor 把 String 与其它类型相互转换
- PropertyEditorRegistry 可以注册多个 PropertyEditor 对象
- 与第一套接口直接可以通过 FormatterPropertyEditorAdapter 来进行适配
高层接口与实现
- 它们都实现了 TypeConverter 这个高层转换接口,在转换时,会用到 TypeConverter Delegate 委派ConversionService 与 PropertyEditorRegistry 真正执行转换(Facade 门面模式)
- 首先看是否有自定义转换器, @InitBinder 添加的即属于这种 (用了适配器模式把 Formatter 转为需要的 PropertyEditor)
- 再看有没有 ConversionService 转换
- 再利用默认的 PropertyEditor 转换
- 最后有一些特殊处理
- SimpleTypeConverter 仅做类型转换
- BeanWrapperImpl 为 bean 的属性赋值,当需要时做类型转换,走 Property
- DirectFieldAccessor 为 bean 的属性赋值,当需要时做类型转换,走 Field
- ServletRequestDataBinder 为 bean 的属性执行绑定,当需要时做类型转换,根据 directFieldAccess 选择走 Property 还是 Field,具备校验与获取校验结果功能
案例
非web环境
SimpleConverter
输出
BeanWrapper
输出
FieldAccessor
DataBinder
默认走set方法绑定数据
去掉set方法后
dataBinder.initDirectFieldAccess();
开启直接字段的访问web环境
ServletRequestDataBinder
数据绑定工厂
ServletRequestDataBinder 的局限性
使用之前的ServletRequestDataBinder 去绑定参数无法支持特殊的数据类型,比如日期,如果输入的是自定义格式
YYYY|MM|DD
输出
日期类型没有绑定上
使用工厂创建转换器
用 @InitBinder 转换
自定义转换器,继承Formatter接口
ConversionService
同时使用ConversionService和@initBinder
@initBinder优先级更高
使用默认的ConversionService 不需要自定义formatter,配合
@DateTimeFormat(pattern = "yyyy|MM|dd")
springboot使用ApplicationConversionService
非springboot用DefaultConversionService