第九章 数据绑定流程分析

数据转换

springMVC封装自定义类型对象的时候;
javaBean要和页面提交的数据进行一一绑定

  • 页面提交的所有数据都是字符串
  • Integer age ,Date birth;age=18&gender=1...
  • String age = request.getParameter("age")

牵扯到一下操作:

  • 数据绑定期间的数据类型转换?String--Integer String--Boolean
  • 数据绑定期间的数据格式化问题
    birth = 2017-01-10 -> Date 2017/01/10.....
  • 数据校验
    我们提交的数据必须是合法的?前端校验:js+正则表达式、后端校验:复杂数据 【校验成功、校验失败】
    WebDataBinder:数据绑定器负责数据绑定工作
    数据绑定期间产生的类型转换、格式化、数据校验等问题
    bindingResult:处理异常
    conversionService:类型转换 格式化
    validators:数据校验器
    图片说明
    Spring MVC 上下文中内建了很多转换器,可完成大多数 Java 类型的转换工作
    ConversionService converters =  
    java.lang.Boolean->java.lang.String: org.springframework.core.convert.support.ObjectToStringConverter@f874ca
    java.lang.Character -> java.lang.Number : CharacterToNumberFactory@f004c9
    java.lang.Character -> java.lang.String : ObjectToStringConverter@68a961
    java.lang.Enum -> java.lang.String : EnumToStringConverter@12f060a
    java.lang.Number -> java.lang.Character : NumberToCharacterConverter@1482ac5
    java.lang.Number -> java.lang.Number : NumberToNumberConverterFactory@126c6f
    java.lang.Number -> java.lang.String : ObjectToStringConverter@14888e8
    java.lang.String -> java.lang.Boolean : StringToBooleanConverter@1ca6626
    java.lang.String -> java.lang.Character : StringToCharacterConverter@1143800
    java.lang.String -> java.lang.Enum : StringToEnumConverterFactory@1bba86e
    java.lang.String -> java.lang.Number : StringToNumberConverterFactory@18d2c12
    java.lang.String -> java.util.Locale : StringToLocaleConverter@3598e1
    java.lang.String -> java.util.Properties : StringToPropertiesConverter@c90828
    java.lang.String -> java.util.UUID : StringToUUIDConverter@a42f23
    java.util.Locale -> java.lang.String : ObjectToStringConverter@c7e20a
    java.util.Properties -> java.lang.String : PropertiesToStringConverter@367a7f
    java.util.UUID -> java.lang.String : ObjectToStringConverter@112b07f  ……

POJO 请求域?session?创建一个?绑定部分的代码
ModelAttributeMethodProcessor:新源码 mvc相关注解的影响
图片说明

数据绑定流程原理

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

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

自定义类型转换器

类型转换器概述

  • ConversionService 是 Spring 类型转换体系的核心接口。
  • 可以利用 ConversionServiceFactoryBean 在 Spring 的 IOC 容器中定义一个
    ConversionService. Spring 将自动识别出 IOC 容器中的 ConversionService,并在 Bean 属性配置及 Spring MVC 处理方法入参绑定等场合使用它进行数据的转换
  • 可通过 ConversionServiceFactoryBean 的 converters 属性注册自定义的类型转换器

ConversionService组件:负责数据类型的转换以及格式化功能;
ConversionService中有非常多的converter
不同类型的转换和格式化用他自己的converter

Spring 支持的转换器类型

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

  • Converter<S,T>:将 S 类型对象转为 T 类型对象
  • ConverterFactory:将相同系列多个 “同质” Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将 String 转换为 Number 及 Number 子类(Integer、Long、Double 等)对象)可使用该转换器工厂类 x
  • GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换 x

自定义转换器示例

需求:字符串转换为对象: 12-java编程思想=>book
如果没有加自定义转换器组件-->报错
图片说明

《% 
    pageContext.setAttribute("ctp", request.getContextPath());
