`
bsr1983
  • 浏览: 1104031 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring MVC学习笔记

 
阅读更多
1.CGI:(Common Gateway Interface)公共网关接口,一种在web服务端使用的脚本技术,使用C或Perl语言编写,用于接收web用户请求并处理,最后动态产生响应给用户,但每次请求将产生一个进程,重量级。
2.一种JavaEE web组件技术,是一种在服务器端执行的web组件,用于接收web用户请求并处理,最后动态产生响应给用户。但每次请求只产生一个线程(而且有线程池),轻量级。而且能利用许多Java EE技术。本质就是在java代码里面输出html流。但表现逻辑、控制逻辑、业务逻辑调用混杂。
3.JSP:(Java Server Page):一种在服务的执行的web组件,是一种运行在标准的HTML页面中嵌入脚本语言(现在只支持Java)的模板页面技术。本质就是在html代码中嵌入java代码。JSP最终还是会被编译为Servlet,只不过比纯Servlet开发页面更简单、方便。但表现逻辑、控制逻辑、业务逻辑调用还是混杂。
4.Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web 框架,即使用了MVC架构模式的思想,将web 层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。
Spring Web MVC也是服务到工作者模式的实现,但进行可优化。前端控制器是DispatcherServlet;应用控制器其实拆为处理器映射器(Handler Mapping)进行处理器管理和视图解析器(View Resolver)进行视图管理;页面控制器/动作/
处理器为Controller 接口(仅包含ModelAndView handleRequest(request, response) 方法)的实现(也可以是任何的POJO 类);支持本地化(Locale)解析、主题(Theme)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了强大的约定大于配置(惯例优先原则)的契约式编程支持。
5.前端控制器(DispatcherServlet)、请求到处理器映射(HandlerMapping)、处理器适配器 (HandlerAdapter)、视图解析器(ViewResolver)、处理器或页面控制器(Controller)、验证器( Validator)、命令对象 (Command 请求参数绑定到的对象就叫命令对象)、表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
6.默认DispatcherServlet会加载WEB-INF/[DispatcherServerlet的Servlet名字]-servlet.xml配置文件。
BeanNameUrlHandlerMapping:表示将请求的URL和Bean名字映射,如URL为“上下文/hello”,则Spring配置文件必须有一个名字为“/hello”的Bean,上下文默认忽略。
SimpleControllerHandlerAdapter:表示所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean 可以作为Spring Web MVC中的处理器。如果需要其他类型的处理器可以通过实现HadlerAdapter 来解决。
7.@Controller:用于标识是处理器类; 
@RequestMapping:请求到处理器功能方法的映射规则;
@RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定;
@ModelAttribute:请求参数到命令对象的绑定;
@SessionAttributes:用于声明session 级别存储的属性,放置在处理器类上,通常列出模型属性(如@ModelAttribute)对应的名称,则这些属性会透明的保存到session 中;
@InitBinder:自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;
@CookieValue:cookie 数据到处理器功能处理方法的方法参数上的绑定;
@RequestHeader:请求头(header)数据到处理器功能处理方法的方法参数上的绑定;
@RequestBody:请求的body体的绑定(通过HttpMessageConverter 进行类型转换);
@ResponseBody:处理器功能处理方法的返回值作为响应体(通过HttpMessageConverter进行类型转换);
@ResponseStatus:定义处理器功能处理方法/异常处理器返回的状态码和原因;
@ExceptionHandler:注解式声明异常处理器;
@PathVariable:请求URI 中的模板变量部分到处理器功能处理方法的方法参数上的绑定,从而支持RESTful 架构风 格的URI;
8.DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:
(1)文件上传解析,如果请求类型是multipart将通过MultipartResolver 进行文件上传解析;
(2) 通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个 HandlerInterceptor 拦截器); 
(3) 通过 HandlerAdapter 支持多种类型的处理器(HandlerExecutionChain中的处理器);
(4) 通过ViewResolver 解析逻辑视图名到具体视图实现;
(5) 本地化解析;
(6) 渲染具体的视图等;
(7) 如果执行过程中遇到异常将交给HandlerExceptionResolver 来解析。
9.DispatcherServlet也可以配置自己的初始化参数,覆盖默认配置:
(1)contextClass:实现WebApplicationContext接口的类,当前的servlet用它来创建上下文。如果这个参数没有指定, 默认使用XmlWebApplicationContext。
(2)contextConfigLocation:传给上下文实例(由contextClass指定)的字符串,用来指定上下文的位置。 这个字符串可以被分成多个字符串(使用逗号作为分隔符) 来支持多个上下文 (在多上下文的情况下,如果同一个bean被定义两次,后面一个优先)。
(3)namespace:WebApplicationContext命名空间。默认值是[server-name]-servlet。
10.ContextLoaderListener 初始化的上下文加载的Bean 是对于整个应用程序共享的,不管是使用什么表现层技术,一 般如DAO层、Service层Bean; 
DispatcherServlet 初始化的上下文加载的Bean 是只对Spring Web MVC 有效的Bean,Controller、 HandlerMapping、HandlerAdapter等等,该初始化上下文应该只加载Web相关组件。
11.cancelParamKey:用于判断是否是取消的请求参数名,默认是_cancel,即如果请求参数数据中含有名字_cancel则表 示是取消,将调用onCancel功能处理方法; 
cancelView:表示取消时时显示的页面;“redirect:/cancel”表示成功处理后重定向到/cancel控制器;防止表单 重复提交;
12.DispatcherServlet中使用的特殊的Bean
DispatcherServlet默认使用WebApplicationContext作为上下文,因此我们来看一下该上下文中有哪些特殊的Bean:
(1)Controller:处理器/页面控制器,做的是MVC中C的事情,但控制逻辑转移到前端控制器了,用于对请求进行处理。
(2)HandlerMapping:请求到处理器的映射,如果映射成功返回一个HandlerExceutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象;如BeanNameUrlHandlerMapping将URL与Bean名字映射,映射成功的Bean就是此处的处理器。
(3)HandlerAdapter:HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;如SimpleControllerHandlerAdapter将对实现了Controller接口的Bean进行适配,并且调用处理器的handleRequest方法进行功能处理。
(4)ViewResolver:ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;如InternalResourceViewResolver将逻辑视图名映射为jsp视图;
(5)LocalResover:本地化解析,因为Spring支持国际化,因此LocalResover解析客户端的Local信息从而方便进行国际化。
(6)ThemeResovler:主题解析,通过它来实现一个页面多套风格,即常见的类似于软件皮肤效果;
(7)MultipartResolver:文件上传解析,用于支持文件上传。
(8)HandlerExceptionResolver:处理器异常解析,可以将异常映射到相应的统一错误界面,从而显示用户友好的界面(而不是给用户看到的具体错误信息);
(9)RequestToViewNameTranslator:当处理器没有返回逻辑视图名等相关信息时,自动将请求URL映射为逻辑视图名。
(10)FlashMapManager:用于管理FlashMap的策略接口,FlashMap用于存储一个请求的输出,当进入另一个请求时作为该请求的输入,通常用于重定向场景。
13.注:下面提到一些关于缓存控制的一些特殊情况:
(1)对于一般的页面跳转(如超链接点击跳转、通过js调用window.open打开新页面都是会使用浏览器缓存的,在未过期的情况下会直接使用浏览器缓存的副本,在未过期的情况下一次请求也不发送);
(2)对于刷新页面(如按F5键刷新),会再次发送一次请求到服务器的。
14.Last-Modified缓存机制
(1)在客户端第一次输入url时,服务器端会返回内容和状态码200表示请求成功并返回了内容;同时会添加一个“Last-Modified”的响应头表示此文件在服务器上的最后更新时间。
(2)客户端第二次请求此URL时,客户端会向服务器发送请求头“If-Modified-Since”,询问服务器该时间之后当前请求内容是否有被修改过,如果服务器端的内容没有变化,则自动返回HTTP304状态码(只要响应头,内容为空,这样就节省了网络带宽)。
15.客户端强制缓存过期:
(1)可以按ctrl+F5强制刷新(会添加请求头HTTP1.0 Pragma:no-cache和HTTP1.1 Cache-Control:no-cache、If-Modified-Since请求头被删除)表示强制获取服务器内容,不缓存。
(2)在请求的url后加上时间戳来重新获取内容,加上时间戳后浏览器就认为不是同一份内容
Spring也提供了Last-Modified机制的支持,只需要实现LastModified接口的getLastModified方法,保证当内容发送改变时返回最新的修改时间即可。
16.ETag(实体标记)缓存机制
(1)浏览器第一次请求,服务器在响应时给请求URL标记,并在HTTP响应头中将其传送到客户端,类似服务器端返回的格式:“ETag:"0f8b0c86fe2c0c7a67791e53d660208e3"”
(2)浏览器第二次请求,客户端的查询更新格式是这样的:“If-None-Match:"0f8b0c86fe2c0c7a67791e53d660208e3"”,如果ETag没改变,表示内容没有发送改变,则返回状态304.
Spring也提供了对ETag的支持,具体需要在web.xml中配置如下代码:
<filter>
    <filter-name>etagFilter</filter-name>
    <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>etagFilter</filter-name>
    <servlet-name>/</servlet-name>
</filter-mappring>
17.ServletForwardingController 将接收到的请求转发到一个指定名称的servlet
18.BaseCommandController 命令控制器通用基类,提供了以下功能支持:
(1)数据绑定:请求参数绑定到一个command object,这里的命令对象是指绑定请求参数的任何POJO对象;
commandClass:表示命令对象实现类。
commandName:表示放入请求的命令对象名字(默认command)
request.setAttribute(commandName,commandObject);
(2)验证功能:提供Validator注册功能,注册的验证器会验证命令对象属性数据是否合法;
validators:通过该属性注入验证器,验证器用来验证命令对象属性是否合法。
19.AbstractCommandController 命令控制器之一,可以实现该控制器来创建命令控制器,该控制器能把自动封装请求参数到一个命令对象,而且提供验证功能。
20.注册PropertyEditeor
(1)使用WebDataBinder进行控制器级别注册PropertyEditor(控制器独享)
(2)使用WebBindingInitializer批量注册PropertyEditor
21.验证流程
(1)首先进行数据绑定验证,如果验证失败会通过MessageCodesResolver生成错误码放入Errors错误对象
(2)数据不合法验证,通过自定义的验证器验证,如果失败需要手动将错误码放入Errors错误对象
22.数据绑定失败(类型不匹配)会自动生成如下错误码(错误码对应的错误消息按照如下顺序依次查找):
(1)typeMismatch.命令对象名.属性名
(2)typeMismatch.属性名
(3)typeMismatch.属性全限定名(包名.类名)
(4)typeMismatch
23.Spring Web MVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
拦截器有三个方法:
(1)preHandle:预处理回调方法,实现处理器的预处理,第三个参数为响应的处理器。
    返回值:true表示继续流程,如调用下一个拦截器或处理器
                  false表示流程终端,不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应
(2)postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
(3)afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以再次记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中的prtHandle返回true的拦截器的afterCompletion。
24.窄化的请求映射可以认为是方法级别的@RequestMapping继承类级别的@RequestMapping
请求的映射分为以下几种:
(1)URL路径映射:使用URL映射请求到处理器的功能处理方法;
(2)请求方法映射限定:如限定功能处理方法只处理GET请求
(3)请求参数映射限定:如限定只处理包含“abc”请求参数的请求
(4)请求头映射限定:如限定只处理“Accept=application/json”的请求
25.URL路径映射
(1)普通URL路径映射
@RequestMapping(value={"/test1","/user/create"}):多个URL路径可以映射到同一个处理器的功能处理方法。
(2)URI模板模式映射
@RequestMapping(value="/users/{userId}"):{×××}占位符, 请求的URL可以是“/users/123456”或“/users/abcd”,通过@PathVariable可以提取URI模板模式中的{×××}中的×××变量。
@RequestMapping(value="/users/{userId}/create") : 这样也是可以的, 请求的URL 可以是“/users/123/create”。
@RequestMapping(value="/users/{userId}/topics/{topicId}"):这样也是可以的,请求的URL 可以是“/users/123/topics/123”
(3)Ant风格的URL路径映射
@RequestMapping(value="/users/**"):可以匹配“/users/abc/abc”,但“/users/123”将会被【URI模板模式映射
中的“/users/{userId}”模式优先映射到】【详见4.14的最长匹配优先】。
@RequestMapping(value="/product?"):可匹配“/product1”或“/producta”,但不匹配“/product”或“/productaa”;
@RequestMapping(value="/product*"):可匹配“/productabc”或“/product”,但不匹配“/productabc/abc”;
@RequestMapping(value="/product/*"):可匹配“/product/abc”,但不匹配“/productabc”;
@RequestMapping(value="/products/**/{productId}"):可匹配“/products/abc/abc/123”或“/products/123”,
也就是Ant风格和URI模板变量风格可混用;
(4)正则表达式风格的URL路径映射
从Spring3.0 开始支持正则表达式风格的URL路径映射,格式为{变量名:正则表达式},这样我们就可以通过6.6.5 讲的
通过@PathVariable提取模式中的{×××:正则表达式匹配的值}中的×××变量了。
@RequestMapping(value="/products/{categoryCode:\\d+}-{pageNumber:\\d+}") : 可以匹配
“/products/123-1”,但不能匹配“/products/abc-1”,这样可以设计更加严格的规则。
正则表达式风格的URL路径映射是一种特殊的URI模板模式映射:
URI模板模式映射是{userId},不能指定模板变量的数据类型,如是数字还是字符串;
正则表达式风格的URL路径映射,可以指定模板变量的数据类型,可以将规则写的相当复杂。
26.@RequestMapping配置
@RequestMapping(value="/methodOr", method = {RequestMethod.POST, RequestMethod.GET}):即请求方法可以是GET 或POST。
DispatcherServlet默认开启对GET、POST、PUT、DELETE、HEAD 的支持;
如果需要支持OPTIONS、TRACE,请添加DispatcherServlet 在web.xml 的初始化参数:dispatchOptionsRequest 和dispatchTraceRequest 为true。
@RequestMapping(params="create", method=RequestMethod.GET) :表示请求中有“create”的参数名且请求方法为“GET”即可匹配,如可匹配的请求URL“http://×××/parameter1?create”;
@RequestMapping(params="create", method=RequestMethod.POST):表示请求中有“create”的参数名且请求方法为“POST”即可匹配;
@RequestMapping(params="!create", method=RequestMethod.GET):表示请求中没有“create”参数名且请求方法为“GET”即可匹配,如可匹配的请求URL“http://×××/parameter1?abc”。
@RequestMapping(params="submitFlag=create", method=RequestMethod.GET) : 表示请求中有 “submitFlag=create”请求参数且请求方法为“GET” 即可匹配,如请求URL为http://××× /parameter2?submitFlag=create; 
@RequestMapping(params="submitFlag=create", method=RequestMethod.POST) : 表示请求中有 “submitFlag=create”请求参数且请求方法为“POST”即可匹配;
@RequestMapping(params="submitFlag!=create", method=RequestMethod.GET):表示请求中的参数 “submitFlag!=create”且请求方法为“GET”即可匹配,如可匹配的请求URL“http://××× /parameter1?submitFlag=abc”。
@RequestMapping(params={"test1", "test2=create"}):表示请求中的有“test1”参数名且 有 “test2=create”参数即可匹配,如可匹配的请求URL“http://×××/parameter3?test1&test2=create。
@RequestMapping(value="/header/test1", headers= "Accept"):表示请求的URL必须为“/header/test1” 且 请求头中必须有Accept参数才能匹配。 
@RequestMapping(value="/header/test1", headers = "abc"):表示请求的URL必须为“/header/test1” 且 请求头中必须有abc参数才能匹配
@RequestMapping(value="/header/test2", headers = "!abc"):表示请求的URL必须为“/header/test2” 且 请求头中必须没有abc参数才能匹配。
@RequestMapping(value="/header/test3", headers = "Content-Type=application/json"):表示请求 的URL必须为“/header/test3”且 请求头中必须有“Content-Type=application/json”参数即可匹配。
当你请求的URL为“/header/test3” 但 如果请求头中没有或不是“Content-Type=application/json”参数(如 “text/html”其他参数),将返回“HTTP Status 415”状态码【表示不支持的媒体类型(Media Type),也就是MIME 类型】,即我们的功能处理方法只能处理application/json 的媒体类型。 
@RequestMapping(value="/header/test4", headers = "Accept=application/json"):表示请求的URL必 须为“/header/test4” 且 请求头中必须有“Accept =application/json”参数即可匹配。
当你请求的URL为“/header/test4” 但 如果请求头中没有“Accept=application/json”参数(如“text/html”其他参数),将返回“HTTP Status 406”状态码【不可接受,服务器无法根据Accept头的媒体类型为客户端生成响应】,即客户只接受“application/json”媒体类型的数据,即我们的功能处理方法的响应只能返回“application/json”媒体类型的数据。
@RequestMapping(value="/header/test5", headers = "Accept=text/*") : 表示请求的URL必须为“/header/test5” 且 请求头中必须有如“Accept=text/plain”参数即可匹配。(将Modify Header的Accept参数值改为“text/plain”即可);Accept=text/*:表示主类型为text,子类型任意,如“text/plain”、“text/html”等都可以匹配。
@RequestMapping(value="/header/test6", headers = "Accept=*/*") : 表示请求的URL 必须为“/header/test6” 且 请求头中必须有任意Accept参数即可匹配。(将Modify Header的Accept参数值改为“text/html”或“application/xml”等都可以)。
Accept=*/*:表示主类型任意,子类型任意,如“text/plain”、“application/xml”等都可以匹配。
@RequestMapping(value="/header/test7", headers = "Accept!=text/vnd.wap.wml"):表示请求的URL 必须为“/header/test7” 且 请求头中必须有“Accept”参数但值不等于“text/vnd.wap.wml”即可匹配。
@RequestMapping(value="/header/test8", headers = {"Accept!=text/vnd.wap.wml", "abc=123"}): 表示请求的URL必须为“/header/test8” 且 请求头中必须有“Accept”参数但值不等于“text/vnd.wap.wml”且 请求中必须有参数“abc=123”即可匹配。 
注:Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
如果您的请求中含有Accept:“*/*”,则可以匹配功能处理方法上的如“text/html”、“text/*”,“application/xml”等。
27.Media Type
互联网媒体类型,一般就是我们所说的MIME 类型,用来确定请求的内容类型或响应的内容类型。
常见媒体类型:
text/html : HTML格式         text/plain :纯文本格式                  text/xml :XML格式
image/gif :gif图片格式       image/jpeg :jpg图片格式              image/png:png图片格式
application/x-www-form-urlencoded : <form encType=””>中默认的encType,form表单数据被编码为key/value 格式发 送到服务器(表单默认的提交数据的格式)。 
multipart/form-data : 当你需要在表单中进行文件上传时,就需要使用该格式;
application/xhtml+xml :XHTML格式                   application/xml : XML数据格式
application/atom+xml :Atom XML聚合格式       application/json : JSON 数据格式
application/pdf :pdf格式                                     application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)。
在如 tomcat服务器的“conf/web.xml”中指定了扩展名到媒体类型的映射,在此我们可以看到服务器支持的媒体类型。
28.Content-Type:内容类型,即请求/响应的内容区数据的媒体类型;
(1)请求头的内容类型,表示发送到服务器的内容数据的媒体类型;
request中设置请求头“Content-Type: application/x-www-form-urlencoded”表示请求的数据为key/value数据;
①客户端—发送请求—服务器:客户端通过请求头Content-Type指定内容体的媒体类型(即客户端此时是生产者),服务 器根据Content-Type消费内容体数据(即服务器此时是消费者); 
②服务器—发送请求—客户端:服务器生产响应头Content-Type指定的响应体数据(即服务器此时是生产者),客户端根 据Content-Type消费内容体数据(即客户端此时是消费者)。
29.Accept:用来指定什么媒体类型的响应是可接受的,即告诉服务器我需要什么媒体类型的数据,此时服务器应该 根据Accept请求头生产指定媒体类型的数据。
@RequestMapping(value = "/consumes", consumes = {"application/json"}):此处使用consumes来指定功能处理方法能消费的媒体类型,其通过请求头的“Content-Type”来判断。
@RequestMapping(value= "/produces", produces= "application/json"):表示将功能处理方法将生产json 格式的数据,此时根据请求头中的Accept进行匹配,如请求头“Accept:application/json”时即可匹配; 
@RequestMapping(value = "/produces", produces = "application/xml"):表示将功能处理方法将生产xml 格式的数据,此时根据请求头中的Accept进行匹配,如请求头“Accept:application/xml”时即可匹配。
当你有如下Accept 头:
①Accept:text/html,application/xml,application/json
将按照如下顺序进行produces的匹配①text/html ②application/xml ③application/json
②Accept:application/xml;q=0.5,application/json;q=0.9,text/html
将按照如下顺序进行produces的匹配①text/html ②application/json ③application/xml
q参数为媒体类型的质量因子,越大则优先权越高(从0到1)
③Accept:*/*,text/*,text/html
将按照如下顺序进行produces的匹配①text/html ②text/* ③*/*
即匹配规则为:最明确的优先匹配。
如 类级别的映射为@RequestMapping(value="/narrow", produces="text/html") , 方法级别的为
@RequestMapping(produces="application/xml"),此时方法级别的映射将覆盖类级别的,因此请求头 “Accept:application/xml”是成功的,而“text/html”将报406错误码,表示不支持的请求媒体类型。
@RequestMapping(produces={"text/html", "application/json"}) : 将 匹配“ Accept:text/html ” 或 “Accept:application/json”
30.WebRequest是Spring Web MVC提供的统一请求访问接口,不仅仅可以访问请求相关数据(如参数区数据、请求头数 据,但访问不到Cookie区数据),还可以访问会话和上下文中的数据;NativeWebRequest继承了WebRequest,并提 供访问本地Servlet API的方法。
① webRequest.getParameter:访问请求参数区的数据,可以通过getHeader()访问请求头数据;
② webRequest.setAttribute/getAttribute:到指定的作用范围内取/放属性数据,Servlet定义的三个作用范围
分别使用如下常量代表:
SCOPE_REQUEST :代表请求作用范围;
SCOPE_SESSION :代表会话作用范围;
SCOPE_GLOBAL_SESSION :代表全局会话作用范围,即ServletContext上下文作用范围。
③ nativeWebRequest.getNativeRequest/nativeWebRequest.getNativeResponse:得到本地的Servlet API。 
注意:session 访问不是线程安全的,如果需要线程安全,需要设置AnnotationMethodHandlerAdapter 或 RequestMappingHandlerAdapter 的synchronizeOnSession属性为true,即可线程安全的访问session。
Spring Web MVC能够自动将请求参数绑定到功能处理方法的命令/表单对象上。
Spring Web MVC 提供Model、Map或ModelMap让我们能去暴露渲染视图需要的模型数据。
AnnotationMethodHandlerAdapter 和RequestMappingHandlerAdapter 将使用BindingAwareModelMap 作为模型对象的实 现,即此处我们的形参(Model model, Map model2, ModelMap model3)都是同一个BindingAwareModelMap实例。
功能处理方法的返回值中的模型数据(如ModelAndView)会合并 功能处理方法形式参数 中的模型数据(如Model),但如果两者之间有同名的,返回值中的模型数据会覆盖形式参数中的模型数据。
31.@RequestParam注解主要有哪些参数:
value:参数名字,即入参的请求参数名字,如username表示请求的参数区中的名字为username的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报404错误码;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值,默认值可以是SpEL 表达式,如 “#{systemProperties['java.vm.version']}”
public String requestparam4(@RequestParam(value="username",required=false) String username)
表示请求中可以没有名字为username 的参数,如果没有默认为null,此处需要注意如下几点:
(1)原子类型:必须有值,否则抛出异常,如果允许空值请使用包装类代替。
(2)Boolean包装类型类型:默认Boolean.FALSE,其他引用类型默认为null。
@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。
@RequestMapping(value="/users/{userId}/topics/{topicId}")
public String test(
@PathVariable(value="userId") int userId,
@PathVariable(value="topicId") int topicId)
如请求的 URL 为“控制器URL/users/123/topics/456”,则自动将URL 中模板变量{userId}和{topicId}绑定到通过 @PathVariable注解的同名参数上,即入参后userId=123、topicId=456。
@CookieValue用于将请求的Cookie数据映射到功能处理方法的参数上。 
public String test(@CookieValue(value="JSESSIONID", defaultValue="") String sessionId)
public String test2(@CookieValue(value="JSESSIONID", defaultValue="") Cookie sessionId)
如上配置将自动将JSESSIONID 值入参到sessionId 参数上,defaultValue 表示Cookie 中没有JSESSIONID 时默认 为空。
@RequestHeader 用于将请求的头信息区数据映射到功能处理方法的参数上。
@RequestMapping(value="/header")
public String test( @RequestHeader("User-Agent") String userAgent, @RequestHeader(value="Accept") String[] accepts)
如上配置将自动将请求头“User-Agent”值入参到userAgent 参数上,并将“Accept”请求头值入参到accepts参数上。
@RequestHeader 也拥有和@RequestParam相同的三个参数,含义一样。
@ModelAttribute一个具有如下三个作用:
①绑定请求参数到命令对象:放在功能处理方法的入参上时,用于将多个请求参数绑定到一个命令对象,从而简化绑 定流程,而且自动暴露为模型数据用于视图页面展示时使用; 
②暴露表单引用对象为模型数据:放在处理器的一般方法(非功能处理方法)上时,是为表单准备要展示的表单引用
对象,如注册时需要选择的所在城市等,而且在执行功能处理方法(@RequestMapping 注解的方法)之前,自动添加 到模型对象中,用于视图页面展示时使用; 
③暴露@RequestMapping 方法返回值为模型数据:放在功能处理方法的返回值上时,是暴露功能处理方法的返回值为 模型数据,用于视图页面展示时使用。
32.暴露表单引用对象为模型数据
@ModelAttribute("cityList")
public List<String> cityList() {
return Arrays.asList("北京", "山东");
}
如上代码会在执行功能处理方法之前执行,并将其自动添加到模型对象中,在功能处理方法中调用Model 入参的 containsAttribute("cityList")将会返回true。
如果同一个Controller中有同名的命令对象,那Spring Web MVC内部如何处理的呢:
(1)首先执行@ModelAttribute 注解的方法,准备视图展示时所需要的模型数据;@ModelAttribute 注解方法形式参 数规则和@RequestMapping规则一样,如可以有@RequestParam等; 
(2)执行@RequestMapping 注解方法,进行模型绑定时首先查找模型数据中是否含有同名对象,如果有直接使用,如果 没有通过反射创建一个,因此②处的user将使用①处返回的命令对象。即②处的user等于①处的user。
(3)@ModelAttribute 注解的返回值会覆盖@RequestMapping 注解方法中的@ModelAttribute 注解的同名命令对 象。
32.有时候我们需要在多次请求之间保持数据,一般情况需要我们明确的调用HttpSession的API来存取会话数据,如多步 骤提交的表单。Spring Web MVC提供了@SessionAttributes进行请求间透明的存取会话数据。
//1、在控制器类头上添加@SessionAttributes注解
@SessionAttributes(value = {"user"}) //①
public class SessionAttributeController
//2、@ModelAttribute注解的方法进行表单引用对象的创建
@ModelAttribute("user") //②
public UserModel initUser()
//3、@RequestMapping注解方法的@ModelAttribute注解的参数进行命令对象的绑定
@RequestMapping("/session1") //③
public String session1(@ModelAttribute("user") UserModel user)
//4、通过SessionStatus的setComplete()方法清除@SessionAttributes指定的会话数据
@RequestMapping("/session2") //③
public String session(@ModelAttribute("user") UserModel user, SessionStatus status) {
if(true) { //④
status.setComplete();
}
return "success";
}
33.@Value用于将一个SpEL表达式结果映射到到功能处理方法的参数上。
public String test(@Value("#{systemProperties['java.vm.version']}") String jvmVersion)
34.在 Spring3 之前,我们使用如下架构进行类型转换、验证及格式化
流程:
①:类型转换:首先调用PropertyEditor 的setAsText(String),内部根据需要调用setValue(Object)方法进行设置转换后 的值; 
②:数据验证:需要显示调用Spring的Validator 接口实现进行数据验证;
③:格式化显示:需要调用PropertyEditor 的getText 进行格式化显示。
使用如上架构的缺点是:
(1)PropertyEditor 被设计为只能String<——>Object 之间转换,不能任意对象类型<——>任意类型,如我们常见的
Long时间戳到Date类型的转换是办不到的;
(2)PropertyEditor 是线程不安全的,也就是有状态的,因此每次使用时都需要创建一个,不可重用;
(3)PropertyEditor 不是强类型的,setValue(Object)可以接受任意类型,因此需要我们自己判断类型是否兼容;
(4)需要自己编程实现验证,Spring3支持更棒的注解验证支持;
(5)在使用SpEL表达式语言或DataBinder 时,只能进行String<--->Object之间的类型转换;
(6)不支持细粒度的类型转换/格式化,如UserModel 的registerDate 需要转换/格式化类似“2012-05-01”的数据,
而OrderModel 的orderDate 需要转换/格式化类似“2012-05-01 15:11:13”的数据,因为大家都为java.util.Date
类型,因此不太容易进行细粒度转换/格式化。
在 Spring Web MVC环境中,数据类型转换、验证及格式化通常是这样使用的:
流程:
①、类型转换:首先表单数据(全部是字符串)通过WebDataBinder 进行绑定到命令对象,内部通过PropertyEditor 实现; 
②:数据验证:在控制器中的功能处理方法中,需要显示的调用Spring的Validator实现并将错误信息添加到BindingResult 对象中; 
③:格式化显示:在表单页面可以通过如下方式展示通过PropertyEditor格式化的数据和错误信息:
35.从Spring3 开始,我们可以使用如下架构进行类型转换、验证及格式化:
流程:
①:类型转换:内部的ConversionService会根据S源类型/T目标类型自动选择相应的Converter SPI进行类型转换,而 且是强类型的,能在任意类型数据之间进行转换; 
②:数据验证:支持JSR-303验证框架,如将@Valid 放在需要验证的目标类型上即可;
③:格式化显示:其实就是任意目标类型---->String 的转换,完全可以使用Converter SPI完成。
Spring为了更好的诠释格式化/解析功能提供了Formatter SPI,支持根据Locale信息进行格式化/解析,而且该套SPI可 以支持字段/参数级别的细粒度格式化/解析,流程如下: 
①:类型解析(转换):String---->T类型目标对象的解析,和PropertyEditor 类似;
③:格式化显示:任意目标类型---->String的转换,和PropertyEditor 类似。
在Spring Web MVC环境中,数据类型转换、验证及格式化通常是这样使用的:
①、类型转换:首先表单数据(全部是字符串)通过WebDataBinder 进行绑定到命令对象,内部通过Converter SPI 实现; 
②:数据验证:使用JSR-303验证框架进行验证;
③:格式化显示:在表单页面可以通过如下方式展示通过内部通过Converter SPI格式化的数据和错误信息:
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
//1、格式化单个命令/表单对象的值(好像比较麻烦,真心没有好办法)
<spring:bind path="dataBinderTest.phoneNumber">${status.value}</spring:bind>
//2、<spring:eval>标签,自动调用ConversionService并选择相应的Converter SPI进行格式化展示
<spring:eval expression="dataBinderTest.phoneNumber"></spring:eval>
如 上代码能工作的前提是在RequestMappingHandlerMapping 配置了 ConversionServiceExposingInterceptor , 它的作用是暴露conversionService 到请求中以便如 <spring:eval>标签使用。
//3、通过form标签,内部的表单标签会自动调用命令/表单对象属性对应的PropertyEditor进行格式化显示
<form:form commandName="dataBinderTest">
<form:input path="phoneNumber"/><!-- 如果出错会显示错误之前的数据而不是空-->
</form:form>
//4、显示验证失败后的错误信息
<form:errors></form:errors>
36.类型转换器:提供类型转换的实现支持
一个有如下三种接口:
(1)Converter:类型转换器,用于转换S类型到T类型,此接口的实现必须是线程安全的且可以被共享。
(2)GenericConverter 和ConditionalGenericConverter:GenericConverter 接口实现能在多种类型之间进行转换,ConditionalGenericConverter 是有条件的在多种类型之间进行转换。
(3)ConverterFactory:工厂模式的实现,用于选择将一种S源类型转换为R类型的子类型T的转换器的工厂接口。
37.类型转换器注册器、类型转换服务:提供类型转换器注册支持,运行时类型转换API支持。
一共有如下两种接口:
(1)ConverterRegistry:类型转换器注册支持,可以注册/删除相应的类型转换器。
(2)ConversionService:运行时类型转换服务接口,提供运行期类型转换的支持
如果我同时使用PropertyEditor 和ConversionService,执行顺序是什么呢?内部首先查找 PropertyEditor 进行类型转换,如果没有找到相应的PropertyEditor 再通过ConversionService进行转换。
38.数据格式化
Spring3 引入了格式化转换器(Formatter SPI) 和格式化服务API (FormattingConversionService)从而支持这种需求。在Spring中它和PropertyEditor 功能类似,可以替代PropertyEditor 来进行对象的解析和格式化,而且支持细粒度的字段级别的格式化/解析。 
Formatter SPI核心是完成解析和格式化转换逻辑,在如Web应用/客户端项目中,需要解析、打印/展示本地化的对象值 时使用,如根据Locale信息将java.util.Date---->java.lang.String打印/展示、java.lang.String---->java.util.Date等。 
该格式化转换系统是Spring通用的,其定义在org.springframework.format包中,不仅仅在Spring Web MVC场景下。
1)格式化转换器:提供格式化转换的实现支持。
一共有如下两组四个接口:
(1)Printer接口:格式化显示接口,将T 类型的对象根据Locale信息以某种格式进行打印显示(即返回字符串形式);
(2)Parser接口:解析接口,根据Locale信息解析字符串到T类型的对象;
(3)Formatter接口:格式化SPI接口,继承Printer 和Parser 接口,完成T类型对象的格式化和解析功能;
(4)AnnotationFormatterFactory接口:注解驱动的字段格式化工厂,用于创建带注解的对象字段的Printer 和Parser, 即用于格式化和解析带注解的对象字段。
2)格式化转换器注册器、格式化服务:提供类型转换器注册支持,运行时类型转换API支持。
一共有如下两种接口:
(1)FormatterRegistry:格式化转换器注册器,用于注册格式化转换器(Formatter、Printer 和Parser、 AnnotationFormatterFactory);
(2)FormattingConversionService:继承自ConversionService,运行时类型转换和格式化服务接口,提供运行期类型 转换和格式化的支持。
不同于Convert SPI,Formatter SPI可以根据本地化(Locale)信息进行解析/格式化。
39.使用内置的注解进行字段级别的解析/格式化:
了Spring字段级别解析/格式化的两个内置注解:
@Number:定义数字相关的解析/格式化元数据(通用样式、货币样式、百分数样式),参数如下:
style:用于指定样式类型,包括三种:Style.NUMBER(通用样式) Style.CURRENCY(货币样式) Style.PERCENT (百分数样式),默认Style.NUMBER; 
pattern:自定义样式,如patter="#,###";
@DateTimeFormat:定义日期相关的解析/格式化元数据,参数如下:
pattern:指定解析/格式化字段数据的模式,如”yyyy-MM-dd HH:mm:ss”
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),默认ISO.NONE; 
style : 指定用于格式化的样式模式, 默认“ SS ”, 具体使用请参考Joda-Time 类库的 org.joda.time.format.DateTimeFormat的forStyle的javadoc; 
优先级: pattern 大于iso  大于style。
40.声明式数据验证
Spring3开始支持JSR-303验证框架,JSR-303支持XML风格的和注解风格的验证,接下来我们首先看一下如何和Spring 集成。
(1)添加jar包:
此处使用Hibernate-validator 实现(版本:hibernate-validator-4.3.0.Final-dist.zip),将如下jar 包添加到classpath
(WEB-INF/lib 下即可):
dist/lib/required/validation-api-1.0.0.GA.jar JSR-303 规范API包
dist/hibernate-validator-4.3.0.Final.jar Hibernate 参考实现 
(2)在Spring 配置总添加对JSR-303验证框架的支持
此处使用Hibernate validator 实现:
validationMessageSource属性:指定国际化错误消息从哪里取,此处使用之前定义的messageSource来获取国际化消息; 如果此处不指定该属性,则默认到classpath下的ValidationMessages.properties 取国际化错误消息。 
<!-- 以下validator ConversionService 在使用mvc:annotation-driven 会自动注册-->
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
<!-- 如果不加默认到使用classpath下的ValidationMessages.properties -->
<property name="validationMessageSource" ref="messageSource"/>
</bean>
通过 ConfigurableWebBindingInitializer 注册validator: 
<bean id="webBindingInitializer"
class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"/>
<property name="validator" ref="validator"/>
</bean>

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics