目录
一、数据绑定
1.SpringMVC主框架将ServletRequest对象及目标方法的入参实例传递给WebDataBinderFactory实例,以创建 DataBinder 实例对象。
2. DataBinder 调用装配在SpringMVC 上下文中的 ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中 。
3. 调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果 BindingData 对象 。
4. Spring MVC 抽取BindingResult中的入参对象和校验错误对象,将它们赋给处理方法的响应入参。
源码分析:
在请求参数对象的setter方法设置断点:
定位到方法:
主要处理代码:
查看binder对象的重要属性:
三个重要的属性:conversionService:存放数据转换器。bindingResult:数据绑定的结果存放处。validators:数据校验器存放的地方。
其中conversionService存放了很多内建的常用数据转换器。
二、数据转换
ConversionService 是 Spring 类型转换体系的核心接口。
可以利用 ConversionServiceFactoryBean 在 Spring 的 IOC 容器中定义一个 ConversionService. Spring 将自动识别出 IOC 容器中的 ConversionService,并在 Bean 属性配置及 Spring MVC 处理方法入参绑定等场合使用它进行数据的转换 。
可通过 ConversionServiceFactoryBean 的 converters 属性 注册自定义的类型转换器。
1、编写自定义的转换器
转换器实现Converter接口。
ConversionServiceFactroyBean 中:
- – Converter<S,T>:将 S 类型对象转为 T 类型对象。
- – ConverterFactory:将相同系列多个 “同质” Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象,例如将 String 转换为 Number 及 Number 子类(Integer、Long、Double 等)对象)可使用该转换器工厂类。
- – GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换。
@Component
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String text) {
if (text == null) {
return null;
} else {
String value = text.trim();
if ("".equals(value)) {
return null;
} else {
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
return format.parse(text);
} catch (ParseException e) {
return null;
}
}
}
}
}
2、配置全局的日期转换:
<mvc:annotation-driven conversion-service=“conversionService”/> 会将自定义的 ConversionService 注册到Spring MVC 的上下文中
<!-- 配置 ConversionService -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="dateConverter"/>
</set>
</property>
</bean>
<!-- 在实际开发中通常都需配置 mvc:annotation-driven 标签 -->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
三、mvc:annotation-driven
<mvc:annotation-driven /> 会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean。
还将提供以下支持:
– 支持使用 ConversionService 实例对表单参数进行类型转换
– 支持使用 @NumberFormat annotation、@DateTimeFormat注解完成数据类型的格式化
– 支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证
– 支持使用 @RequestBody 和 @ResponseBody 注解
四、@InitBinder
@InitBinder 标识的方法,可以对 WebDataBinder 对 象进行初始化。WebDataBinder 是 DataBinder 的子类,用 于完成由表单字段到 JavaBean 属性的绑定
@InitBinder方法不能有返回值,它必须声明为void。
@InitBinder方法的参数通常是是 WebDataBinder
通常使用@InitBinder进行数据的格式化:其余Controller继承该BaseController则可以实现上述自定义类型转换器的相同效果。
public class BaseController {
/**
*
* @param binder
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
binder.registerCustomEditor(Date.class, new DateEditor());// 基于传统的PropertyEditor来实现日期类型的数据绑定
}
/**
* 基于传统的PropertyEditor来实现日期类型的数据绑定
*
* @author StarFall
*
*/
public class DateEditor extends PropertyEditorSupport {
/**
* 获取日期
*/
@Override
public String getAsText() {
Date value = (Date) getValue();
return value != null ? new SimpleDateFormat("yyyy-MM-dd").format(value) : "";
}
/**
* 设置日期
*/
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (text == null) {
setValue(null);
} else {
String value = text.trim();
if ("".equals(value)) {
setValue(null);
} else {
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
setValue(format.parse(text));
} catch (ParseException e) {
setValue(null);
}
}
}
}
}
}
五、数据格式化
Spring 在格式化模块中定义了一个实现ConversionService 接口的FormattingConversionService 实现类,该实现类扩展了 GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能。
FormattingConversionService 拥有一个FormattingConversionServiceFactroyBean 工厂类,后者用于在 Spring 上下文中构造前者
FormattingConversionServiceFactroyBean 内部已经注册了 :
– NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性使用 @NumberFormat 注解
– JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用 @DateTimeFormat 注解
装配了 FormattingConversionServiceFactroyBean 后,就可以在 Spring MVC 入参绑定及模型数据输出时使用注解驱动了。<mvc:annotation-driven/> 默认创建的ConversionService 实例即为FormattingConversionServiceFactroyBean。
1、@DateTimeFormat 注解
可对 java.util.Date、java.util.Calendar、java.long.Long 时间 类型进行标注
- pattern 属性:类型为字符串。指定解析/格式化字段数据的模式, 如:”yyyy-MM-dd hh:mm:ss”
- iso 属性:类型为 DateTimeFormat.ISO。指定解析/格式化字段数据 的ISO模式,包括四种:ISO.NONE(不使用) -- 默 认、ISO.DATE(yyyy-MM-dd) 、ISO.TIME(hh:mm:ss.SSSZ)、 ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ)
- style 属性:字符串类型。通过样式指定日期时间的格式,由两位字 符组成,第一位表示日期的格式,第二位表示时间的格式:S:短日 期/时间格式、M:中日期/时间格式、L:长日期/时间格式、F:完整 日期/时间格式、-:忽略日期或时间格式
例:
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;
2、@NumberFormat
可对类似数字类型的属性进行标 注,它拥有两个互斥的属性
- style:类型为 NumberFormat.Style。用于指定样式类 型,包括三种:Style.NUMBER(正常数字类型)、 Style.CURRENCY(货币类型)、 Style.PERCENT( 百分数类型)
- pattern:类型为 String,自定义样式, 如patter="#,###";
六、数据校验
1、JSR 303
JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架, 它已经包含在 JavaEE 6.0 中 .
JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证。
2、Spring MVC 数据校验
1、Spring 4.0 拥有自己独立的数据校验框架,同时支持 JSR303 标准的校验框架。
Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在 Spring MVC 中,可直接通过注解驱动的方式进行数据校验。
2、Spring 的 LocalValidatorFactroyBean 既实现了 Spring 的Validator 接口,也实现了 JSR 303 的 Validator 接口。只要在 Spring 容器中定义了一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的 Bean 中。
Spring 本身并没有提供 JSR303 的实现,所以必须将JSR303 的实现者的 jar 包放到类路径下。
3、<mvc:annotation-driven/> 会默认装配好一个LocalValidatorFactoryBean,通过在处理方法的入参上标注 @valid 注解即可让 Spring MVC 在完成数据绑定后执行数据校验的工作。
4、在已经标注了 JSR303 注解的表单/命令对象前标注一个@Valid,Spring MVC 框架在将请求参数绑定到该入参对象后,就会调用校验框架根据注解声明的校验规则实施校验
5、Spring MVC 是通过对处理方法签名的规约来保存校验结果的:前一个表单/命令对象的校验结果保存到随后的入参中,这个保存校验结果的入参必须是 BindingResult 或Errors 类型,这两个类都位于org.springframework.validation 包中。
3、使用方法
①. 使用 JSR 303 验证标准
②. 加入 hibernate validator 验证框架的 jar 包
③. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven />
④. 需要在 bean 的属性上添加对应的注解
@NotEmpty
private String lastName;
@Email
private String email;
⑤. 在目标方法 bean 类型的前面添加 @Valid 注解
@RequestMapping(value="/emp", method=RequestMethod.POST)
public String save(@Valid Employee employee, Errors result,
Map<String, Object> map){
System.out.println("save: " + employee);
if(result.getErrorCount() > 0){
System.out.println("出错了!");
for(FieldError error:result.getFieldErrors()){
System.out.println(error.getField() + ":" + error.getDefaultMessage());
}
//若验证出错, 则转向定制的页面
map.put("departments", departmentDao.getDepartments());
return "input";
}
employeeDao.save(employee);
return "redirect:/emps";
}
需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参
Errors 接口提供了获取错误信息的方法,如 getErrorCount() 或 getFieldErrors(String field) ,BindingResult 扩展了 Errors 接口。
4、在目标方法中获取校验结果
在表单/命令对象类的属性中标注校验注解,在处理方法对 应的入参前添加 @Valid,Spring MVC 就会实施校验并将校 验结果保存在被校验入参对象之后的 BindingResult 或 Errors 入参中。 •
常用方法:
- FieldError getFieldError(String field)
- List getFieldErrors()
- Object getFieldValue(String field)
- Int getErrorCount()