SpringMVC 学习笔记(六) 数据绑定和JSR校验

① Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象

② DataBinder 调用装配在 Spring MVC 上下文中的ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中

③ 调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果BindingData 对象

④ Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

1.1. 运行机制

Spring MVC 通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是DataBinder,运行机制如下:

1.2. 源码分析

1.3. ConversionService 类型转换器

① ConversionService 是 Spring 类型转换体系的核心接口。

②可以利用 ConversionServiceFactoryBean 在Spring的IOC容器中定义一个 ConversionService. Spring 将自动识别出IOC 容器中的 ConversionService,并在 Bean 属性配置及Spring MVC 处理方法入参绑定等场合使用它进行数据的转换

③ 可通过 ConversionServiceFactoryBean 的 converters 属性注册自定义的类型转换器

1.4. 自定义类型转换器

Spring 定义了 3 种类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到

ConversionServiceFactroyBean 中:

– Converter<S,T>:将 S 类型对象转为 T 类型对象

– ConverterFactory:将相同系列多个 “同质” Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将 String 转换为 Number 及 Number 子类(Integer、Long、Double 等)对象)可使用该转换器工厂类

– GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换

现在自己实现一个类型转换器将字符串转换成员工

spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

	<context:component-scan base-package="com.ibigsea.springmvc"/>

	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/"/>
		<property name="suffix" value=".jsp"/>
	</bean>

	<mvc:default-servlet-handler/>

	<mvc:annotation-driven conversion-service="converterService"/>

	<bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
		<property name="converters">
			<list>
				<bean class="com.ibigsea.springmvc.conversion.DepartmentConversion"></bean>
			</list>
		</property>
	</bean>
</beans>

DepartmentConversion.java

package com.ibigsea.springmvc.conversion;

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

import com.ibigsea.springmvc.model.Department;

public class DepartmentConversion implements Converter<String, Department>{

	/**
	 * 传入的数据格式
	 * xx-xx
	 */
	@Override
	public Department convert(String data) {
		if (data == null) {
			return null;
		}
		String [] args = data.split("-");
		if (args!=null && args.length != 2) {
			return null;
		}
		return new Department(Integer.parseInt(args[0]), args[1]);
	}

}

ConversionController.java

package com.ibigsea.springmvc.rest;

import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.ibigsea.springmvc.model.Employee;

@Controller
public class ConversionController {

	@RequestMapping("/conversion")
	public String toConversionData(){
		return "conversionData";
	}

	@RequestMapping("/addemp")
	public String addEmp(Employee emp,Map<String, Object> map){
		map.put("emp", emp);
		return "conversionData";
	}

}

conversionData.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<form action="addemp" method="post">
<input type="hidden" name="id" ><br/><br/>
name : <input type="text" name="name" ><br/><br/>
email : <input type="text" name="email" ><br/><br/>
sex :<input type="radio" name="sex" value="0" >男    
<input type="radio" name="sex" value="1" >女<br/><br/>
department : <input type="text" name="department" ><br><br>
<input type="submit" value="提交">
</form>

${emp}

</body>
</html>

1.5. 数据格式化

对属性对象的输入/输出进行格式化,从其本质上讲依然属于 “类型转换” 的范畴。

① Spring 在格式化模块中定义了一个实现ConversionService 接口的

FormattingConversionService 实现类,该实现类扩展了 GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能

② FormattingConversionService 拥有一个 工厂类,后者用于在 Spring 上下文中构造前者

FormattingConversionServiceFactroyBean 内部已经注册了 :

– NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性使用 @NumberFormat 注解

–JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用 @DateTimeFormat 注解

? 装配了 FormattingConversionServiceFactroyBean 后,就可以在 Spring MVC 入参绑定及模型数据输出时使用注解驱动了。<mvc:annotation-driven/> 默认创建的ConversionService 实例即为FormattingConversionServiceFactroyBean

如果自定义了类型转换器 只用将Class配置为FormattingConversionServiceFactroyBean即可

spring-mvc.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

	<context:component-scan base-package="com.ibigsea.springmvc"/>

	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/"/>
		<property name="suffix" value=".jsp"/>
	</bean>

	<mvc:default-servlet-handler/>

	<mvc:annotation-driven conversion-service="converterService"/>

	<bean id="converterService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
		<property name="converters">
			<list>
				<bean class="com.ibigsea.springmvc.conversion.DepartmentConversion"></bean>
			</list>
		</property>
	</bean>
</beans>

1.5.1. @DateTimeFormat

@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:完整日期/时间格式、-:忽略日期或时间格式

1.5.2. @NumberFormat

@NumberFormat 可对类似数字类型的属性进行标

注,它拥有两个互斥的属性:

– style:类型为 NumberFormat.Style。用于指定样式类型,包括三种:Style.NUMBER(正常数字类型)、Style.CURRENCY(货币类型)、 Style.PERCENT(百分数类型)

– pattern:类型为 String,自定义样式,如patter="#,###";

1.5.3. FormattingConversionService转换

1.6. JSR 303 校验

JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 中 .

? JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对 Bean进行验证

1.6.1. Hibernate Validator 扩展注解

在pom.xml 中加入

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.0.2.Final</version>
		</dependency>

Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解

1.6.2. SpringMVC 数据校验

Spring 4 拥有自己独立的数据校验框架,同时支持 JSR303 标准的校验框架。

① Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在 Spring MVC 中,可直接通过注解驱动的方式进行数据校验

