一、问题分析
在之前的增删改查中,数据都是通过表单传向方法然后转化成相应的数据类型!那么如果我们在java bean中再添加一个日期属性birth时,就会有三个问题:
1.如何将表单中的字符串格式转向日期格式:数据类型转换
2.表单中输入的字符串格式应该是怎么样的:数据类型格式化
3.这是个生日属性,既然是生日属性就应该是当前日期的前面的时间,不能填未来的时间,如何检验:数据校验
二、数据绑定流程
如尚硅谷视频所说:
1.SpringMVC会把request和目标方法的入参传递给WebDataBinderFactory实例,以创建DataBinder实例对象
2.DataBinder调用SpringMVC上下文中的ConversionService组件将request中的数据转换为相应的类型,然后填充到目标方法的入参中。(类型转换和格式化往往是一起的!)
3.调用Validator对已经绑定了的请求消息的入参进行合法性的校验,并将最终生成数据绑定结果BindingData对象!
4.SpringMVC抽取BindingResult中的校验错误信息和入参对象,将他们赋给处理方法中相应的入参!
至此,SpringMVC就将我们上面的三个问题都解决了!
三、源码分析
我们一直在写的那个程序学生类有一个数据类型为整型类型的,即我们可以查看这个由字符串转整型的过程:
因为在最终SpringMVC会调用Student类中的setAge方法,所以我们在这里打个断点:
调试,新增学生信息,填写表单,点击添加,停在这个setter语句!我们在函数栈中翻到这个点击:
可以看出来这个类完成了表单中数据绑定校验等操作,第一行调用WebDataBinderFactory这个工厂类创建了一个WebDataBinder对象,然后第三行进行的是数据绑定,第四行完成校验。
再看Variables,点击属性列表中的Binder属性中的:
这个ConversionService是个DefaultFormattingConversionService对象,其可以完成数据的绑定和格式化工作!
这个组件中有个对象属性里面包含一个有97个转换器的对象的LinkHashMap(age中用的转换器是StringToNumberconverter),SpringMVC就是在这里找到相应的对象并进行数据性转换的!
出来往后翻可以看到一个size为0的validator。我们现在还没有加任何校验!
如果加了校验的话,校验过程中发生错误,就会将错误信息放进bindingResult中。
这就是一个数据绑定的流程!
四、自定义一个类型转换器
SpringMVC内建了很多类型转换器,可以完成大部分的转换工作!
但如果我们遇到特殊情况,自定义转换器还是可以了解下的!
视图层
在input.jsp上加上表单:
<br><br><br><br>
<!--the basic format is "name-gender-age-school.id", such as "Tom-female/male-22-4"-->
<h3>字符串添加学生信息</h3>
<form action="/testDIYConversionService" method="post">
信息:<input type="text" name="student"/>
<input type="submit" value="添加信息">
</form>
控制层
新建一个TestConversionServiceHandler类:
@Controller
public class TestConversionServiceHandler {
@Autowired
private StudentDao studentDao;
@RequestMapping(value = "/testDIYConversionService", method = RequestMethod.POST)
public String testDIYConversionService(Student student){
System.out.println(student);
studentDao.saveStudent(student);
return "redirect:stus";
}
}
如果只是这样的话,字符串类型和Student类型肯定会报错。
我们现在只需实现一个Converter<S,T>接口将String信息转化为一个student对象:
Converter
public class StudentConverter implements Converter<String, Student> {
@Autowired
private SchoolDao schoolDao;
@Override
public Student convert(String s) {
Student student = new Student();
String parameters[] = s.split("-");
if (parameters.length == 4) {
String name = parameters[0];
boolean gender = "female".equals(parameters[1]);
int age = Integer.parseInt(parameters[2]);
int schoolId = Integer.parseInt(parameters[3]);
student = new Student(0, name, gender, age, schoolDao.getSchoolById(schoolId));
System.out.println(s + "--convert--" + student);
}
return student;
}
}
springmvc.xml文件的配置
<!--config ConverterService bean-->
<bean id="studentConverter" class="cn.jxufe.Conversion.StudentConverter"> </bean>
<!--config ConversionServiceFactoryBean-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="studentConverter"/>
</set>
</property>
</bean>
可以看出来这个converters是个set对象。
然后我们在之前写的mvc:annotation-driven配置使得其能自动注册ConversionServiceFactoryBean对象。
<mvc:annotation-driven conversion-service="conversionService"> </mvc:annotation-driven>
注意: 这个配置写一个就行了,之前因为重定向要用到,获取静态文件也要用到,所以我写了两个,然后写自定义转换器时只在一个mvc:annotation-driven配置了conversion-service,然后运行就一直没有用,String不转换为student,一直报错!
mvc:annotation-driven的功能很多,教学视频的进度还没能覆盖其全部作用(比如其对于json的作用),故后面再做详细总结!
把一个删掉运行就成功了!