Spring MVC Web官方参考文档
Spring Web MVC来源于spring-webmvc模块。
处于中央Servlet的DispatcherServlet,提供了一种用于请求处理的共享算法,而实际的工作由可配置的委托组件来执行。支持多种工作流程。
DispatcherServlet使用spring的配置来发现它需要的请求映射、视图解析、异常处理、委托组件及其他。
以下是在web.xml配置中注册、初试化DispatcherServlet:
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
// springmvc配置文件
/WEB-INF/app-context.xml
app
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
1
app
/app/*
Root WebApplicationContext通常包含基础结构bean,在多个DispatcherServlet(或其他Servlet)实例之间共享,每个实例还有其自己的子Servlet WebApplicationContext配置。
在web.xml配置应用程序上下文层次结构:
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
/WEB-INF/root-context.xml
app1
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
/WEB-INF/app-context.xml
1
app1
/app1/*
如果不需要应用程序上下文层次结构,则应用程序可以仅配置“根”上下文,并将contextConfigLocationServlet参数保留为空。
在DispatcherServlet中特殊类型bean用于处理请求、渲染响应。
特殊类型bean指带有内置约束,但可以自定义属性、扩展、替换它们。如:
特殊类型bean | 说明 |
---|---|
HandlerMapping | 将请求映射到处理程序以及用于预处理和后处理的拦截器列表 。 映射基于某些标准,其细节因HandlerMapping实现类而异。两个主要HandlerMapping实现类:RequestMappingHandlerMapping (支持带@RequestMapping注释的方法)和SimpleUrlHandlerMapping(维护URI路径模式到处理程序的显式注册)。 |
HandlerAdapter | DispatcherServlet无论如何调用处理程序,都可以使调用映射到请求的处理程序。例如,调用带注解的控制器需要解析注,HandlerAdapter主要目的是保护DispatcherServlet这些细节。 |
HandlerExceptionResolver | 解决异常的策略,将异常映射到处理程序,HTML错误页或其他目标。 |
ViewResolver | 从处理程序返回的基于逻辑的String视图名称解析为View,用于呈现给响应的页面。 |
LocaleResolver,LocaleContextResolver | 解决Locale客户端正在使用的时间区域,以便能够提供国际化的视图。 |
ThemeResolver | 解决Web应用程序可以使用的主题 - 例如,提供个性化布局。 |
MultipartResolver | 在一些多部分解析库的帮助下解析多部分请求(例如,浏览器表单文件上载)的抽象。 |
FlashMapManager | 存储和检索“输入”和“输出” FlashMap,可用于将属性从一个请求传递到另一个请求,通常是通过重定向。 |
应用程序可以声明处理请求所需的特殊类型bean中列出的基础结构bean 。
DispatcherServlet检查 WebApplicationContext中每个特殊类型bean,若没有匹配的bean类型,DispatcherServlet将回退到列出的默认类型DispatcherServlet.properties。
在Servlet 3.0+环境中,您可以选择以Java配置Servlet容器作为替代方案或与web.xml文件组合。如:
Java配置:
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(1);
registration.addMapping("/");
}
}
WebApplicationInitializer是Spring MVC提供的接口,可确保检测到您的实现并自动用于初始化任何Servlet 3容器。
AbstractDispatcherServletInitializer抽象类实现了WebApplicationInitializer接口,使DispatcherServlet通过重写方法注册去指定“servlet映射”、“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();
// spring配置文件
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() };
}
}
每个过滤器都会根据其具体类型添加一个默认名称,并自动映射到DispatcherServlet。
如果您需要进一步自定义DispatcherServlet自身,则可以覆盖该createDispatcherServlet方法。
DispatcherServlet要求如下:
HandlerExceptionResolver特殊类型bean:WebApplicationContext用于解决在请求处理期间抛出的异常。这些异常解析器允许自定义逻辑以解决异常。
DispatcherServlet还支持last-modification-dateServlet API指定的返回 。确定特定请求的最后修改日期的过程很简单: DispatcherServlet查找适当的处理程序映射并测试找到的处理程序是否实现LastModified接口。如果是,则将接口long getLastModified(request)方法的值 LastModified返回给客户端。
可以通过DispatcherServlet将Servlet初始化参数(init-param元素)添加到web.xml文件中的Servlet声明来自定义单个实例。下表列出了支持的参数:
初始化参数 | 说明 |
---|---|
contextClass | 实现ConfigurableWebApplicationContext,由此Servlet实例化和本地配置的类。默认情况下,XmlWebApplicationContext使用。 |
contextConfigLocation | 传递给上下文实例(由其指定contextClass)的字符串,用于指示可以在何处找到上下文。该字符串可能包含多个字符串(使用逗号作为分隔符)以支持多个上下文。对于具有两次定义的bean的多个上下文位置,最新位置优先。 |
namespace | WebApplicationContext命名空间。默认为[servlet-name]-servlet。 |
throwExceptionIfNoHandlerFound | NoHandlerFoundException在没有找到请求的处理程序时抛出。然后可以使用HandlerExceptionResolver(例如,通过使用 @ExceptionHandler控制器方法)捕获异常并像其他任何方式一样处理。默认情况下,此设置为false,在这种情况下,DispatcherServlet将响应状态设置为404(NOT_FOUND)而不引发异常。请注意,如果还配置了默认servlet处理,则始终将未解析的请求转发到默认servlet,并且永远不会引发404。 |
所有HandlerMapping实现类都支持处理程序拦截器。HandlerInterceptor拦截器必须从 org.springframework.web.servlet包中实现三种方法,这些方法应该提供足够的灵活性来进行各种预处理和后处理:
若在请求映射期间发生异常或请求处理程序(如 @Controller控制器)抛出异常,则DispatcherServlet委托给特殊类型bean—— HandlerExceptionResolver——链解决异常并提供替代处理,这通常是错误响应。
可用的HandlerExceptionResolver实现类:
实例 | 说明 |
---|---|
SimpleMappingExceptionResolver | 异常类名称和错误视图名称之间的映射。用于在浏览器应用程序中呈现错误页面。 |
DefaultHandlerExceptionResolver | 解决Spring MVC引发的异常并将它们映射到HTTP状态代码。 |
ResponseStatusExceptionResolver | 使用@ResponseStatus注释解析异常,并根据注释中的值将它们映射到HTTP状态代码。 |
ExceptionHandlerExceptionResolver | 通过调用或 类中的@ExceptionHandler方法来解决异常。 |
责任链模式
可以通过HandlerExceptionResolver 在Spring配置中声明多个bean并order根据需要设置其属性来形成异常解析程序链。order属性越高,异常解析器定位的越晚。
HandlerExceptionResolver规定它可以返回:
如果异常仍然未被任何解析,且HandlerExceptionResolver将其传播或者响应状态设置为错误状态(即4xx,5xx),则Servlet容器可以在HTML中呈现默认错误页面。要自定义容器的默认错误页面,可以声明错误页面映射web.xml。
/error
上面的示例,当异常冒泡或响应具有错误状态时,Servlet容器会在容器内对配置的URL进行ERROR调度(例如,/error)。然后给DispatcherServlet处理,可能将其映射到@Controller,可以将其实现为使用模型返回错误视图名称或呈现JSON响应,如以下示例所示:
@RestController
public class ErrorController {
@RequestMapping(path = "/error")
public Map handle(HttpServletRequest request) {
Map map = new HashMap();
map.put("status", request.getAttribute("javax.servlet.error.status_code"));
map.put("reason", request.getAttribute("javax.servlet.error.message"));
return map;
}
}
Servlet API不提供在Java中创建错误页面映射的方法。但是,您可以同时使用WebApplicationInitializer和web.xml
Spring MVC定义了一些ViewResolver和View接口,使您可以在浏览器中呈现模型,而无需将您与特定的视图技术联系起来。
ViewResolver 提供视图名称和实际视图之间的映射。
View在移交给特定视图技术之前解决数据准备问题。
ViewResolver实现:
视图解析器 | 说明 |
---|---|
AbstractCachingViewResolver | AbstractCachingViewResolver他们解析的缓存视图实例的子类。缓存可提高某些视图技术的性能。可以通过将cache属性设置为关闭缓存false。此外,如果必须在运行时刷新某个视图(如修改FreeMarker模板时),则可以用removeFromCache(String viewName, Locale loc)方法。 |
XmlViewResolver | 接受使用与Spring的XML bean工厂相同的DTD以XML编写的配置文件。默认配置文件是 /WEB-INF/views.xml。 |
ResourceBundleViewResolver | 它的实现视图解析器使用bean中的bean定义ResourceBundle,由bundle base name指定。对于应该解析的每个视图,它使用属性的值[viewname].(class)作为视图类,将属性的值[viewname].url用作视图URL。 |
UrlBasedViewResolver | 简单实现的ViewResolver接口会影响逻辑视图名称直接解析为没有显式映射定义的URL。如果您的逻辑名称以直接的方式与视图资源的名称匹配,则这是合适的,而不需要任意映射。 |
InternalResourceViewResolver | 方便的子类UrlBasedViewResolver支持InternalResourceView(实际上,Servlet和JSP)和子类,如JstlView和TilesView。您可以使用指定此解析程序生成的所有视图的视图类setViewClass(…)。 |
FreeMarkerViewResolver | 方便的子类UrlBasedViewResolver支持FreeMarkerView它们的自定义子类 |
ContentNegotiatingViewResolver | 实现ViewResolver基于请求文件名或Accept标头解析视图的接口 |
可以通过声明多个解析程序bean链接视图解析程序,并在必要时通过设置order属性来指定排序。请记住,order属性越高,视图解析器在链中的位置越晚。
ViewResolver指定它可以返回null以指示无法找到该视图。但是,对于JSP而言,确定JSP InternalResourceViewResolver是否存在的唯一方法是执行调度 RequestDispatcher。因此,您必须在视图解析器链的整体顺序中将InternalResourceViewResolver配置为最后一个视图解析器。
配置ViewResolver视图解析就像在Spring配置中添加bean 一样简单。MVC配置提供了一种专用配置API 视图解析器和用于将逻辑较少视图控制器,其可用于HTML模板呈现而不用控制器逻辑。
redirect: 视图名称中的特殊前缀,允许执行重定向。UrlBasedViewResolver(和它的子类)识别为是需要重定向的指令。视图名称的其余部分是重定向URL。
请注意,如果使用注解控制器方法**@ResponseStatus**,则RedirectView 注解值优先于设置的响应状态。
forward: 前缀表示最终由UrlBasedViewResolver和子类解析的视图名称。这将创建一个InternalResourceView,它执行RequestDispatcher.forward()。因此,对于InternalResourceViewResolver和InternalResourceView(对于JSP),这个前缀是没有用的,但是如果您使用另一种视图技术,但是仍然希望强制Servlet/JSP引擎处理资源的转发,那么这个前缀是有用的。
请注意,您还可以链接多个视图解析器。
ContentNegotiatingViewResolver不解析视图本身,而是委托给其他视图解析器并选择类似于客户端请求表示的视图。可以从Accept头部或查询参数(例如,"/path?format=pdf")确定表示。
在ContentNegotiatingViewResolver选择一个适当的View处理由与媒体类型(也称为比较请求的媒体类型的请求 Content-Type被支持)View与每个其相关联ViewResolvers。View列表中具有兼容性的第一个Content-Type将表示返回给客户端。如果ViewResolver链不能提供兼容的视图,DefaultViews则查阅通过该属性指定的视图列表。后一个选项适用于Views可以呈现当前资源的适当表示的单例,而不管逻辑视图名称如何。的Accept 报头可以包括通配符(例如text/*),在这种情况下View,其 Content-Type是text/xml为相容的匹配。
当请求进入时,DispatcherServlet查找区域解析器,如果找到,则尝试使用它来设置区域设置。通过使用RequestContext.getLocale() 方法,您始终可以检索由区域解析器解析的区域设置。
除了自动语言环境解析之外,您还可以将拦截器附加到处理程序映射,用于在特定情况下更改语言环境(例如,基于请求中的参数)。
区域解析器、拦截器在org.springframework.web.servlet.i18n包中定义, 并以正常方式在应用程序上下文中进行配置。
Spring中包含以下选择的语言环境解析器:
应用Spring Web MVC框架主题来设置应用程序的整体外观,从而增强用户体验。主题是静态资源的集合,通常是样式表和图像,它们会影响应用程序的视觉样式。
要在Web应用程序中使用主题,必须设置org.springframework.ui.context.ThemeSource接口的实现 。WebApplicationContext 继承了ThemeSource,但其代表职责的专用实现。
默认情况下,委托是一个 org.springframework.ui.context.support.ResourceBundleThemeSource实现,它从类路径的根目录加载属性文件。要使用自定义ThemeSource 实现或配置其基本名称前缀ResourceBundleThemeSource,可以在应用程序上下文中使用保留名称注册bean themeSource。Web应用程序上下文自动检测具有该名称的bean并使用它。
使用ResourceBundleThemeSource时,主题在简单的属性文件中定义。属性文件列出构成主题的资源,如下所示:
styleSheet = /themes/cool/style.css
background = /themes/cool/img/coolBg.jpg
属性的键是从页面代码引用主题元素的名称。
对于JSP,通常使用spring:theme自定义标记执行此操作,该标记与spring:message标记非常相似。以下JSP片段使用上一示例中定义的主题来自定义外观:
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
...
在DispatcherServlet查找名为ThemeResolver的bean实现类。主题解析器的工作方式与LocaleResolver非常相似。它检测用于特定请求的主题,还可以更改请求的主题。下表描述了Spring提供的主题解析器:
类 | 说明 |
---|---|
FixedThemeResolver | 选择使用defaultThemeName属性设置的固定主题。 |
选择使用defaultThemeName属性设置的固定主题。 | 主题在用户的HTTP会话中维护。它只需要为每个会话设置一次,但不会在会话之间保留。 |
CookieThemeResolver | 所选主题存储在客户端的cookie中。 |
Spring还提供了一个ThemeChangeInterceptor允许使用简单的请求参数对每个请求进行主题更改的方法。
MultipartResolver从org.springframework.web.multipart包中解析多部分请求(包括文件上载)的策略。有一个基于Commons FileUpload的实现,另一个基于Servlet 3.0多部分请求解析。
启用多部分解析器,要在DispatcherServletSpring配置中声明一个名为MultipartResolver的bean。在DispatcherServlet检测到它,并将其应用于传入请求。当与内容类型的POST multipart/form-data被接收时,分解器解析该内容和包装了当前HttpServletRequest作为MultipartHttpServletRequest对露出它们作为请求参数提供到解析部件除了访问。
常用多部分解析器:
Spring MVC中的DEBUG级别日志记录旨在实现紧凑,简约和人性化。它侧重于高价值的信息,这些信息一次又一次地有用,而只有在调试特定问题时才有用。
TRACE级日志记录通常遵循与DEBUG相同的原则(例如,也不应该是消防软管),但可以用于调试任何问题。此外,一些日志消息可能在TRACE与DEBUG中显示不同的详细程度。
spring-web模块提供了一些有用的过滤器: