–> go to 总目录
Servlet API
和Spring。
分发器。像大多数web框架一样,围绕着前置controller模式,指一个中心的 Servlet(DispatcherServlet),提供对请求处理的分享算法,真实的工作交给配置的组件。这种模式是灵活和支持分流。
核心的DispatcherServlet
需要使用java配置或者web.xml
来配置。反过来DispatcherServlet
使用Spring的配置来发现他委托的组件:mapping,view resolution,exception handling处理等。
使用java配置注册和初始化DispatcherServlet
。
分发器
DispatchServlet希望WebApplicationContext(从Application扩展)
有自己的配置。WebApplicationContext
有对ServletContext
和Servlet
的链接。同时也会被绑定到ServletContext
,以便于RequestContextUtils
静态方法反向找到WebApplicationContext。
对于很多应用来说一个独立的WebApplicationContext
就够了。但是也有可能有一个层次化的context结构,一个root WebApplicationContext被多个DispatcherServlet(或者其他Servlet)
共享,每一个都拥有子WebApplicationContext
配置。
root WebApplicationContext
典型的包含基础设施bean,例如
data repositories 和 business services,需要被多个servlet共享。这些bean可以被有效的复用和重用,典型的每个Servlet拥有本地版的bean。
层次图
等效的xml配置
DispatcherServlet
委托给特殊的bean去处理request和提供合适的response。这里的特殊bean指的是被Spring-managed管理的的实例,也实现Spring框架,这些类通常是自带的,但是你也可以去自定义。
bean type | 解释 |
---|---|
HandlerMapping | 映射一个request到一个handler,且拥有一堆链式的拦截器pre-和post-。映射是基于一些准则,但是各自的实现有很大差异。两个主要的HandlerMapping实现是RequestMappingHandlerMapping (支持@requestMapping)和SimpleUrlHandlerMapping (对URI path有明确的要求) |
HandlerAdapter | 帮助DispatchServlet去调用Handler(当请求来的时候),无视真实的handler是如何调用的。这个类的主要目的是帮助DispatcherServlet无需关注调用handler的实现细节 |
HandlerExceptionResolver | 解决异常的策略,有可能将异常路由到handler,到HTML的错误*(如404,500页面) |
ViewResolver | 解决将String-based viewname对应到真实的view页面作为响应 |
LocaleEsolver,localContextResolver | 解决本地化的client端提供一个时间域,然后提供国家化的视图 |
ThemeResolver | 解决你web应用的主题 |
MultipartResolver | 解析分片请求multi-part request(比如brower 格式化 文件上传) |
FlashMapManager | 存储和解析"input"和"output",flashMap可以将一个请求的属性传递给另外一个 |
应用可以声明基础设施bean如上面1.1.2所列的来处理请求。DispatcherServlet会为每个special bean来检查WebApplicationContext。如果没有匹配的bean类型,他会使用DispatcherServlet.properties配置默认标识的类型。
大多数场景,mvc config是最佳的开始。他用java或者xml提供一个high-level的配置。
Servlet 3.0+,你可以用是用代码或者web.xml来配置Servlet 容器。下列示例注册一个DispatcherServlet
。
WebApplicationInitializer
是Spring MVC提供的一个接口,确保你的实现能被检测到,并自动应用到Servlet 3容器。一个WebApplicationInitializer
的抽象实现是AbstractDispatcherServletInitializer
让你更容易的注册DispatcherServlet
通过覆盖指定的方法。
use Java-based的配置推荐如下模板
如果你是用XML-based的Spring 配置,你应该是用AbstractDispatcherServletInitializer
,如下
AbstractDispatcherServletInitializer
也提供添加Filter实例,自动会添加到DispatcherServlet
。
DispatchServlet处理请求的流程如下
WebApplicationContext
被搜索并作为一个属性绑定到request中去,会被controller和其他process中元素使用到。默认会被绑定到 DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
key下Resolver
被绑定到request上,去解决本地处理请求需要使用的资源(渲染 view,准备数据等等)。如果不需要本地Resolver
,那么你就不需要这一层,。MultipartHttpServletRequest
中,为proccess的其他元素提供进一步的处理。被声明在WebApplicationContext
中的HandlerExceptionResolver
bean,被用来解决处理request proceesing的异常。这个resolver可以被自定义
Spring的DispatcherServlet支持返回last-modification-date
(最后修改日期),由于Sevelet 的具体API。对于一个具体 的request,process支持侦测最后一次的修改日期:这DispatcherServlet寻找合适嗯handler(实现LastModified)。如果找到了LastModified
中getLastModified(request)
方法被返回给client。
你可以自定义分离的DispatcherServlet
实例,通过添加到Servelt初始化参数(init-param elements)到web.xml中去。下列的表列举了被支持的参数
HandlerMapping
的实现支持handler interceptors是十分有用的,当你想为request应用一些特殊的规则-例如检查。Interception必须实现org.springframework.web.servlet
中的HandlerInterceptor
,其包含了三个灵活的方法:
preHandle(…)返回一个boolean用来确定,是否继续执行下来的调用链。true执行,false中断。
postHandle(…)很少被用到。是用@ResponseBody和ResponseEntity方法时,response在HandlerAdapte内已经被提交或者写入,意味着做任何更改太迟了—比如添加extra header。
对于这种情况,你可以实现ResponseBodyAdvice
然后声明一个Controller Advice bean
,直接配置在RequestMappingHandlerAdapter
中
如果在request mapping过程比如 在一个@Controller中发生异常了,DispatcherServlet
会委托链式的HandlerExceptionResolver的bean去处理异常,也提供默认的处理,通常是erorr response.
resolver的实现
你可以通过声明多个HandlerExceptionResolver
来构成异常链,在你的spring配置里,并且设置它的order
属性。order的序号越大,resolver就会被放到越后面。
HandlerExceptionResolver具体会返回这些内容
error page的返回
声明的error page mapping
以上的配置会被映射到controler逻辑
Spring MVC定义了ViewResolver和view接口,提供渲染逻辑。ViewResolver提供viewname和真实views映射的能力。view路由到数据的准备到具体的view技术。
ViewResolver的实现
ViewRsolver | Description |
---|---|
AbstractCachingViewResolver | AbstractCachingViewResolver的子类,负责缓存view实例,缓存提升了查询性能。你可以设置属性cache 为false来关闭。如果你在runtime必须刷新一个特定的view,你可以使用removeFromCache(String viewName, Locale loc) method. |
XmlViewResolver | 实现ViewResolver,来接受xml配置。默认的配置文件位置是/WEB-INF/views.xml |
ResourceBundleViewResolver | 实现ViewResolver,来接受bean的定义在ResourceBundle ,这个bundle是基于name的。对于每个需要支持的view,需要配置[viewname].(clss) 和[viewname].url 。 |
UrlBasedViewResolver | ViewResolver的简单实现,处理view name到urls的映射,无需清晰的定义。这种方式适用于你的viewname,匹配你的view resource,但是不能产生二义性,找到多个匹配 |
InternalResourceViewResolver | UrlBasedViewResolver的便利子类,支持InternalResourceView (Servlets and JSPs)。其子类有JstlView and TilesView。你可以细化这个view类去生成所有views,通过是用setViewClass(..) |
FreeMarkerViewResolver | UrlBasedViewResolver的便捷子类,去支持FreeMarkerView |
ContentNegotiatingViewResolver | 实现ViewResolver接口,基于request的file name或者 Acceprt header属性 |
你可以链式的声明view resolvers,设置order属性可以排序,越小越执行。
ViewResolver约定,当未找到view可以返回一个null。但是在JSPs和InteralResourceViewResolver,去判定JSP是否存在的唯一方式是通过RequestDispatcher
去做分发。因此你必须在relover列表的最后配置InternalResourceViewResolver
。
配置view解决方案和添加ViewResolver 一样容易,详见config篇。
重定向细节:view name的前缀让你实现重定向。URLBaseViewResolver
用前缀来判定是否需要重定向。其余的的重定向URL。
网络形象是是否返回RedirectView
的原因之一,但是现在可以依赖自己的prefix来判定是否需要去重定向例如(redirect:/myapp/some/resource
)重定向到了当前的servlet的context,当一个名称例如redirect:https://myhost.com/some/arbitrary/path
。
注意如果controller如果带有@ResponseStatus
,注解的值会优先于RedirectView。
转向forward:
,UrlBasedViewResolver
可以解析。这会创建一个InternalResourceView
,其做了一个定向RequestDispatcher.forward()
。因此不用
InternalResourceViewResolver
和InternalResourceView
(for JSPS),但是仍旧有用。
ContentNegotiatingViewResolver
不能解决views但是可以委托其他 view resolvers和选择这些view。这个委托可以从Accept
header接受一个查询参数(例如"/path?format=pdf")
这个ContentNegotiatingViewResolver
选择合适的View
去处理request,比如Content-type
字段,ContentNegotiatingViewResolver
支持Content-type
和ViewResolvers
的绑定。处理请求时会命中第一个ViewResolver
,命中不了时,会返回DefaultViews
。随后的操作是SingleTon模式的View
进行渲染。
Accept Header
可以包含模糊匹配
比如text/*
。
本地化,相对的是国际化。DispatcherServlet让你可以自动解决本地客户端的locale化。这部分是由LocaleResolver
对象来解决的。
当request来时,DispatcherServlet去寻找local resolver,如果发现了就使用。通过使用RequestContext.getLocale()方法,你总是可以获取到本地resolver。
额外的本地化方案,你可以向handler mapping 添加额外的intercepeter去处理本地化需求。
本地化的解决包是在org.springframework.web.servlet.i18n
而且配置你的应用容器用一种普通的方式。下列是Spring包含的几种resolver。
获取client的本地化,指导它的time zone十分有用。LocaleContextResolver接口提供一个对LocaleResolver的扩展–让resolver提供一个丰富的LocaleContext
。
TimeZone
可以通过使用RequestContext.getTimeZone()
方法获取。Time zone的信息会自动被 Date/Time的 Cpnverter和Formatter的对象所注册到。
local resolver 侦测到在request中accept-language
的header。通常,header 的field会包含client端本地的os系统。注意resolver不能支持time zone信息。
本地的resolver侦测到Cookie去看Local和TimeZone是否被细化。他使用具体的细节。通过使用本地resolver的属性,你可以细化这个cookie得名称和最大时长,下列是一个例子。
Session Resolver让你可以从session中获取Locale
和TimeZone
,这些可以被包含在用的请求里。和CookieLocaleResolver的差异是,这个策略本地化的选择本地setting在 Servlet container的HttpSession容器里。结果是设置只会应用到每一个session中,因此,当session结束时就会丢失。
注意无需直接和额外的session管理组件。SessionLocalResolver是和HttpSession属性一同关联在HttpServletRequest。
你可以通过添加LocaleChangeInterceptor
到一个HandlerMapping
定义中去开启本地化的更改。开启后会侦测在request中的参数来直接更改本地化,即会调用在LocaleResolver
中的setLoacle
方法。
示例中展示调用*.view
的资源,其包含了参数siteLanguage
。所以示例中
主题的设置。theme是一系列静态资源的集合,典型的是style sheets和images,这些会影响应用的风格。
去给你的Web应用使用主体,你必须去实现org.springframework.ui.context.ThemeSource
接口。WebApplicationContext
接口扩展了ThemeSource,但是委托给一个具体的实现。默认是org.springframework.ui.context.support.ResourceBundleThemeSource
实现去加载properties文件(从classpath的root)。去使用自定义的ThemeSource
或者去配置一个基于ResourceBundleThemeSource
,你可以是用名称注册到Context中,Web application context会自动容器里并去使用。
当你使用ResourceBundleThemeSource
的时候,主题会定义在一个简单的properties文件。
例如
properties的key-values,会关联到view code中去。
默认ResourceBundleThemeSource
会是用空的basename前缀。结果是properties文件会从classpath的root的去加载。因此,cool.properties主体文件放在root下就可以,例如/WEB-INF/classes
。ResourceBundleThemeSource
会使用标准的java源文件去加载组件,允许全国际化的主题。
例如/WEB-INF/classes/cool_nl.properties
会被引用到一个特殊的本经图片。
如果你如前面定义了这些theme。DispatcherServlet会寻找bean名为themeResolver
的bean,然后找出是用哪一个ThemeResolver
。A theme resolver和LocaleResolver
工作方式一样。从request中去侦测主题的选定
分片 resolver。
MultipartResolver
在org.springframework.web.multipart
package中,在上传文件的时候去解析多片的请求。有 Commons FileUpload
和基于Servlet 3.0
的请求。
去开启多分片传输,你需要在DispatcherServlet中声明
MultipartResolver
bean,名称为multipartResolver
。DispatcherServlet会侦测并把它应用到即将到来的request。
当POST并使用multipart/form-data
,当前的resover 会解析并包裹HttpServletRequest
为MultipartHttpServletRequest
去解决分片。
使用Commons FileUpload,你可以配置CommonsMultipartResolver
名为multipartResolver
的bean。你也需要去添加这个依赖。
Servlet 3.0的分片穿出需要在Servlet container的配置中打开。
DEBUG级别的日志在Spring MVC被设置成友好的方式,聚焦于有价值的信息。
TRACE级别的设置原则和DEBUG级别基本一样。但是被用在打印任何输出。
DEBUG 和 TRACE 也许会打印敏感数据。这个为什么header和参数会被默认掩盖,但是你也可以开启他,通过在DispatcherServlet设置enableLoggingRequestDetails