%>
    《form action="${ctp}/book" method="post">
    《!-- 直接封装成book对象 -->
        《input type="text" name="bookInfo" value="12-java编程思想">
        《input type="submit" value="提交"/>
    《/form>

步骤1
conversionService:是一个接口,里有Converter(转换器)进行工作
图片说明

步骤2
实现converter接口,写一个自定义的类型转换器

import org.springframework.core.convert.converter.Converter;
import com.project.bean.Book;
public class MyConverterFunc implements Converter<String, Book> {
    public Book convert(String s) {
        Book book = new Book();
        if(s.contains("-")) {    
            String arr[] = s.split("-");
            book.setId(arr[0]);
            book.setBookName(arr[1]);

        }
            return book;
    }
}

步骤3
Converter是ConversionService中的组件,你的Converter得放进Converter中

  • 你的Converter得放进ConversionService中

  • 将WebDataBinder中的ConversionService设置成我们这个加了自定义类型转换器的ConversionService

  • 配置出ConversionService

      <!-- 告诉SpringMVC 别用默认的ConversionService,而用我自定义的ConversionService
          可能有我们自定义的Converter
       -->
      <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
          <property name="converters">
              <set>
                  <bean class="com.project.component.MyConverterFunc"/>
              </set>
          </property>
      </bean>
    
      <mvc:default-servlet-handler/>
    
      <!-- 可以告诉springmvc使用我们自己配置的类型转换组件 -->
      <mvc:annotation-driven conversion-service="conversionService"/> 

    图片说明

  • 效果 springmvc 会自动找到String->Book 的转换器
    图片说明

总结:

  • 实现Converter接口,做一个自定义类型的转换器
  • 将这个converter配置在ConversionService中
  • 告诉springmvc使用这个ConversionService

数据的格式化

数据格式化概述

  • 对属性对象的输入/输出进行格式化,从其本质上讲依然属于 “类型转换” 的范畴。
  • Spring 在格式化模块中定义了一个实现 ConversionService 接口的
    FormattingConversionService 实现类,该实现类扩展了 GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能
  • FormattingConversionService 拥有一个 FormattingConversionServiceFactroyBean 工厂类,后者用于在 Spring 上下文中构造前者,FormattingConversionServiceFactroyBean 内部已经注册了 :
  • NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性使用
    @NumberFormat 注解
  • JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用
    @DateTimeFormat 注解
  • 装配了 FormattingConversionServiceFactroyBean 后,就可以在 Spring MVC 入参绑定及模型数据输出时使用注解驱动了。
  • 《mvc:annotation-driven/> 默认创建的 ConversionService 实例即为
    DefaultFormattingConversionService

DeBug 看看替换ConversionService是否也替换了其他转换器

  • 图片说明
  • 源码上WebDataBinder上的ConversionService组件就替换了 默认的转换器都还 在 注册的新添上
    图片说明
  • 默认的转换器
    图片说明

《mvc:annotation-driven/>配置在什么时候必须配置

  • 直接配置响应的页面:无需经过控制器来执行结果 ;但会导致其他请求路径失效,需要配置mvc:annotation-driven标签
    <mvc:view-controller path="/success" view-name="success"/>
  • RESTful-CRUD操作,删除时,通过jQuery执行delete请求时,找不到静态资源,需要配置mvc:annotation-driven标签
    <mvc:default-servlet-handler/> 将在 SpringMVC 上下文中定义一个
    DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由 WEB 应用服务器默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理。
  • 配置类型转换器服务时,需要指定转换器服务引用
    《mvc:annotation-driven conversion-service=“conversionService”/> 会将自定义的ConversionService 注册到 Spring MVC 的上下文中
  • 后面完成JSR 303数据验证,也需要配置

关于 《mvc:annotation-driven /> 作用