② Spring 的 LocalValidatorFactroyBean 既实现了 Spring 的Validator 接口,也实现了 JSR 303的Validator 接口。只要在 Spring 容器中定义了一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的 Bean 中。

③ Spring 本身并没有提供 JSR303 的实现,所以必须将JSR303 的实现者的 jar 包放到类路径下。

<mvc:annotation-driven/> 会默认装配好一个LocalValidatorFactoryBean,通过在处理方法的入参上标注 @valid 注解即可让 Spring MVC 在完成数据绑定后执行数据校验的工作

在已经标注了 JSR303 注解的表单/命令对象前标注一个@Valid,Spring MVC 框架在将请求参数绑定到该入参对象后,就会调用校验框架根据注解声明的校验规则实施校验

Spring MVC 是通过对处理方法签名的规约来保存校验结果的:前一个表单/命令对象的校验结果保存到随后的入参中,这个保存校验结果的入参必须是 BindingResult 或Errors 类型,这两个类都位于org.springframework.validation 包中

时间: 2024-10-11 07:43:07

SpringMVC 学习笔记(六) 数据绑定和JSR校验的相关文章

springMVC学习笔记汇总(持续更新)

SpringMVC 学习笔记(一) Hello World SpringMVC 学习笔记(二) @RequestMapping.@PathVariable等注解 SpringMVC 学习笔记(三) 使用ServletAPI 和 实体 做为参数 SpringMVC 学习笔记(四) 处理模型数据 SpringMVC 学习笔记(五) 基于RESTful的CRUD SpringMVC 学习笔记(六) 数据绑定和JSR校验 SpringMVC 学习笔记(七) JSON返回:HttpMessageConve

java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessController的checkPerssiom方法,访问控制器AccessController的栈检查机制又遍历整个 PerssiomCollection来判断具体拥有什么权限一旦发现栈中一个权限不允许的时候抛出异常否则简单的返回,这个过程实际上比我的描述要复杂 得多,这里我只是简单的一句带过,因为这

springmvc学习笔记(14)-springmvc校验

springmvc学习笔记(14)-springmvc校验 springmvc学习笔记14-springmvc校验 校验理解 springmvc校验需求 环境准备 配置校验器 在pojo中添加校验规则 捕获和显示校验错误信息 分组校验 本文主要介绍springmvc校验,包括环境准备,校验器配置,pojo张添加校验规则,捕获和显示检验错误信息以及分组校验简单示例. 校验理解 项目中,通常使用较多是前端的校验,比如页面中js校验.对于安全要求较高点建议在服务端进行校验. 服务端校验: 控制层con

SpringMVC学习笔记(二): 日常使用功能

前提: 1.web.xml 和spring-mvc核心配置如:SpringMVC学习笔记(一): 基础知识中注解实现. 2.类的@RequestMapping(value="/annotationController") 3.spring-mvc 推荐使用注解实现. 一.数据的接收 (一)URL参数数据的接收 1.使用 HttpServletRequest 获取参数 <span style="font-size:18px;"><span style

史上最全的SpringMVC学习笔记

SpringMVC学习笔记---- 一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于SpringMVC的配置 <!--configure the setting of springmvcDispatcherServlet and configure the mapping--> <servlet> <servlet-name>springmvc</servlet

springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定

springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定 springmvc学习笔记13-springmvc注解开发之集合类型參数绑定 数组绑定 需求 表现层实现 list绑定 需求 表现层实现 map绑定 本文主要介绍注解开发的集合类型參数绑定,包含数组绑定,list绑定以及map绑定 数组绑定 需求 商品批量删除,用户在页面选择多个商品.批量删除. 表现层实现 关键:将页面选择(多选)的商品id,传到controller方法的形參,方法形參使用数组接收页面请求的多个商

springmvc学习笔记(20)-拦截器

springmvc学习笔记(20)-拦截器 springmvc学习笔记20-拦截器 拦截定义 拦截器配置 针对HandlerMapping配置 类似全局的拦截器 拦截测试 拦截器应用实现登陆认证 需求 登陆controller方法 登陆认证拦截实现 本文主要介绍springmvc中的拦截器,包括拦截器定义和的配置,然后演示了一个链式拦截的测试示例,最后通过一个登录认证的例子展示了拦截器的应用 拦截定义 定义拦截器,实现HandlerInterceptor接口.接口中提供三个方法. public

springmvc学习笔记(11)-springmvc注解开发之简单参数绑定

springmvc学习笔记(11)-springmvc注解开发之简单参数绑定 springmvc学习笔记11-springmvc注解开发之简单参数绑定 spring参数绑定过程 默认支持的类型 简单类型 pojo绑定 自定义参数绑定实现日期类型绑定 springmvc和struts2的区别 本文主要介绍注解开发的简单参数绑定,包括简单类型.简单pojo以及自定义绑定实现类型转换 spring参数绑定过程 从客户端请求key/value数据,经过参数绑定,将key/value数据绑定到contro

springmvc学习笔记(13)-springmvc注解开发之集合类型参数绑定

springmvc学习笔记(13)-springmvc注解开发之集合类型参数绑定 springmvc学习笔记13-springmvc注解开发之集合类型参数绑定 数组绑定 需求 表现层实现 list绑定 需求 表现层实现 map绑定 本文主要介绍注解开发的集合类型参数绑定,包括数组绑定,list绑定以及map绑定 数组绑定 需求 商品批量删除,用户在页面选择多个商品,批量删除. 表现层实现 关键:将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商