底层第一套转换接口与实现
FormattingConversionService
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
DataBinder 普通环境下的属性数据绑定类型转换
ServletRequestDataBinder 为 bean 的属性执行绑定,当需要时做类型转换,根据 directFieldAccess 选择走 Property 还是 Field,具备校验与获取校验结果功能
类型转换与数据绑定
点击查看代码
SimpleTypeConverter converter = new SimpleTypeConverter();
System.out .println(converter.convertIfNecessary("11" , int .class ));
System.out .println(converter.convertIfNecessary("2011/01/02" , Date.class ));
BeanWrapperImpl beanWrapper = new BeanWrapperImpl ();
S22Bean1 s22Bean1 = new S22Bean1 ();
beanWrapper.setBeanInstance(s22Bean1);
beanWrapper.setPropertyValue("name" ,13 );
beanWrapper.setPropertyValue("age" ,"32" );
beanWrapper.setPropertyValue("date" ,"2011/11/20" );
System.out.println(s22Bean1);
S22Bean2 s22Bean2 = new S22Bean2 ();
DirectFieldAccessor fieldAccessor = new DirectFieldAccessor (s22Bean2);
fieldAccessor.setPropertyValue("name" ,22 );
fieldAccessor.setPropertyValue("age" ,"19" );
System.out.println(s22Bean2);
S22Bean2 s22Bean2 = new S22Bean2();
DataBinder dataBinder = new DataBinder(s22Bean2);
dataBinder.initDirectFieldAccess();
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add ("name" , 34 );
propertyValues.add ("age" , "12" );
dataBinder.bind(propertyValues);
System.out .println(s22Bean2);
S22Bean2 s22Bean2 = new S22Bean2 ();
DataBinder dataBinder = new ServletRequestDataBinder (s22Bean2);
dataBinder.initDirectFieldAccess();
MockHttpServletRequest request = new MockHttpServletRequest ();
request.setParameter("name" ,"13" );
request.setParameter("age" ,"13" );
request.setParameter("date" ,"2011/2/2" );
ServletRequestParameterPropertyValues propertyValues = new ServletRequestParameterPropertyValues (request);
dataBinder.bind(propertyValues);
System.out.println(s22Bean2);
基本的类型转换与数据绑定用法
SimpleTypeConverter
BeanWrapperImpl
DirectFieldAccessor
ServletRequestDataBinder
数据绑定工厂
点击查看代码
public static void main (String [] args) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ();
request.setParameter ("birthday" , "1999|01|02" );
request.setParameter ("address.name" , "西安" );
User target = new User ();
ApplicationConversionService service = new ApplicationConversionService ();
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer ();
initializer.setConversionService (service);
ServletRequestDataBinderFactory factory = new ServletRequestDataBinderFactory (null , initializer);
WebDataBinder dataBinder = factory.createBinder (new ServletWebRequest (request), target, "user" );
dataBinder.bind (new ServletRequestParameterPropertyValues (request));
System .out .println (target);
}
static class MyController {
@InitBinder
public void aaa (WebDataBinder dataBinder ) {
dataBinder.addCustomFormatter (new MyDateFormatter ("用 @InitBinder 方式扩展的" ));
}
}
public static class User {
@DateTimeFormat (pattern = "yyyy|MM|dd" )
private Date birthday;
private Address address;
public Address getAddress ( ) {
return address;
}
public void setAddress (Address address ) {
this .address = address;
}
public Date getBirthday ( ) {
return birthday;
}
public void setBirthday (Date birthday ) {
this .birthday = birthday;
}
@Override
public String toString ( ) {
return "User{" +
"birthday=" + birthday +
", address=" + address +
'}' ;
}
}
public static class Address {
private String name;
public String getName ( ) {
return name;
}
public void setName (String name ) {
this .name = name;
}
@Override
public String toString ( ) {
return "Address{" +
"name='" + name + '\'' +
'}' ;
}
}
}
ServletRequestDataBinderFactory 的用法和扩展点
可以解析控制器的 @InitBinder 标注方法作为扩展点,添加自定义转换器
可以通过 ConfigurableWebBindingInitializer 配置 ConversionService 作为扩展点,添加自定义转换器
同时加了 @InitBinder 和 ConversionService 的转换优先级
优先采用 @InitBinder 的转换器
其次使用 ConversionService 的转换器
使用默认转换器
特殊处理(例如有参构造)
获取泛型参数
点击查看代码
System.out .println(">>>>>>>>>>>>>>>>>>>>>>>" );
Type type = TeacherDao.class .getGenericSuperclass();
System.out .println(type);
if (type instanceof ParameterizedType parameterizedType) {
System.out .println(parameterizedType.getActualTypeArguments()[0 ]);
}
System.out .println(">>>>>>>>>>>>>>>>>>>>>>>" );
Class<?> t = GenericTypeResolver.resolveTypeArgument(TeacherDao.class , BaseDao.class );
System.out .println(t);
System.out .println(">>>>>>>>>>>>>>>>>>>>>>>" );
System.out .println(ResolvableType.forClass(TeacherDao.class ).getSuperType().getGeneric().resolve());
1. java api 获取泛型参数
2. spring api 获取泛型参数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现