SpringMVC 学习笔记(八)- 数据转换 & 数据校验 & 数据格式化

1. 数据绑定流程

  1. Spring MVC 主框架将ServletRequest 对象目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象
  2. DataBinder 调用装配在 Spring MVC 上下文中的 ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中
  3. 调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果 BindingData 对象
  4. Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

Spring MVC 通过反射机制对目标方法进行解析,将请求绑定到处理方法的入参中。数据绑定的核心部件是 DataBinder,运行机制如下:
SpringMVC 学习笔记(八)- 数据转换 & 数据校验 & 数据格式化

2. 自定义类型转换器(了解)

注意:本次实例在 CRUD 代码中加入

1. 在视图 input.jsp 中加入

<form action="testConversionServiceConverer" method="POST">
		<!-- lastname-email-gender-department.id 例如: [email protected] -->
		Employee: <input type="text" name="employee"/>
		<input type="submit" value="Submit"/>
	</form>
	<br><br>

2. 在 src 下创建处理器类 SpringMVCTest

@Controller
public class SpringMVCTest {
 
	@Autowired
	private EmployeeDao employeeDao;
	
@RequestMapping("/testConversionServiceConverer")
	public String testConverter(@RequestParam("employee") Employee employee){
		System.out.println("save: " + employee);
		employeeDao.save(employee);
		return "redirect:/emps";
	}
}

3. 在 src 下创建自定义转换器 EmployeeConverter

package www.xq.springmvc.converters;

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import www.xq.springmvc.crud.entities.Department;
import www.xq.springmvc.crud.entities.Employee;

@Component
public class EmployeeConverter implements Converter<String, Employee> {

	@Override
	public Employee convert(String source) {
		if(source != null){
			String [] vals = source.split("-");
			//[email protected]
			if(vals != null && vals.length == 4){
				String lastName = vals[0];
				String email = vals[1];
				Integer gender = Integer.parseInt(vals[2]);
				Department department = new Department();
				department.setId(Integer.parseInt(vals[3]));
				
				Employee employee = new Employee(null, lastName, email, gender, department);
				System.out.println(source + "--convert--" + employee);
				return employee;
			}
		}
		return null;
	}

}

4. 在 springMVC 的配置文件中配置转换器

<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>	
	
	<!-- 配置 ConversionService -->
	<bean id="conversionService"
		class="org.springframework.context.support.ConversionServiceFactoryBean">
		<property name="converters">
			<set>
				<ref bean="employeeConverter"/>
			</set>
		</property>	
	</bean>

5. 运行结果

前台

SpringMVC 学习笔记(八)- 数据转换 & 数据校验 & 数据格式化
SpringMVC 学习笔记(八)- 数据转换 & 数据校验 & 数据格式化

后台

[email protected] [id=null, lastName=GG, [email protected], gender=0, department=Department [id=105, departmentName=null], birth=null, salary=null]
save: Employee [id=null, lastName=GG, [email protected], gender=0, department=Department [id=105, departmentName=null], birth=null, salary=null]

3. 关于 mvc:annotation-driven

  • mvc:annotation-driven/ 会自动注册 RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver 三个 bean。
  • 还将提供以下支持:
    • 支持使用 ConversionService 实例对表单参数进行类型转换
    • 支持使用 @NumberFormat annotation@DateTimeFormat 注解完成数据类型的格式化
    • 支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证
    • 支持使用 @RequestBody@ResponseBody 注解

4. @InitBinder 注解

1. 简介

  • @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定
  • @InitBinder 方法不能有返回值,它必须声明为 void。
  • @InitBinder 方法的参数通常是 WebDataBinder

2. 举例

1. 处理器类 EmployeeHandler 加入方法

@InitBinder
	public void initBinder(WebDataBinder binder){
	    //不能设置lastName的值
		binder.setDisallowedFields("lastName");
	}

2. 测试添加

运行结果

SpringMVC 学习笔记(八)- 数据转换 & 数据校验 & 数据格式化

5. 数据格式化

1. 简介

  • 对属性对象的输入/输出进行格式化,从其本质上讲依然属于“类型转换的范畴”
  • Spring 在格式化模块中定义了一个实现 ConversionService 接口的 FormattingConversionService 实现类,该实现类扩展了 GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能,具体实现如下图:
  • FormattingConversionService 拥有一个 FormattingConversionServiceFactoryBean 工厂类,后者用于在 Sring 上下文中构造前者(具体例子如下图)
    SpringMVC 学习笔记(八)- 数据转换 & 数据校验 & 数据格式化

2. 举例(只需在对应实例类的相关属性上加上注解即可)

1. 首先应该在 springMVC 配置文件中装配 FormattingConversionServiceFactoryBean 后,就可以在 SpringMVC 入参绑定及模型数据输出时使用注解驱动了。

<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>	
	
	<!-- 配置 ConversionService -->
	<bean id="conversionService"
		class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
		<property name="converters">
			<set>
				<ref bean="employeeConverter"/>
			</set>
		</property>	
	</bean>

2. 具体

日期格式化
    //示例输入:1999-09-09
	@DateTimeFormat(pattern="yyyy-MM-dd")
	private Date birth;
数值格式化
    //示例输入:1,525,555.4
	@NumberFormat(pattern="#,###,###.#")
	private Float salary;

3. 数据格式化出错设置

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";
		}

6. JSR 303 数据校验

1. 如何校验 ? 注解 ?

1. 使用 JSR 303 验证标准
2. 加入 hibernate validator 验证框架的 jar 包
3. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven />
4. 需要在 bean 的属性上添加对应的注解
5. 在目标方法 bean 类型的前面添加 @Valid 注解

注意:假如出现 NoSuchMethodError 异常,那么可能是 el jar 包冲突,具体将 hibernate validator 中有关 el jar 包替换Tomcat中java目录下的 el jar包

2. 具体如下

1. 请求处理器类 EmployeeHandler save 方法加工

@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";
	}

2. bean 类加入对应注解

具体操作
@NotEmpty
private String lastName;

@Email
private String email;

@Past
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;
总结
  • JSR 303
    • JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 中
    • JSR 303 通过在 Bean 属性上标注类似 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证
  • Hibernate Validator 扩展注解
    • Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解
3. 视图 input.jsp 加入错误标签以显示错误信息
<!-- 显示全部错误 -->
<form:errors path="*"></form:errors>
<!-- 显示 name 错误 -->	
<form:errors path="lastName"></form:errors>
<!-- 显示 email 错误 -->	
<form:errors path="email"></form:errors>
<!-- 显示 日期 错误 -->		
<form:errors path="birth"></form:errors>

4. 运行结果

前台

SpringMVC 学习笔记(八)- 数据转换 & 数据校验 & 数据格式化

后台
save: Employee [id=null, lastName=, [email protected], gender=0, department=Department [id=101, departmentName=null], birth=Fri Nov 22 00:00:00 CST 2019, salary=1111111.0]
出错了!
birth:需要是一个过去的事件
email:不是一个合法的电子邮件地址
lastName:不能为空