SpringMVC-05-数据绑定/转化/校验
静动态资源处理管理
我们最初在配置 DispatcherServlet
来作为处理方法映射的时候,因为静态资源无法找到对应的处理方法,所以无法访问,针对这个问题,使用 <mvc:default-servlet-handler/>
之后,SpringMVC 将在容器中中定义一个 SimpleUrlhandlerMapping,它的作用就是将请求交给 WEB 应用服务器默认的 Tomcat 处理,这样静态资源的访问就得到了解决。
但是我们标注了 <mvc:default-servlet-handler/>
之后,新加入的 SimpleUrlHandlerMapping 会覆盖我们原本用来处理方法映射的 DefaultAnnotationHandlerMapping。这样处理动态资源访问的映射关系就没有了,因此动态资源无法访问。
解决方法就是:使用 <mvc:annotation-driven/>
,添加这个设置之后,就会多出来一个优先级最高的 RequestMappingHandlerMapping,专门处理动态资源访问和处理方法之间的映射关系。只有这个 Mapping 无法处理的资源(静态资源),才会交给后面的 SimpleUrlHandlerMapping 处理(交给 Tomcat)。
<mcv:anntation-driven>
这个配置的字面意思就是 MVC 注解驱动。那么这个配置有什么用呢?
<mvc:annotation-driven/>
会自动注册: RequestMappingHandlerMapping 、 RequestMappingHandlerAdapter 与 ExceptionHandlerExceptionResolver 三个 bean。还将提供以下支持:
- 支持使用 ConversionService 实例对表单参数进行类型转换
- 支持使用 @NumberFormat、@DateTimeFormat 注解完成数据类型的格式化
- 支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证
- 支持使用 @RequestBody 和 @ResponseBody 注解实现 AJAX
数据绑定
数据绑定指的是从请求的数据到处理方法中的参数这个过程,在 SpringMVC 中,数据绑定的流程大概如下:
- SpringMVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象
- DataBinder 调用装配在 SpringMVC 上下文中的 ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中
- 调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果 BindingData 对象
- SpringMVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的参数。
也就是过程如下:
在 SpringMVC 的 ConversionService 数据转化服务中,有大量的转化器 Converter 可以作为用于将 String 类型的数据转化为 Java 常间的类型,但是对于我们自己设置的类型,如果需要转化则需要我们手动实现 Converter 接口。
比如我们想要将 String 类型转化为 User 类型;"Xorex-Tempest-Xorex@Tempest.com"
-> User{username=Xorex,password=Tempest,email=Xorex@Tempest.com}
需要这样实现接口:
1 | public class StringToUserConverter implements Converter<String, User> { |
实现了 Converter 之后,需要将我们自己实现的 Converter 放入执行转化服务的 ConversionService 中。而麻烦之处在于 ConversionService 是由 ConversionServiceFactoryBean 生成的,那么我们最终其实是将 Converter 交给 FormattingConversionServiceFactoryBean,由这个工厂来生成含有自定义 Converter 的 ConversionService。
所以我们需要 SpringMVC 配置文件中,声明:将自定义 Converter 交给 FormattingConversionServiceFactoryBean 并告诉 SpringMVC 用这个含有我们自定义 Converter 的 FactoryBean 来生成 ConversionService:
1 | <mvc:annotation-driven conversion-service="conversionService"/> |
数据格式化
前面介绍了通过实现 Converter 来实现自定义数据和请求数据的绑定。下面来介绍一下请求数据的格式化,也就是将请求发过来的数据转化为格式化的数据,比如将 2021-06-01
转化为 Date 对象。将 $12,123,234.3242
转化为 Double 对象等等。
这里使用的 Format 注解:@DateTimeFormat
和 @NumberFormat
等,只需要标注到需要接收格式化的参数或者字段前面,被 SpringMVC 自动填充的时候,就会根据 ConversionService 里面定义的 Format 规则进行格式化了。
而我们上面配置的 FormattingConversionServiceFactoryBean 这个工厂生成的 ConversionService 就包含一系列 Format 类型的 Class 用于数据格式化,而不同的注解也有不同的格式化方法,需要在注解参数 pattern
中填写。举个例子:
1 |
|
时间用 yyyy-MM-dd
规定传入的时间字符串格式,浮点数用 $#,###.##
规定传入的金钱的格式,对于 JavaBean 里面的数据使用格式化,则直接在 Bean 里面的字段加上注解即可,SpringMVC 进行参数填充的时候会读取上面的注解的。
数据校验
JSR-303
对于数据在服务端进行的数据校验工作,我们自己写真的是太麻烦了,于是在 JAVA6 里面推出了一种规范:JSR-303,JSR 是 Java Specification Requests 的缩写,意思是 Java 规范提案,又叫做 Bean Validation。JSR 303 是 Java 为 bean 数据合法性校验提供的标准框架。
使用 hibernate 实现的 JSR-303
需要导入一下包:一个是 hibernate.validator 的 hibernate-validator 和 fasterxml 的 classmate 共两个包。其中前者提供 JSR-303 接口的实现,后者为前者的依赖包(会自动加入另外一个依赖 jboss-logging)。
然后就可以使用很多 hibernate 自己实现的接口了,挺多挺好用的。
JavaBean 校验
然后我们就可以利用 JSR-303 定义的注解,去去进行数据校验了,这里的所有注解可以查看文档。对于自定义 Bean ,在 Bean 的声明处向内部标校验注解,然后参数处标注 @Valid
表示需要要校验这个 Bean,并紧接着被校验的 Bean 声明一个参数:BindingResult result
或者 Errors errors
,这个 两个类可以记录校验的结果。
1 | public class User { |
1 |
|
自定义错误消息
最简单的方法就是在任何一个校验的注解里面添加 message 属性,里面填写需要自定错误的消息。这样我们取出来的 Message 就是我们自己设置的错误了。
1 |
|
但是如果需要实现国际化的话,具体的流程和 JstlView 实现国际化的流程都是一样的,唯一的不同是对国际化文件的 Key 进行一定的规则限制。
因为我们在回显错误信息的时候,比如使用 <form:errors path="email">
来现实隐含模型中属性为 email 的校验错误的时候,他会根据一定的规则从国际化文档中寻找对应的 Key:
1 | Email.user.email=XXXX //在隐含模型的 user 对象的 email 字段使用 @Email 校验时,匹配此国际化错误信息 |
当有多个国际化 Key 得到匹配的时候,同样按照精确度决定匹配优先级。