1.底层的转换接口
Spring提供的接口
- Printer: 其他类型转为String
- Parser: String转为其他类型
- Formatter: Printer + Parser
- Converter: 类型S转为类型T
- Printer, Parser, Converter通过适配转换为GenericConverter, 放入Converters 集合中
Jdk提供的接口
- PropertyEditor: 把String和其他类型的转换
- PropertyEditorRegistry: 可以注册多个PropertyEditor对象
- 与前面一套接口可以通过FormatterPropertyEditorAdapter进行适配
2.高层的转换接口
- 它们都实现了 TypeConverter 这个高层转换接口,在转换时,会用到 TypeConverter Delegate 委派ConversionService 与 PropertyEditorRegistry 真正执行转换(Facade 门面模式)
- 首先看是否有自定义转换器, @InitBinder 添加的即属于这种 (用了适配器模式把 Formatter 转为需要的 PropertyEditor)
- 再看有没有 ConversionService 转换
- 再利用默认的 PropertyEditor 转换
- 最后有一些特殊处理
- SimpleTypeConverter 仅做类型转换
- BeanWrapperImpl 为 bean 的属性赋值,当需要时做类型转换,走 Property
- DirectFieldAccessor 为 bean 的属性赋值,当需要时做类型转换,走 Field
- ServletRequestDataBinder 为 bean 的属性执行绑定,当需要时做类型转换,根据 directFieldAccess 选择走 Property 还是 Field,具备校验与获取校验结果功能
3.演示高级接口类型转化
- TestSimpleConverter: SimpleTypeConverter
public class TestSimpleConverter {
public static void main(String[] args) {
// 类型转换
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
Integer integer = typeConverter.convertIfNecessary("13", int.class);
Date date = typeConverter.convertIfNecessary("1111/11/11", Date.class);
System.out.println(date);
System.out.println(integer);
}
}
- TestBeanWrapper: BeanWrapper
BeanWrapperImpl 为 bean 的属性赋值,当需要时做类型转换,走 Property, 利用反射
public class TestBeanWrapper {
public static void main(String[] args) {
// 反射
MyBean myBean = new MyBean();
BeanWrapperImpl wrapper = new BeanWrapperImpl(myBean);
wrapper.setPropertyValue("a", "10");
wrapper.setPropertyValue("b", "hello");
wrapper.setPropertyValue("c", "1111/11/11");
System.out.println(myBean);
}
@Data
@ToString
static class MyBean{
private int a;
private String b;
private Date c;
}
}
- TestDataBinder: DataBinder
默认走set方法
public class TestDataBinder {
public static void main(String[] args){
// 默认走set方法
MyBean bean = new MyBean();
DataBinder dataBinder = new DataBinder(bean);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValue("a", "1");
pvs.addPropertyValue("b", "a");
pvs.addPropertyValue("c", "1111/11/11");
dataBinder.bind(pvs);
System.out.println(bean);
}
@Data
static class MyBean{
private int a;
private String b;
private Date c;
}
}
- TestServletDataBinder: Web环境下的DataBinder
public class TestServletDataBinder {
public static void main(String[] args) {
// web 条件下的数据绑定
MyBean bean = new MyBean();
ServletRequestDataBinder dataBinder = new ServletRequestDataBinder(bean);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("a", "1");
request.setParameter("b", "A");
request.setParameter("c", "1111/11/11");
dataBinder.bind(new ServletRequestParameterPropertyValues(request));
System.out.println(bean);
}
@Data
static class MyBean{
private int a;
private String b;
private Date c;
}
}
- TestFileAccessor: DirectFieldAccessor 为 bean 的属性赋值,当需要时做类型转换,走 Field
public class TestFileAccessor {
public static void main(String[] args) {
// 反射, 走的不是get/set方法而是成员变量
MyBean myBean = new MyBean();
DirectFieldAccessor accessor = new DirectFieldAccessor(myBean);
accessor.setPropertyValue("a", "10");
accessor.setPropertyValue("b", "hello");
accessor.setPropertyValue("c", "1111/11/11");
System.out.println(myBean);
}
@ToString
static class MyBean{
private int a;
private String b;
private Date c;
}
}
4.Spring中是如何操作泛型参数的
框架代码中, 父类有泛型的时候, 如何获取到泛型参数的类型的
public class Student {
}
public class BaseDao<T> {
}
public class StudentDao extends BaseDao<Student> {
}
- TestGenericType
public class TestGenericType {
public static void main(String[] args){
// 如何获取继承参数
// jdk
Type type = StudentDao.class.getGenericSuperclass();
System.out.println(type);
ParameterizedType parameterizedType = (ParameterizedType)type;
System.out.println(parameterizedType.getActualTypeArguments()[0]);
// spring
Class<?> aClass = GenericTypeResolver.resolveTypeArgument(StudentDao.class, BaseDao.class);
System.out.println(aClass);
}
}
5.ConversionService扩展和@InitBinder扩展
转换类型的功能扩展: 比如日期的形式可以改为 “xxxx|xx|xx” 本来是 “xxxx/xx/xx”
- @InitBinder
- ConversionService
MyDataFormatter
public class MyDataFormatter implements Formatter<Date> {
@Override
public Date parse(String text, Locale locale) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy|MM|dd");
return sdf.parse(text);
}
@Override
public String print(Date object, Locale locale) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy|MM|dd");
return sdf.format(object);
}
}
InitBinder
public class TestServletDataBinderFactory {
public static void main(String[] args) throws Exception{
// 1.工厂, 无需转换
// 2.@InitBinder 转换
// 3.ConversionService 转换 Formatter
// 4.默认的ConversionService
User user = new User();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("date", "1111|11|11");
request.setParameter("address.name", "1");
// @InitBinder
InvocableHandlerMethod method = new InvocableHandlerMethod(new Controller(), Controller.class.getMethod("aaa", WebDataBinder.class));
ArrayList<InvocableHandlerMethod> list = new ArrayList<>();
list.add(method);
ServletRequestDataBinderFactory factory = new ServletRequestDataBinderFactory(list, null);
WebDataBinder webDataBinder = factory.createBinder(new ServletWebRequest(request), user, "user");
webDataBinder.bind(new ServletRequestParameterPropertyValues(request));
System.out.println(user);
}
static class Controller{
@InitBinder
public void aaa(WebDataBinder webDataBinder){
webDataBinder.addCustomFormatter(new MyDataFormatter());
}
}
@Data
public static class User{
@DateTimeFormat(pattern = "yyyy||MM|dd")
private Date date;
private Address address;
}
@Data
public static class Address{
private String name;
}
}
ConversionService
public class TestServletDataBinderFactory {
public static void main(String[] args) throws Exception{
// 1.工厂, 无需转换
// 2.@InitBinder 转换
// 3.ConversionService 转换 Formatter
// 4.默认的ConversionService
User user = new User();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("date", "1111|11|11");
request.setParameter("address.name", "1");
// ConversionService
FormattingConversionService service = new FormattingConversionService();
service.addFormatter(new MyDataFormatter());
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(service);
ServletRequestDataBinderFactory factory = new ServletRequestDataBinderFactory(null, initializer);
WebDataBinder webDataBinder = factory.createBinder(new ServletWebRequest(request), user, "user");
webDataBinder.bind(new ServletRequestParameterPropertyValues(request));
System.out.println(user);
}
static class Controller{
@InitBinder
public void aaa(WebDataBinder webDataBinder){
webDataBinder.addCustomFormatter(new MyDataFormatter());
}
}
@Data
public static class User{
@DateTimeFormat(pattern = "yyyy||MM|dd")
private Date date;
private Address address;
}
@Data
public static class Address{
private String name;
}
}