SpringMVC(八)数据转换 & 数据格式化 & 数据校验

一、数据绑定流程

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

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

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

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

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

二、数据转换

Spring MVC 上下文中内建了很多转换器,可完成大多数 Java 类型的转换工作。

三、自定义类型转换器

(1)ConversionService 是 Spring 类型转换体系的核心接口。

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

(3)可通过 ConversionServiceFactoryBean 的 converters 属性 注册自定义的类型转换器。 

四、Spring 支持的转换器

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

(1)Converter<S,T>:将 S 类型对象转为 T 类型对象

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

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

五、自定义转换器示例

(1)input.jsp

(2)控制层

(3)自定义的转换器

(4)配置

(5)输入

(6)添加成功

六、关于 mvc:annotation-driven

<mvc:annotation-driven />会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean。

还将提供以下支持:

(1)支持使用 ConversionService 实例对表单参数进行类型转换

(2)支持使用 @NumberFormat annotation、@DateTimeFormat注解完成数据类型的格式化

(3)支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证

(4)支持使用 @RequestBody 和 @ResponseBody 注解

既没有配置<mvc:default-servlet-handler/>也没有配置<mvc:annotation-driven/>

配置了<mvc:default-servlet-handler/>但没有配置<mvc:annotation-driven/>

既配置了<mvc:default-servlet-handler/>又配置<mvc:annotation-driven/>

七、@InitBinder

由 @InitBinder 标识的方法,可以对 WebDataBinder 对 象进行初始化。WebDataBinder 是 DataBinder 的子类,用 于完成由表单字段到 JavaBean 属性的绑定

@InitBinder方法不能有返回值,它必须声明为void。

@InitBinder方法的参数通常是是 WebDataBinder

八、数据格式化

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

Spring 在格式化模块中定义了一个实现ConversionService 接口的FormattingConversionService 实现类,该实现类扩展 了 GenericConversionService,因此它既具有类型转换的 功能,又具有格式化的功能

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

FormattingConversionServiceFactroyBean 内部已经注册了 :

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

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

装配了 FormattingConversionServiceFactroyBean 后,就可以在 Spring MVC 入参绑定及模型数据输出时使用注解驱动 了。

<mvc:annotation-driven/>默认创建的ConversionService 实例即为FormattingConversionServiceFactroyBean

日期格式化

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

数值格式化

@NumberFormat 可对类似数字类型的属性进行标 注,它拥有两个互斥的属性:

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

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

配置了这个还是没有影响

转换失败

九、数据校验

JSR 303

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

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


Hibernate Validator 扩展注解

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

Spring MVC 数据校验

Spring 4.0 拥有自己独立的数据校验框架,同时支持 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 包中

需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参

Errors 接口提供了获取错误信息的方法,如 getErrorCount() 或getFieldErrors(String field)

BindingResult 扩展了 Errors 接口

在目标方法中获取校验结果

在表单/命令对象类的属性中标注校验注解,在处理方法对 应的入参前添加 @Valid,Spring MVC 就会实施校验并将校 验结果保存在被校验入参对象之后的 BindingResult 或Errors 入参中。

常用方法:

FieldError getFieldError(String field)

List<FieldError> getFieldErrors()

Object getFieldValue(String field)

Int getErrorCount()

测试

(1)先导入相关的包

(2)给实体的属性上添加校验的注解

(3)在控制层的入参前加上@Valid,还有出错就转向定制页面

(4)验证结果

在页面上显示错误

Spring MVC 除了会将表单/命令对象的校验结果保存到对 应的 BindingResult 或 Errors 对象中外,还会将所有校验 结果保存到 “隐含模型”

即使处理方法的签名中没有对应于表单/命令对象的结果 入参,校验结果也会保存在 “隐含对象” 中。

隐含模型中的所有数据最终将通过 HttpServletRequest 的 属性列表暴露给 JSP 视图对象,因此在 JSP 中可以获取 错误信息

在 JSP 页面上可通过<form:errors path=“userName”>显示错误消息

提示消息的国际化

每个属性在数据绑定和数据校验发生错误时,都会生成一 个对应的 FieldError 对象。

当一个属性校验失败后,校验框架会为该属性生成 4 个消 息代码,这些代码以校验注解类名为前缀,结合modleAttribute、属性名及属性类型名生成多个对应的消息代码:例如 User 类中的 password 属性标准了一个 @Pattern 注 解,当该属性值不满足 @Pattern 所定义的规则时, 就会产生以下 4  个错误代码:

Pattern.user.password

Pattern.password

Pattern.java.lang.String

Pattern

当使用 Spring MVC 标签显示错误消息时, Spring MVC 会查看WEB 上下文是否装配了对应的国际化消息,如果没有,则显示默认 的错误消息,否则使用国际化消息。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容