文档简略翻译1

Spring MVC
文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc

Spring Web MVC (Spring MVC) 是一套以 Servlet API 为基础平台的优雅的 Web
框架,一直是 Spring Framework 中重要的一个组成部分。 正式名称 “Spring
Web MVC” 来自其源模块 spring-webmvc 的名称,但它通常被称为“Spring MVC”。

1. Spring Web MVC

Spring MVC是基于Servlet API和Spring框架构建的项目,同时,Spirng
WebFlux是支持反应式web构建的框架。

DispatcherServlet用于分发请求,实际的请求处理工作由其他组件处理。

DispatcherServlet可以使用Java代码或者在web.xml中配置。其需要处理的工作有:请求映射、视图处理、异常处理等。

如下代码是DispatcherServlet的注册和初始化,该类会自动被Servlet容器检测到。

public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletCxt) { // Load Spring web application configuration AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext(); ac.register(AppConfig.class); ac.refresh(); // Create and register the DispatcherServlet DispatcherServlet servlet = new DispatcherServlet; ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet); registration.setLoadOnStartup; registration.addMapping; }}

如下是web.xml中DispatcherServlet的注册和初始化配置。

<web-app> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/app-context.xml</param-value> </context-param> <servlet> <servlet-name>app</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app</servlet-name> <url-pattern>/app/*</url-pattern> </servlet-mapping></web-app>

与 Spring Web MVC 并行,Spring Framework 5.0 引入了一个 Reactive stack
—— Web框架,其名称 Spring WebFlux 也基于它的源模块 spring-webflux。

1.2.1. Context层次结构

DispatcherServlet依赖WebApplicationContext进行配置。多个DispatcherServlet可以共用一个WebAplicationContext实例。Root
WebApplicationContext包括数据服务bean,业务服务bean等,而Servlet
WebpplicationContext仅包含特定servlet处理bean。

图片 1image

如下是WebApplicationContext的配置示例:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?[] { RootConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?[] { App1Config.class }; } @Override protected String[] getServletMappings() { return new String[] { "/app1/*" }; }}

如果不需要应用上下文,只需要使用getRootConfigClasses()返回配置并且getServletConfigClasses()返回null即可。

对应的web.xml如下:

<web-app> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/root-context.xml</param-value> </context-param> <servlet> <servlet-name>app1</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/app1-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app1</servlet-name> <url-pattern>/app1/*</url-pattern> </servlet-mapping></web-app>

如果应用不需要上下文,仅需要配置root上下文并设置contextConfigLocation参数为空。

与许多其他 Web 框架一样,Spring MVC 同样围绕前端页面的控制器模式
(Controller) 进行设计,其中最为核心的 Servlet —— DispatcherServlet
为来自客户端的请求处理提供通用的方法,而实际的工作交由可自定义配置的组件来执行。
这种模型使用方式非常灵活,可以满足多样化的项目需求。

1.2.2. 特殊Bean类型

DispatcherServlet委派特殊Bean处理请求并返回相应。如下是DispatcherHandler能够检测的特殊Bean:1.HandlerMapping:映射请求到Handler,有两个实现:RequestMappingHandlerMapping和SimpleUrlHandlerMapping。2.HandlerAdapter:用于帮助DispatcherServlet调动handler。3.HandlerExceptionResolver:解决映射异常,html错误视图等。4.VieResolver:主要作用是把一个逻辑上的视图名称解析为一个真正的视图,SpringMVC中用于把View对象呈现给客户端的是View对象本身,而ViewResolver只是把逻辑视图名称解析为对象的View对象。4.LocaleResolver、LocaleContextResolver:国际化资源处理。5.ThemeResolver:主题处理,可以个性化主题处理。6.MultipartResolver:处理multi-part
request,如上传等。7.FlashMapManager:存储FlashMap,用于处理重定向问题。

和任何普通的 Servlet 一样,DispatcherServlet 需要根据 Servlet 规范使用
Java 代码配置或在 web.xml 文件中声明请求和 Servlet 的映射关系。
DispatcherServlet 通过读取 Spring
的配置来发现它在请求映射,视图解析,异常处理等方面所依赖的组件。

1.2.3. Web MVC配置

应用可以声明上述特殊bean来处理对应的请求。DispatcherServlet会检查WebApplicationContext,如果没有发现特殊bean,将返回DispatcherServlet.properties中定义的默认类型bean。

以下是注册和初始化 DispatcherServlet 的 Java 代码配置示例。 该类将被
Servlet 容器自动检测到:

1.2.4. Servlet配置

在Servlet
3.0+环境中,支持在代码中和web.xml中配置servlet。如下是注册DispacherServlet的例子:

import org.springframework.web.WebApplicationInitializer;public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) { XmlWebApplicationContext appContext = new XmlWebApplicationContext(); appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml"); ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext)); registration.setLoadOnStartup; registration.addMapping; }}

继承WebApplicationInitializer保证你的servlet被Servlet3容器加载。AbstractDispatcherServletInitializer是WebApplicationInitializer的抽象类,它通过重写方法来简化Servlet的配置。

下面是推荐的基于Java的应用配置方法:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return null; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { MyWebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; }}

如果使用基于XML的配置,就应该直接扩展AbstractDispatcherServletInitializer。

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { @Override protected WebApplicationContext createRootApplicationContext() { return null; } @Override protected WebApplicationContext createServletApplicationContext() { XmlWebApplicationContext cxt = new XmlWebApplicationContext(); cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml"); return cxt; } @Override protected String[] getServletMappings() { return new String[] { "/" }; }}

AbstractDispatcherServletInitializer也提供简单的方法添加Filer实例。

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { // ... @Override protected Filter[] getServletFilters() { return new Filter[] { new HiddenHttpMethodFilter(), new CharacterEncodingFilter() }; }}

AbstractDispatcherServletInitializer的isAsyncSupported保护方法提供
异步支持,默认设置为true。

如果想自定义DispatcherServlet,重写createDispatcherServlet方法。

public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletCxt) { // 加载 Spring Web Application 的配置 AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext(); ac.register(AppConfig.class); ac.refresh(); // 创建并注册 DispatcherServlet DispatcherServlet servlet = new DispatcherServlet; ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet); registration.setLoadOnStartup; registration.addMapping; }}
1.2.5. Processing

DispatcherServlet处理请求流程如下:1.查找WebApplicationContext并将其作为属性和请求绑定以便使用。2.绑定local
resolver到请求处理资源国际化,可以不使用。3.绑定theme
resolver到请求处理主题,可以不使用。4.如果设定了multipart
resolver并发送了multipart请求,请求的内容采用MultipartHttpServletRequest包装以便后续处理5.查找匹配的handler,找到后顺序执行:preprocessors/postprocessors/controllers。6.查找模型,找到则渲染视图,找不到则不渲染视图。

WebApplicationContext中的HandlerExceptionResolver用于处理异常请求。支持自定义异常处理。

DispatcherServlet也支持返回上次修改日期,其流程为:DispatcherServlet查找对应的映射处理器并检查该处理器是否实现LastModified接口,如果继承该接口,通过方法long
getLastModified返回上次修改时间值给客户端。

你可以通过添加Servlet初始化参数(init-param)在web.xml中自定义DispatcherServlet。下面是支持的初始化参数:1.contexClass:继承自WebApplicationContext,实力化Servlet使用的上下文,默认使用XmlWebApplicationContext。2.contextConfigLocation:上下文配置文件路径,支持多个路径配置多个上下文,对于在不同路径配置文件中重复定义的bean,以最后的定义为准。3.namespace:WebApplicationContext的命名空间,默认[servlet-name]-servlet。

以下是在 web.xml 中注册和初始化 DispatcherServlet 的方法:

1.2.6. 拦截器

所有映射处理器都支持拦截器,用于对请求添加特殊处理。拦截器需要实现org.springframework.web.servlet包下的HandlerInterceptor接口的三个方法:1.preHandler-handler执行前处理2.postHandler-handler执行后处理3.afterCompletion-handler处理完成之后执行preHandler方法返回布尔值,你可以通过该函数打断或者继续handler的处理流程。true继续执行,false不继续执行接下来的拦截器或者handler。

<web-app> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <!-- Spring 上下文的配置 --> <param-value>/WEB-INF/app-context.xml</param-value> </context-param> <servlet> <servlet-name>app</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app</servlet-name> <!-- "/*" 表示将所有请求交由 DispatcherServlet 处理 --> <url-pattern>/*</url-pattern> </servlet-mapping></web-app>
1.2.7. 异常

如果在请求映射或者处理时发生异常,DispatcherServlet委托HandlerExceptionResolver解决异常,例如准备错误页面等。

下面是HandlerExceptionResolver的实现类:1.SimpleMappingExceptionResolver:异常类与错误视图名称的映射,用于在浏览器中渲染错误页面。2.DefaultHandlerExceptionResolver:处理异常并将其映射成HTTP错误码。3.ResponseStatusExceptionResolver:使用@ResponseStatus注解处理异常并映射为HTTP错误码。4.ExceptionHandlerExceptionResolver:在使用@Controller和@ControllerAdvice注解的类种,通过@ExceptionHandler注解处理异常。

异常处理过程:设置多个异常处理resolver,如果需要,设置resolver的优先级,优先级越高,执行的越晚。

HandlerExceptionResolver约定返回内容如下:1.指向错误页面的ModeAndView。2.如果异常在resolver中被处理,返回空的ModeAndView。3.如果异常无法处理,返回null后继续下一个resolvers;如果均无法处理,异常抛给Servlet容器。

异常处理的配置就是在spring配置中添加HandlerExceptionesolver。对于Spring
MVC的异常,使用@ResponseStatus注解的异常和@ExceptionHandler方法注解的异常,MVC配置自动声明内置的异常处理器。

容器中的错误页面如果HandlerExceptionResolver依然无法处理异常或者响应错误码是4xx,5xx,Servlet容器会呈现一个错误页面。自定义容器的错误页面,需要在web.xml
中进行如下定义。

<error-page> <location>/error</location></error-page>

当由servlet容器处理异常或者错去码是4xx或者5xx时,servlet容器根据配置的
url分发错误。然后DispatcherServlet可以通过@Controller映射处理返回异常视图名称,如下:

@RestControllerpublic class ErrorController { @RequestMapping(path = "/error") public Map<String, Object> handle(HttpServletRequest request) { Map<String, Object> map = new HashMap<String, Object>(); map.put("status", request.getAttribute("javax.servlet.error.status_code")); map.put("reason", request.getAttribute("javax.servlet.error.message")); return map; }}

DispatcherServlet 依赖于一个 WebApplicationContext(对普通
ApplicationContext 的功能扩展)来实现自己的配置。 WebApplicationContext
中包含了一个指向它所关联的 ServletContext 和 Servlet 的链接。
它同时还绑定到 Servlet 上下文中,以便应用程序可以使用
RequestContextUtils 中的静态方法在 WebApplicationContext
进行查找,来判断是否需要调用 DispatcherServlet 中的方法。

1.2.8. 视图

Spring
MVC定义ViewResolver和View放假鹅口来处理视图。ViewResolver定义名和实际视图的映射,View用于展示视图之前的数据准备。下面是ViewResolver的类层次结构:1.AbstractCachingViewResolvre:用于缓存处理的视图实例。缓存可以提升性能,可以将cache属性设置为false来关闭缓存。如果必须刷新缓存,可以调用removeFromCache(String
viewName, Locale
loc)方法。2.XmlViewResolver:实现ViewResolver接口,采用xml的配置方式,默认配置文件是/WEB-INF/view.xml。3.ResourceBundleViewResolver:实现ViewResolver接口,使用ResourceBundle读取配置文件中视图类和视图的映射关系。配置文件中配置方式为:[viewname].指定视图类,[viewname].url指定视图。4.UrlBasedViewResolver:简单实现ViewResolver接口,关联逻辑视图名与url,不使用明确的视图定义。5.InternalResourceViewResolver:UrlBaseViewResolver的子类,支持InternalResourceView/JstlView和TilesView。6.FreeMarkerViewResolver:UrlBasedViewResolver的子类,支持FreeMarkerView视图处理。7.ContentNegotiatingViewResolver:实现ViewResolver接口,用于根据请求名或者Accep请求消息头类型处理视图。

处理流程:可以设置多个resolver组成视图处理链,甚至可以设置处理的优先级。记住,优先级越高,越晚执行。

ViewResolver返回null表示视图未找到。在处理jsp时,InternalResourceViewResolver一定要设置为最后处理的resolver。下文会介绍ViewResolver的配置。

重定向:特殊的重定向:通过视图名的前缀进行重定向。UrlBaseViewResolver识别前缀然后将前缀后的内容作为重定向的地址。

控制器Controller返回RedirectView也是重定向。例如,逻辑视图名:redirect:/myapp/some/resource基于当前上下文重定向相对路径,而redirect:

如果控制器的方法使用@ResponseStatus注解,那么注解值优先于RedirectView设置的响应值。

转发:UrlBasedViewResolver可以根据视图名处理转发。通过创建InternalResourceView执行RequestDispatcher.forward()。这样对于InternalResourceViewResolver和InternalResourceView而言前缀失效,不进行重定向而进行转发。

内容协商:协商返回的数据格式。ContentNegotiatingViewResolver不直接处理view,而是委托给其他符合客户端请求格式的resolver。检测Accept消息头中的数据格式或者从参数(如/path?form=pdf)中提取格式。ContentNegotiatingViewResolver通过比较media
type(就是Content-Type)来选取合适的视图处理。如果没有找到对应的,使用DefaultView。Accept消息头可以设置统配,例如text/*可以匹配到text/xml的视图处理。

对于只有一个 WebApplicationContext 应用程序来说,这已经可以满足使用了。
同时也可以使用具有层次结构的上下文,其中有一个根上下文 被多个
DispatcherServlet(或其他普通
Servlet)实例所共享,每个实例都有属于自己的子上下文配置。

1.2.9. 国际化资源

DispatcherServlet支持根据客户端地区自动消息转换,这是通过LocaleResolver实现的。

请求来到时,DispatcherServlet查找对应的LocaleResolver处理国际化。使用RequestContext.getLocale()方法获取当前处理国际化resolver的地区。

LocaleContextResolver提供LocaleContext,用以获取当前client的时区。请求的时区信息开通过RequestContext.getTmeZone获取。

地区信息还可以使用Header
Resolver从accept-language消息头中获取并处理地区信息还可以使用Cookie
Resolver从cookie中获取并处理。CookieLocaleResolver例子如下:

<bean > <property name="cookieName" value="clientlanguage"/> <!-- in seconds. If set to -1, the cookie is not persisted (deleted when browser shuts down) --> <property name="cookieMaxAge" value="100000"/></bean>

CookieLocaleResolver属性如下:1.cookieName:cookie名称2.cookieMaxAge:客户端存储coodie的最大值,-1表示不存储cookie,客户端关闭browser时cookie清空。3.cookiePath:存储cookie的地址。

SessionLocaleResolver也允许从session中获取Locale和TimeZone。该信息存储于Servlet容器的HttpSession中。

地区拦截器:通过添加LocaleChangeInterceptor处理特定映射的地区。

根上下文通常包含被多个 Servlet 实例共享的公共 bean,例如数据仓库和业务。
这些 bean 被继承下来使用,还可以在特定的 Servlet
的子上下文中重写(即重新声明一个 bean 的配置),子上下文中拥有该 Servlet
所独有的局部 bean 实例:

1.2.10. 主题

主题是一系列静态资源,如样式表、图片等。Spring MVC支持主题的更改。

定义主题:要想使用主题,必须实现org.springframework.ui.context.ThemeSource接口。WebApplicaionContext继承ThemeSource但将处理任务委派给另一个实现:org.springframework.ui.context.support.ResourceBundleThemeSource。它读取配置文件中主题的定义构建主题,配置如下:

styleSheet=/themes/cool/style.cssbackground=/themes/cool/img/coolBg.jpg

对于JSP,使用spring:theme自定义标签,如下:

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%><html> <head> <link rel="stylesheet" href="<spring:theme%20code='styleSheet'/>" type="text/css"/> </head> <body style="background=<spring:theme code='background'/>"> ... </body></html>

主题处理器有:FixedThemeResolver、SessionThemeResolver和CookieThemeResolver。提供ThemeChangeInterceptor拦截器根据请求改变主题。

图片 2image

1.2.11. Multipart resolver

Multipart
resolver用于处理诸如上传等multipart请求。使用时需要在DispatcherServlet中定义MultipartResolver,然后会监听content-type为multipart/form-data的请求,然后解析内容并将当前的HttpServletRequest打包为MultipartHttpServletRequest以便处理。

Apache文件上传:通过配置CommonsMultipartResolver来使用Apache文件上传。需要依赖commons-fileupload包。

在Servlet3.0中,添加multipart支持需要进行注册。在web.xml中添加<multipart-config>然后添加StandardServletMultipartResolver处理multipart类型请求。

以下是使用 WebApplicationContext 层次结构的示例配置:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { RootConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { App1Config.class }; } @Override protected String[] getServletMappings() { return new String[] { "/app1/*" }; }}

在 web.xml 中的配置

<web-app> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <!-- 根上下文的配置 --> <param-value>/WEB-INF/root-context.xml</param-value> </context-param> <servlet> <servlet-name>app1</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!-- app1 专属的的子上下文 --> <param-value>/WEB-INF/app1-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app1</servlet-name> <url-pattern>/app1/*</url-pattern> </servlet-mapping></web-app>

DispatcherServlet 依靠这些特殊的 bean 来处理请求并返回响应。 这些特殊的
bean 是指实现 WebFlux 框架协议的,同样由 Spring 管理的对象。
这些对象都含有一套默认的配置,但也可以自定义各种属性,从而进行灵活扩展或功能改写。

bean 类名 功能
HandlerMapping 将请求映射到处理程序以及用于预处理和后续处理的一系列拦截器。 这种映射有着一套标准,具体的功能因 HandlerMapping 实现而异。 HandlerMapping 的两个最主要实现是 RequestMappingHandlerMapping 和 SimpleUrlHandlerMapping ,前者支持 @RequestMapping 注释方法,它为请求的处理进行 URI 映射的注册。
HandlerAdapter 协助 DispatcherServlet 调用匹配请求映射的处理程序,且不需要关心如何调用处理程序以及处理程序的任何细节。 例如,调用带注释的控制器中的方法需要先对 @RequestMapping 等注释进行解析。 HandlerAdapter 的主要功能是屏蔽 DispatcherServlet 的实现细节。
HandlerExceptionResolver 包含各种异常的解决方法,可以将不同的异常映射到响应的处理程序或页面等。
ViewResolver 将处理程序中的方法返回值的逻辑视图名称解析为实际视图,来将响应返回给客户端。
LocaleResolver, LocaleContextResolver 识别客户端的当前区域设置以估测大概的时区,从而能够返回响应地区的国际化视图。
ThemeResolver 解析当前 Web 应用程序可用的主题,例如提供个性化布局。
MultipartResolver 在相应的解析库的辅助下,对 multi-part 请求(比如浏览器的表单文件上传)进行解析。
FlashMapManager 存储和检索可将参数从一个请求传递到另一个请求的“输入”和“输出”的 FlashMap,通常通过重定向来实现。

应用程序可以单独声明上文中“带有特殊功能的 Bean”中列出的基础版的 bean。
DispatcherServlet 扫描这些 bean 所属的 WebApplicationContext。
如果没有匹配的 bean 类型,它将返回 DispatcherServlet.properties
中的默认类型。

在大多数情况下,MVC 默认配置是最好的实现。 它采用 Java 代码或 XML
文件来配置所需的 bean,同时提供更高级别的配置回调 API 用于改写默认配置。

在 Servlet 3.0 以上的版本中,可以用 Java代码或与 web.xml
文件相结合来配置 Servlet 容器。 以下是用 Java 代码注册 DispatcherServlet
的示例:

import org.springframework.web.WebApplicationInitializer;public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) { XmlWebApplicationContext appContext = new XmlWebApplicationContext(); appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml"); ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext)); registration.setLoadOnStartup; registration.addMapping; }}

WebApplicationInitializer 是 Spring MVC
提供的一个接口,其所有实现类都可以被扫描到,并自动用于初始化任何 Servlet
3 容器。 AbstractDispatcherServletInitializer
(WebApplicationInitializer
的一个抽象父类)的实现类可以通过覆盖方法来配置 Servlet
请求映射、DispatcherServlet 配置文件的目录,这样很简单的就实现了
DispatcherServlet 的配置。

如果通过 Java 代码来配置 Spring 的话,需要这样做:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return null; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { MyWebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; }}

如果用 xml 文件来配置 Spring,则只需定义一个
AbstractDispatcherServletInitializer 实现类即可:

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { @Override protected WebApplicationContext createRootApplicationContext() { return null; } @Override protected WebApplicationContext createServletApplicationContext() { XmlWebApplicationContext cxt = new XmlWebApplicationContext(); cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml"); return cxt; } @Override protected String[] getServletMappings() { return new String[] { "/" }; }}

AbstractDispatcherServletInitializer 还可以轻松添加 Filter 并自动映射到
DispatcherServlet 中:

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { // ... @Override protected Filter[] getServletFilters() { return new Filter[] { new HiddenHttpMethodFilter(), new CharacterEncodingFilter() }; }}

不同的 Filter 都会以不同的名称注册,同时映射到 DispatcherServlet 中。

The isAsyncSupported protected method of
AbstractDispatcherServletInitializer provides a single place to enable
async support on the DispatcherServlet and all filters mapped to it. By
default this flag is set to true.

AbstractDispatcherServletInitializer 中的 isAsyncSupported()
方法可以设置各个 Filter 是否开启异步支持。

如果还想更加细化自定义配置,可以通过重写 createDispatcherServlet()
方法来实现。

DispatcherServlet 处理请求的规则:

  • 在请求中查找并绑定
    WebApplicationContext,它可以作为参数被控制器中的方法使用。
    默认绑定到 DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
    对应的值。
  • 区域解析器 (LocaleResolver)
    也绑定到请求上,它可以在请求解析、呈现视图、准备数据等过程中将信息解析为当前的区域环境。如果无需解析这些信息,可以不用管它。
  • 主题解析器用来决定使用哪个主题。 如果你不使用主题,可以忽略掉它。
  • 如果在应用中声明了 multipart file resolver,则会对请求进行 multipart
    检查;如果发现了 multiparts,请求会被包装成 MultipartHttpServlet
    来进行处理。
  • 如果返回模型,则会解析并返回视图。
    如果没有返回模型(由于其他处理程序拦截了请求,可能出于安全原因),则不会返回视图,因为可能已经有响应返回给客户端了。

WebApplicationContext 中声明的 HandlerExceptionResolver bean
可以解析请求处理时抛出的异常。
可以给异常解析器进行特定的配置来解决特定的异常。

DispatcherServlet 还支持返回最后修改日期。 DispatcherServlet
扫描注册的映射关系并,判断找到的处理程序是否实现了 LastModified 接口。
如果实现了,则将 LastModified 接口的 long
getLastModified方法的返回值返回给客户端。

在 web.xml 中,可以通过配置 Servlet
的初始化参数(init-param)来自定义一个 DispatcherServlet 的实例。

DispatcherServlet 的初始化参数

参数 含义
contextClass WebApplicationContext 的实现类,初始化 Servlet 的上下文,默认为 XmlWebApplicationContext
contextConfigLocation 作为参数传递给在 contextClass 中指定上下文实例,用于标识上下文的位置,接受多个字符串,如果同一个 bean 的配置在多个上下文中出现,则以最后一个为准。
namespace WebApplicationContext 的命名空间,默认为 <servlet-name> 元素中的值加上“servlet”。比如,<servlet-name>app</servlet-name>,那么,命名空间为 appServlet。

所有 HandlerMapping
的实现类都支持使用拦截器,特别是将某些功能只应用到特定的请求上时,拦截器就非常有用。
拦截器必须实现 org.springframework.web.servlet 包中的
HandlerInterceptor,它提供了三个方法,供不同时刻来调用:

  • preHandle:在请求处理前执行…
  • postHandle:在请求处理后执行…
  • afterCompletion:在请求处理完全结束后执行…

preHandle
方法返回布尔值,可以通过这一点选择来切断或继续请求的处理链。当返回 true
的时候,处理器链会继续执行;返回 false 的时候, DispatcherServlet
就会认为拦截器已经处理了请求或返回了视图,并不会继续被处理链中的其他处理器或拦截器所处理。

请注意,postHandle 对使用 @ResponseBody 和 ResponseEntity
方法的用处不大,在 HandlerAdapter 中, postHandle
调用之前就已经提交响应了。 所以这时再修改响应什么用也没有了。
这种情况下,可以实现 ResponseBodyAdvice,并将其声明为 Controller Advice
bean (在 Controller 类上添加 @ControllerAdvice 注解)或直接在
RequestMappingHandlerAdapter 中进行配置。

在映射或调用请求处理程序 (例如带有 @Controller 注解的控制器)
处理请求时,如果抛出了异常,则 DispatcherServlet 调用
HandlerExceptionResolver bean
来处理异常,然后将错误页面或错误状态码等信息返回个客户端。

下面列出 HandlerExceptionResolver 的几个实现类:

HandlerExceptionResolver 实现类

类名 功能
SimpleMappingExceptionResolver 将异常类型映射到异常页面的视图名,可以很容易实现错误页面的返回
DefaultHandlerExceptionResolver 处理由 Spring MVC 抛出的异常,可以直接映射到不同的 HTTP 状态码
ResponseStatusExceptionResolver 处理带有 @ResponseStatus 注解的异常,并将其映射到 HTTP 状态码
ExceptionHandlerExceptionResolver 通过调用控制器(带有 @Controller 注解或 @ControllerAdvice 注解)中的带有 @ExceptionHandler 注解的方法,来处理异常

如果需要同时映射多个异常类型,需要设置不同异常的权重
,权重越高,处理时机越晚。

HandlerExceptionResolver 中可以返回:

  • ModelAndView: 指向视图名
  • 不带属性的 ModelAndView: 如果已经通过权重更低的方法处理过异常了
  • null:
    这个异常无法被当前异常处理器识别,需要丢给接下来的处理器,如果所有处理器都不能处理这个异常,异常会传到
    Servlet 容器中,由容器来处理
  • 自定义异常处理请求也非常简单,比如,在 xml 中配置一个
    HandlerExceptionResolver 的 bean, Spring MVC
    会自动使用内部的默认异常处理器来处理 Spring MVC 抛出的异常(带有
    @ResponseStatus 注解的异常或带有 @ExceptionHandler
    注解的方法),可以修改这些默认配置或干脆直接重写新的配置。

发表评论

电子邮件地址不会被公开。 必填项已用*标注