《mvc:annotation-driven /> 会自动注册:
RequestMappingHandlerMapping 、RequestMappingHandlerAdapter 与
ExceptionHandlerExceptionResolver 三个bean。
还将提供以下支持:

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

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

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

  • 支持使用 @RequestBody 和 @ResponseBody 注解

  • 结合源码分析(在bean对象的set方法上设置断点进行调试)

    • 既没有配置 《mvc:default-servlet-handler/> 也没有配置 《mvc:annotation-driven/> 【动态资源能访问 静态不行.html、.js、.img】
      handlerAdapters:方法执行适配器 对我们有用是第三个 mv = ha.handle(...)
      图片说明
      都没有配置情况下,AnnotationMethodHandlerAdapter是默认出厂设置,干活的(过期)。
      HandlerMapping:第二个Default...类中的HashMap 保存了每一个资源的映射信息;却没有保存静态资源映射请求.js .html ....
      图片说明
      另外:conversionService是null(类型转换器是不起作用的)

      静态资源不起作用
      四月 30, 2016 3:52:21 下午 org.springframework.web.servlet.PageNotFound noHandlerFound
      警告: No mapping found for HTTP request with URI [/SpringMVC_03_RESTFul_CRUD/scripts/jquery-1.9.1.min.js] in DispatcherServlet with name 'springDispatcherServlet'
    • 配置了 《mvc:default-servlet-handler/> 但没有配置 《mvc:annotation-driven/> 【静态资源能访问 动态资源不能访问】
      AnnotationMethodHandlerAdapter被取消,解决了静态资源查找,但是@RequestMapping不好使了。
      handlerAdapters:【处理注解的适配器都没有了】
      图片说明
      HandlerMapping:[SimpleUrl...就是把所有请求都交给Tomcat来处理,tomcat只能处理静态资源]
      图片说明

    • 既配置了 《mvc:default-servlet-handler/> 又配置 《mvc:annotation-driven/>【重要 都要能访问】
      AnnotationMethodHandlerAdapter被替换成RequestMappingHandlerAdapter来干活了。
      如果没有配置《mvc:annotation-driven/>标签时,conversionService为null.
      handlerAdapters:【Annotation被换成requestMapping】
      图片说明
      HandlerMapping:【requestMapping....中有handlerMethods所有详细信息 如每一个请求用哪个方法来处理 动态资源可以处理 里面找不到取别的地方找 所以静态资源也可以】
      s

    • AnnotationMethodHandlerAdapter已经过时,Spring3.2推荐RequestMappingHandlerAdapter来替代。所以说,默认情况下,没有配置这两个配置时,HelloWorld 程序可以正常运行,但是,涉及到静态资源查找的时候,就必须配置这个《mvc:annotation-driven/>配置了
      图片说明

      图片说明

BeanDefinitionParser 作用

解析springmvc各种各样的标签 如解析引入外部文件标签 List标签 Set标签 mvc:annotation-driven......
图片说明

全部评论

相关推荐

点赞 评论 收藏
分享
01-14 19:01
吉首大学 Java
黑皮白袜臭脚体育生:加个项目吧,一般需要两个项目一业务一轮子呢,简历统一按使用了什么技术实现了什么功能解决了什么问题或提升了什么性能指标来写
点赞 评论 收藏
分享
02-02 20:25
门头沟学院 Java
数学转码崽:八股文也算是前人总结的精华,但是因为全是结果导向,你光背不去理解它背后的深层原理和这样做的原因,反而忽略了程序员最该重视的过程导向。推荐你不会的就去多问ai,比如我当时背的时候,concurrenthashmap底层原理常见八股网站都会讲,但是我不理解为什么它去用synchronize锁节点,为什么不用reentrantlock去锁节点。面试官问我你为什么觉得synchronize在这个场景下性能更好呢?虽然面试官可能也不确定清楚,但是你可以尝试给他解答,让他看见你的思考,这才是最重要的,毕竟你没实习,你的项目你也无法证明是你自己思考的产物,那就在别的地方体现你的能力
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
02-12 18:14
RT,这周五就是情人节了,前女友给我发了消息,我该不该回?
Yoswell:原则上来说让她滚,但是本着工作很累下班想吃瓜的心态,我觉得你可以回一下
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务