数据类型转换、数据格式化与数据校验的具体实现代码下载地址:http://download.csdn.net/download/bingbeichen/9796699。
SpringMVC通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。其中,数据绑定的核心部件是DataBinder,运行机制如下:
数据绑定的具体流程说明如下:
// ModelAttributeMethodProcessor的resolveArgument()方法的核心代码:
WebDataBinder binder = binderFactory.createBinder(request, attribute, name);
if (binder.getTarget() != null) {
bindRequestParameters(binder, request); //绑定请求数据到入参中
validateIfApplicable(binder, parameter); //校验入参中数据的合法性
if (binder.getBindingResult().hasErrors()) {
if (isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
}
SpringMVC上下文中内建了许多数据类型转换器,可完成大多数Java类型的换工作,具体可通过调试模式查看binder的conversionService属性值。
明确需求:
// 将表单输入的name-email-gender-department.id字符串转换为Employee对象
@RequestMapping("/testEmployeeConverter")
public String testEmployeeConverter(Employee employee) {
System.out.println(employee);
return "redirect:/emps";
}
第一步:自定义实现Converter接口的数据类型转换器类,并添加到Spring的IoC容器中;
package com.qiaobc.springmvc.converter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import com.qiaobc.springmvc.domain.Department;
import com.qiaobc.springmvc.domain.Employee;
// 三种类型的数据转换器接口:Converter、ConverterFactory、GenericConverter
@Component
public class EmployeeConverter implements Converter<String, Employee>{
@Override
public Employee convert(String source) {
if(source != null) {
String[] strs = source.split("-");
if(strs != null && strs.length == 4) {
String name = strs[0];
String email = strs[1];
String gender = strs[2];
Department department = new Department();
department.setDeptId(Integer.parseInt(strs[3]));
return new Employee(null, name, email, gender, department);
}
}
return null;
}
}
第二步:在SpringMVC的配置文件中,通过ConversionServiceFactoryBean的converters属性注册自定义的类型转换器;
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="employeeConverter"/>
set>
property>
bean>
第三步:通过mvc:annotation-driven标签的conversion-service属性,将ConversionServiceFactoryBean注册到SpringMVC的上下文中。
<mvc:annotation-driven conversion-service="conversionService">mvc:annotation-driven>
会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter与ExceptionHandlerExceptionResolver三个bean,其还将提供如下支持:
由@InitBinder注解标识的方法,可以对WebDataBinder对象进行初始化;WebDataBinder是DataBinder的子类,用于完成由表单字段到JavaBean属性的绑定。注意@InitBinder方法不能有返回值,其入参通常是WebDataBinder对象。
/**
* 在进行数据绑定时,不自动绑定对象中的name属性
* 注意:其对自定义类型转换器并不起作用
* @param binder
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields("name");
}
主要作用:用于在Spring上下文中构造FormattingConversionService。
其中,FormattingConversionServiceFactroyBean工厂类的内部已经注册:
@DateTimeFormat注解可对java.util.Date、java.util.Calendar和java.long.Long时间
类型的属性进行标注,其具有如下属性:
@NumberFormat注解可对类似数字类型的属性进行标注,其具有两个互斥的属性:
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;
@NumberFormat(pattern="###,###,###.##")
private float salary;
JSR 303 是Java为Bean数据合法性校验提供的标准框架,其已经包含在JavaEE 6.0中;JSR 303 通过在Bean属性上标注类似于@NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。
JSR 303 支持的校验注解如下:
注解 | 功能说明 |
---|---|
@Null | 被注释的元素必须为null |
@NotNull | 被注释的元素必须不为null |
@AssertTrue | 被注释的元素必须为true |
@AssertFalse | 被注释的元素必须为false |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于或等于指定的最小值 |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于或等于指定的最大值 |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于或等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于或等于指定的最大值 |
@Size(max, min) | 被注释的元素的大小必须在指定的范围内 |
@Digits(integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,还支持一下扩展注解:
注解 | 功能说明 |
---|---|
被注释的元素必须是电子邮箱地址 | |
@Length | 被注释的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注释的字符串必须非空 |
@Range | 被注释的元素必须在合适的范围内 |
① 关于所需要的jar包
Spring4.0拥有独立的数据校验框架,同时支持 JSR 303 标准的校验框架;但其本身并没有提供 JSR 303 的实现,故必须将 JSR 303 的实现者的jar包放到类路径下。
② 关于LocalValidatorFactoryBean工厂类
该工厂类既实现了Spring的Validator接口,也实现了 JSR 303 的Validator接口;故需要在 Spring 容器中定义LocalValidatorFactoryBean,即可将其注入到需要数据校验的Bean中。
③ 关于@Valid注解
会默认装配LocalValidatorFactoryBean,通过在处理方法的入参上标注@Valid注解即可让SpringMVC在进行数据绑定时,同时调用校验框架完成数据校验工作。
④ 关于校验结果
前一个表单/命令对象的校验结果保存到随后处理方法的入参中,该入参必须是BindingResult或Errors类型;且需注意,需校验的Bean对象和其绑定结果对象或错误对象是成对出现的,其之间不允许声明其他的入参。
第一步:添加Hibernate Validator验证框架所依赖的jar包,具体如下图所示:
第二步:在SpringMVC配置文件中添加mvc:annotation-driven标签;
第三步:在需要校验的JavaBean属性上添加相应的校验注解,以Employee为例:
public class Employee {
@NotNull
private String name;
@Email
private String email;
@Past
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;
// ……
}
第四步:在处理器目标方法的Bean类型的入参前添加@Valid注解,并添加保存校验结果的对象:
@RequestMapping(value="/emp", method=RequestMethod.POST)
public String save(@Valid Employee employee, BindingResult result, Map map) {
System.out.println(employee);
if(result.getErrorCount() > 0) {
for(FieldError error : result.getFieldErrors()) {
System.out.println(error.getField() + " : " + error.getDefaultMessage());
}
// 指定校验错误时所转向的定制页面
map.put("departments", departmentDao.getDepartments());
return "emp-edit";
}
employeeDao.save(employee);
return "redirect:/emps";
}
SpringMVC还会将所有校验结果保存到隐含模型中,该模型中的所有数据最终将通过HttpServletRequest的属性列表暴露给JSP视图对象,故在JSP页面上可以获取错误信息。
<form:form action="${pageContext.request.contextPath }/emp" method="post" modelAttribute="employee">
<form:errors path="*">form:errors><br><br>
Name:<form:input path="name"/>
<form:errors path="name">form:errors>
<br><br>
Email:<form:input path="email"/>
<form:errors path="email">form:errors>
<br><br>
Birthday:<form:input path="birth"/>
<form:errors path="birth">form:errors>
<br><br>
<input type="submit" name="submit">
form:form>
当某属性校验失败后,SpringMVC校验框架会为该属性生成4个消息代码,其以校验注解类名为前缀,结合modelAttribute、属性名及属性类型名;如NotNull.employee.name、NotNull.name、NotNull.java.lang.String和NotNull。
错误代码前缀除了校验注解类名外,还有如下几种:
错误代码前缀 | 具体说明 |
---|---|
required | 必要的参数不存在;如@RequiredParam(“name”)标注入参,但该参数不存在时发生的错误 |
typeMismatch | 在数据绑定时,发生数据类型转换或格式化错误 |
methodInvocation | SpringMVC在调用处理方法时发生错误 |
具体实现步骤:
第一步:创建国际化资源文件i18n.properties,文件内容如下所示:
NotNull.employee.name=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
Email.employee.email=\u7535\u5B50\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
Past.employee.birth=\u51FA\u751F\u65E5\u671F\u4E0D\u80FD\u662F\u5C06\u6765\u65F6\u95F4
第二步:在SpringMVC配置文件中注册国际化资源文件,具体如下:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n">property>
bean>
说明:当使用SpringMVC标签显示错误消息时,SpringMVC先查看WEB上下文是否装配对应的国际化消息,若有则显示国际化消息,否则显示默认的错误消息。