一、功能及配置
1.DispatcherServlet、拦截器、错误页面
2.Annotated Controllers 带注释的控制器,Spring MVC提供了一个基于注释的编程模型,其中@Controller和 @RestController组件使用注释来表达请求映射,请求输入,异常处理等。带注释的控制器具有灵活的方法签名,无需扩展基类或实现特定的接口。
3.使用@RequestMapping批注将请求映射到控制器方法。它具有各种属性,可以通过URL,HTTP方法,请求参数,标头和媒体类型进行匹配。您可以在类级别使用它来表示共享的映射,也可以在方法级别使用它来缩小到特定的端点映射,支持占位符、正则表达式、后缀匹配等。
还有HTTP方法特定的快捷方式变体@RequestMapping:
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
还可以在类级别声明共享属性(媒体类型):@PostMapping(path = "/pets", consumes = "application/json") ,该consumes属性还支持否定表达式-例如,!text/plain表示以外的任何内容类型text/plain。
可以produces在类级别声明共享属性:@GetMapping(path = "/pets/{petId}", produces = "application/json") ,但是,与大多数其他请求映射属性不同,在类级使用时,方法级produces属性将覆盖而不是扩展类级声明。
可以根据请求参数条件来缩小请求映射。您可以测试是否存在请求参数(myParam),是否存在请求参数()!myParam或特定值(myParam=myValue)。以下示例显示如何测试特定值:
@GetMapping(path = "/pets/{petId}", params = "myParam=myValue")
可以将其与请求标头条件一起使用,如以下示例所示:
@GetMapping(path = "/pets", headers = "myHeader=myValue")
Spring MVC还支持带有自定义请求匹配逻辑的自定义请求映射属性。这是一个更高级的选项,它需要RequestMappingHandlerMapping对getCustomMethodCondition方法进行子类化 和覆盖,您可以在其中检查自定义属性并返回自己的RequestCondition。
可以以编程方式注册处理程序方法,这些方法可用于动态注册或高级案例,例如同一处理程序在不同URL下的不同实例。下面的示例注册一个处理程序方法:
@Configuration
public class MyConfig {
@Autowired
public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler) //注入目标处理程序和控制器的处理程序映射。
throws NoSuchMethodException {
RequestMappingInfo info = RequestMappingInfo
.paths("/user/{id}").methods(RequestMethod.GET).build();//准备请求映射元数据。
Method method = UserHandler.class.getMethod("getUser", Long.class); //获取处理程序方法。
mapping.registerMapping(info, handler, method); //添加注册。
}
}
4.类型转换
表示一些注解的控制器方法的参数String为基础的请求输入(如 @RequestParam,@RequestHeader,@PathVariable,@MatrixVariable,和@CookieValue)可以要求类型转换如果参数被声明为比其它的东西String。
可以在方法参数上加注解:
通过将@RequestParam批注的required标志设置为false或通过使用java.util.Optional包装器声明参数来指定方法参数是可选的。如果目标方法参数类型不是,则类型转换将自动应用 String
使用@RequestHeader注释将请求标头绑定到控制器中的方法参数。
使用@CookieValue注释将HTTP cookie的值绑定到控制器中的方法参数。
使用@ModelAttribute注释,以从模型访问属性,或者将其实例化(如果不存在)。model属性还覆盖了名称与字段名称匹配的HTTP Servlet请求参数中的值。这称为数据绑定,它使您不必处理解析和转换单个查询参数和表单字段的工作。以下示例显示了如何执行此操作:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { }
绑定的实例Pet。
@ModelAttribute是可选的,要访问没有数据绑定的模型属性,可以设置@ModelAttribute(binding=false)或者到控制器中并直接访问
5.@Validated自动应用验证
6.@SessionAttributes用于在请求之间的HTTP Servlet会话中存储模型属性。它是类型级别的注释,用于声明特定控制器使用的会话属性。这通常列出应透明地存储在会话中以供后续访问请求的模型属性的名称或模型属性的类型。
@Controller
@SessionAttributes("pet") // 将Pet值存储在Servlet会话中。
class EditPetForm {
// ...
@PostMapping("/pets/{id}")
fun handle(pet: Pet, errors: BindingResult, status: SessionStatus): String {
if (errors.hasErrors()) {
// ...
}
status.setComplete()
// ...Pet从Servlet会话中清除值。
}
}
如果您需要访问全局存在(即,在控制器外部,例如,通过过滤器)进行管理且可能存在或不存在的预先存在的会话属性,则可以@SessionAttribute在方法参数上使用注释,如下所示示例显示:
@RequestMapping("/")
fun handle(@SessionAttribute user: User): String {
// ...使用@RequestAttribute注释。
}
对于用例需要添加或删除会话属性,可以考虑注入 org.springframework.web.context.request.WebRequest或 javax.servlet.http.HttpSession到控制器的方法。
要将模型属性临时存储在会话中作为控制器工作流的一部分,请考虑使用@SessionAttributes中所述 @SessionAttributes。
7.重定向属性
@PostMapping("/files/{path}")
fun upload(...): String {
// ...
return "redirect:files/{path}"
}
将数据传递到重定向目标的另一种方法是使用闪存属性。与其他重定向属性不同,Flash属性保存在HTTP会话中(因此不会出现在URL中)。
Flash属性
Flash属性为一个请求提供了一种存储打算在另一个请求中使用的属性的方式。重定向时最常需要此功能,例如Post-Redirect-Get模式。Flash属性在重定向之前(通常在会话中)被临时保存,以便在重定向之后可供请求使用,并立即被删除。
Spring MVC有两个主要的抽象来支持Flash属性。FlashMap用于保存Flash属性,而FlashMapManager用于存储,检索和管理 FlashMap实例。
8.使用@RequestBody注释有请求体读取和反序列化到一个 Object
使用@ResponseBody批注,以通过HttpMessageConverter将返回序列化为响应主体
HttpEntity与使用大致相同,@RequestBody但基于公开请求标头和正文的容器对象
ResponseEntity就像@ResponseBody但带有状态和标题。
9.REST API
REST服务的常见要求是在响应正文中包含错误详细信息。Spring框架不会自动执行此操作,因为响应正文中错误详细信息的表示是特定于应用程序的。但是,a @RestController可以使用@ExceptionHandler带有ResponseEntity返回值的方法来设置响应的状态和主体。也可以在@ControllerAdvice类中声明此类方法以将其全局应用。
在响应主体中实现具有错误详细信息的全局异常处理的应用程序应考虑extend ResponseEntityExceptionHandler,它提供对Spring MVC引发的异常的处理,并提供用于自定义响应主体的钩子。要使用此功能,请创建一个的子类 ResponseEntityExceptionHandler,用对其进行注释@ControllerAdvice,覆盖必要的方法,然后将其声明为Spring bean。
10.Spring Web MVC包含WebMvc.fn,这是一个轻量级的函数编程模型,其中的函数用于路由和处理请求,而契约则是为不变性而设计的。它是基于注释的编程模型的替代方案,但可以在同一DispatcherServlet上运行。
11.Spring框架中可用于URI的各种选项。
UriComponentsBuilder 有助于从带有变量的URI模板构建URI
12.异步请求
1.使用DeferredResult来包装任何受支持的控制器方法返回值
@GetMapping("/quotes")
@ResponseBody
public DeferredResult
DeferredResult
// Save the deferredResult somewhere..
return deferredResult;
}
// From some other thread... 控制器可以从另一个线程异步生成返回值,例如,响应外部事件(JMS消息),计划任务或其他事件。
deferredResult.setResult(result);
2.java.util.concurrent.Callable包装任何受支持的返回值
@PostMapping
public Callable
return new Callable
public String call() throws Exception {
// ...
return "someView";
}
};
}
您可以将DeferredResult和Callable用于单个异步返回值。如果要产生多个异步值并将那些值写入响应,可以使用ResponseBodyEmitter返回值生成对象流,其中每个对象都使用进行序列化 HttpMessageConverter并写入响应,如以下示例所示:
@GetMapping("/events")
public ResponseBodyEmitter handle() {
ResponseBodyEmitter emitter = new ResponseBodyEmitter();
// Save the emitter somewhere..
return emitter;
}
// In some other thread
emitter.send("Hello once");
// and again later on
emitter.send("Hello again");
// and done at some point
emitter.complete();
有时,绕过消息转换并直接流式传输到响应很有用 OutputStream(例如,用于文件下载)。您可以使用StreamingResponseBody 返回值类型来执行此操作,如以下示例所示:
@GetMapping("/download")
public StreamingResponseBody handle() {
return new StreamingResponseBody() {
@Override
public void writeTo(OutputStream outputStream) throws IOException {
// write...
}
};
}
13.CORS
Spring MVC使您可以处理CORS(跨源资源共享)。
出于安全原因,浏览器禁止AJAX调用当前来源以外的资源。例如,您可以在一个标签页中拥有您的银行帐户,而在另一个标签页中拥有evil.com。来自evil.com的脚本不应使用您的凭据向您的银行API发出AJAX请求,例如从您的帐户中提取资金!
跨域资源共享(CORS)是由大多数浏览器实现的W3C规范,可让您指定授权哪种类型的跨域请求,而不是使用基于IFRAME或JSONP的安全性较低且功能较弱的变通办法。
@CrossOrigin 注释能够对带注释的控制器方法跨域请求,如下面的示例所示:
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
默认情况下,@CrossOrigin允许:所有起源。所有标题。控制器方法映射到的所有HTTP方法。
allowCredentials默认情况下不会启用,因为这会建立一个信任级别,该级别公开敏感的用户特定信息(例如cookie和CSRF令牌),并且仅在适当的地方使用。启用后,allowOrigins必须将其设置为一个或多个特定域(而不是特殊值"*"),或者allowOriginPatterns可以使用该属性来匹配动态的一组原点。
maxAge 设置为30分钟。
@CrossOrigin 在类级别也受支持,并且被所有方法继承,如以下示例所示:
@CrossOrigin(origins = "https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
可以@CrossOrigin在类级别和方法级别上使用,如以下示例所示:
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin("https://domain2.com")
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
14.全局配置
大多数应用程序都使用MVC Java配置或MVC XML名称空间来定义一些全局CORS配置。
Java配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
// Add more mappings...
}
}
XML配置
要在XML名称空间中启用CORS,可以使用
allowed-methods="GET, PUT"
allowed-headers="header1, header2, header3"
exposed-headers="header1, header2" allow-credentials="true"
max-age="123" />
15.HTTP缓存
HTTP缓存可以显着提高Web应用程序的性能。HTTP缓存围绕Cache-Control响应标头以及随后的条件请求标头(例如Last-Modified和ETag)展开。Cache-Control为私有(例如浏览器)和公共(例如代理)缓存提供有关如何缓存和重用响应的建议。一个ETag头用于使没有身体可能导致一个304(NOT_MODIFIED)一个条件请求,如果内容没有改变。ETag可以看作是Last-Modified标题的更复杂的后继者。
16.view技术
Thymeleaf是一种现代的服务器端Java模板引擎,它强调可以通过双击在浏览器中预览的自然HTML模板,这对于独立处理UI模板(例如,由设计人员)非常有用,而无需使用正在运行的服务器。如果要替换JSP,Thymeleaf提供了最广泛的功能集之一,以使这种过渡更加容易。
Apache FreeMarker是一个模板引擎,用于生成从HTML到电子邮件等的任何类型的文本输出。Spring框架具有内置的集成,可以将Spring MVC与FreeMarker模板一起使用。
17.MVC配置
启用MVC配置
在Java配置中,可以使用@EnableWebMvc注释启用MVC配置,如以下示例所示:
@Configuration
@EnableWebMvc
public class WebConfig {
}
在XML配置中,可以使用
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
18.MVC Config API
在Java配置中,您可以实现该WebMvcConfigurer接口,如以下示例所示:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// Implement configuration methods...
}
19.类型转换
默认情况下,将安装各种数字和日期类型的格式化程序,并支持通过@NumberFormat和@DateTimeFormat在字段上进行自定义。
要在Java配置中注册自定义格式器和转换器,请使用以下命令:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
要在XML配置中执行相同的操作,请使用以下命令:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
20.验证方式
默认情况下,如果Bean验证存在于类路径中(例如,Hibernate Validator),则将LocalValidatorFactoryBean其注册为全局验证器,以@Valid与 Validated控制器方法参数一起使用。
在Java配置中,您可以自定义全局Validator实例,如以下示例所示:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public Validator getValidator() {
// ...
}
}
以下示例显示了如何在XML中实现相同的配置:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
还可以Validator在本地注册实现,如以下示例所示:
@Controller
public class MyController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new FooValidator());
}
}
如果需要在LocalValidatorFactoryBean某处进行注入,请创建一个bean并标记为Bean,@Primary以避免与MVC配置中声明的bean发生冲突。
21.拦截器
在Java配置中,您可以注册拦截器以应用于传入的请求,如以下示例所示:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
以下示例显示了如何在XML中实现相同的配置:
22.内容类型
您可以配置Spring MVC如何根据请求确定请求的媒体类型(例如,Accept标头,URL路径扩展,查询参数等)。
默认情况下,URL路径扩展首先检查-有json,xml,rss,并atom 注册为已知扩展名(视路径依赖)。的Accept报头检查第二。
考虑将这些默认值更改为Accept仅标头,并且,如果必须使用基于URL的内容类型解析,请考虑对路径扩展使用查询参数策略。有关更多详细信息,请参见 后缀匹配和后缀匹配以及RFD。
在Java配置中,您可以自定义请求的内容类型解析,如以下示例所示:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.mediaType("json", MediaType.APPLICATION_JSON);
configurer.mediaType("xml", MediaType.APPLICATION_XML);
}
}
以下示例显示了如何在XML中实现相同的配置:
json=application/json
xml=application/xml
23.讯息转换器
您可以通过HttpMessageConverter覆盖configureMessageConverters() (替换由Spring MVC创建的默认转换器)或覆盖 extendMessageConverters() (定制默认转换器或向默认转换器添加其他转换器)来在Java配置中 进行自定义。
以下示例使用自定义的ObjectMapper而不是默认的添加了XML和Jackson JSON转换器 :
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(new ParameterNamesModule());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
}
}
在前面的例子中, Jackson2ObjectMapperBuilder 用于创建两种共同的构成MappingJackson2HttpMessageConverter和 MappingJackson2XmlHttpMessageConverter与缩进启用,定制的日期格式,和登记 jackson-module-parameter-names,这增加了用于访问参数名称(在Java中8增加了一个功能)的支持。
该构建器自定义Jackson的默认属性,如下所示:
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 被禁用。
MapperFeature.DEFAULT_VIEW_INCLUSION 被禁用。
如果在类路径中检测到以下知名模块,它将自动注册以下知名模块:
jackson-datatype-joda:支持Joda-Time类型。
jackson-datatype-jsr310:支持Java 8日期和时间API类型。
jackson-datatype-jdk8:支持其他Java 8类型,例如Optional。
jackson-module-kotlin:支持Kotlin类和数据类。
使用Jackson XML支持启用缩进woodstox-core-asl 除了需要依赖之外,还需要 依赖jackson-dataformat-xml。
其他有趣的Jackson模块也可用:
jackson-datatype-money:支持javax.money类型(非官方模块)。
jackson-datatype-hibernate:支持特定于Hibernate的类型和属性(包括延迟加载方面)。
以下示例显示了如何在XML中实现相同的配置:
p:simpleDateFormat="yyyy-MM-dd"
p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>
24.view控制器
这是定义a的快捷方式,该快捷方式ParameterizableViewController在调用时立即转发到视图。当视图生成响应之前没有Java控制器逻辑要运行时,可以在静态情况下使用它。
以下Java配置示例将请求转发/到名为的视图home:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
以下示例通过使用
如果将@RequestMapping方法映射到任何HTTP方法的URL,则视图控制器不能用于处理相同的URL。这是因为通过URL与带注释的控制器的匹配被认为是端点所有权的足够有力的指示,因此可以将405(METHOD_NOT_ALLOWED),415(UNSUPPORTED_MEDIA_TYPE)或类似的响应发送给客户端,以帮助进行调试。因此,建议避免在带注释的控制器和视图控制器之间拆分URL处理。
view解析器
MVC配置简化了视图解析器的注册。
以下Java配置示例通过使用JSP和Jackson作为ViewJSON呈现的默认配置来配置内容协商视图解析:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.jsp();
}
}
以下示例显示了如何在XML中实现相同的配置:
但是请注意,FreeMarker,Tiles,Groovy标记和脚本模板也需要配置基础视图技术。
MVC命名空间提供了专用元素。以下示例适用于FreeMarker:
在Java配置中,您可以添加相应的Configurerbean,如以下示例所示:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.freeMarker().cache(false);
}
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/freemarker");
return configurer;
}
}
25.静态资源
此选项提供了一种方便的方法来从Resource基于位置的列表中提供静态资源 。
在下一个示例中,给定一个以开头的请求,/resources相对路径用于相对于/publicWeb应用程序根目录下或之下的类路径查找和提供静态资源/static。这些资源的使用期限为一年,以确保最大程度地利用浏览器缓存并减少浏览器发出的HTTP请求。Last-Modified从中推导出该信息,Resource#lastModified 以便HTTP条件请求支持"Last-Modified"标头。
以下清单显示了如何使用Java配置进行操作:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public", "classpath:/static/")
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)));
}
}
以下示例显示了如何在XML中实现相同的配置:
cache-period="31556926" />
另请参见 HTTP缓存对静态资源的支持。
资源处理程序还支持一系列 ResourceResolver实现和 ResourceTransformer实现,您可以使用它们来创建用于处理优化资源的工具链。
您可以VersionResourceResolver根据从内容,固定应用程序版本或其他版本计算出的MD5哈希值,使用for版本资源URL。一 ContentVersionStrategy(MD5哈希)是一个不错的选择-有一些明显的例外,如与模块加载程序使用的JavaScript资源。
以下示例显示了如何VersionResourceResolver在Java配置中使用:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public/")
.resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}
}
以下示例显示了如何在XML中实现相同的配置:
然后,您可以ResourceUrlProvider用来重写URL并应用完整的解析器和转换器链-例如,插入版本。MVC配置提供了一个ResourceUrlProvider bean,以便可以将其注入其他对象。您也可以使用ResourceUrlEncodingFilterThymeleaf,JSP,FreeMarker以及其他依赖于URL标签的URL使重写透明 HttpServletResponse#encodeURL。
请注意,在同时使用和EncodedResourceResolver(例如,用于提供压缩或brotli编码的资源)和时VersionResourceResolver,必须按此顺序注册它们。这样可以确保始终基于未编码文件可靠地计算基于内容的版本。
WebJarsResourceResolver当org.webjars:webjars-locator-core类路径中存在库时,也会通过 自动注册 WebJars。解析程序可以重写URL以包括jar的版本,还可以与没有版本的传入URL进行匹配,例如from/jquery/jquery.min.js到 /jquery/1.2.0/jquery.min.js。
26.默认Servlet
Spring MVC允许映射DispatcherServlet到/(从而覆盖了容器默认Servlet的映射),同时仍允许容器默认Servlet处理静态资源请求。它配置的 DefaultServletHttpRequestHandlerURL映射为/**,相对于其他URL映射具有最低的优先级。
该处理程序将所有请求转发到默认Servlet。因此,它必须按所有其他URL的顺序保留在最后HandlerMappings。如果使用,就是这种情况
下面的示例演示如何使用默认设置启用功能:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
以下示例显示了如何在XML中实现相同的配置:
覆盖/Servlet映射的警告是,RequestDispatcher必须通过名称而不是通过路径来检索默认Servlet的。在 DefaultServletHttpRequestHandler尝试自动检测默认的Servlet在启动时的容器,使用大多数主要的Servlet容器(包括软件Tomcat,Jetty的GlassFish,JBoss和树脂中,WebLogic和WebSphere)已知名称的列表。如果已使用其他名称自定义配置了默认Servlet,或者在默认Servlet名称未知的情况下使用了不同的Servlet容器,则必须显式提供默认Servlet的名称,如以下示例所示:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
}
以下示例显示了如何在XML中实现相同的配置:
27.路径匹配
您可以自定义与路径匹配和URL处理有关的选项。有关各个选项的详细信息,请参见 PathMatchConfigurerjavadoc。
以下示例显示了如何在Java配置中自定义路径匹配:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer
.setPatternParser(new PathPatternParser())
.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
}
private PathPatternParser patternParser() {
// ...
}
}
以下示例显示了如何在XML中实现相同的配置:
path-helper="pathHelper"
path-matcher="pathMatcher"/>
28.高级Java配置
@EnableWebMvc进口DelegatingWebMvcConfiguration,其中:
为Spring MVC应用程序提供默认的Spring配置
检测并委托给WebMvcConfigurer实现以自定义该配置。
对于高级模式,您可以@EnableWebMvc直接从中删除和扩展 DelegatingWebMvcConfiguration而不是实现WebMvcConfigurer,如以下示例所示:
@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
// ...
}
您可以将现有方法保留在中WebConfig,但是现在您还可以覆盖基类中的bean声明,并且WebMvcConfigurer在类路径上仍然可以具有许多其他实现。
高级XML配置
MVC命名空间没有高级模式。如果需要在bean上自定义一个不能更改的属性,则可以使用BeanPostProcessorSpring的生命周期挂钩ApplicationContext,如以下示例所示:
@Component
public class MyPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
// ...
}
}
请注意,您需要以MyPostProcessorXML形式显式声明或通过
29.HTTP / 2
需要Servlet 4容器支持HTTP / 2,并且Spring Framework 5与Servlet API 4兼容。从编程模型的角度来看,应用程序不需要做任何特定的事情。但是,有一些与服务器配置有关的注意事项。有关更多详细信息,请参见 HTTP / 2 Wiki页面。
Servlet API确实公开了一种与HTTP / 2相关的构造。您可以使用 javax.servlet.http.PushBuilder主动将资源推送到客户端,并且它作为方法的方法参数而受支持@RequestMapping。
到这 mvc配置完了
二、测试
1.与Spring WebFlux相同
本节总结了spring-testSpring MVC应用程序中可用的选项。
2.Servlet API模拟:用于单元测试控制器,过滤器和其他Web组件的Servlet API合约的模拟实现。有关 更多详细信息,请参见Servlet API模拟对象。
3.TestContext Framework:支持在JUnit和TestNG测试中加载Spring配置,包括跨测试方法高效地缓存已加载的配置,并支持通过加载WebApplicationContexta MockServletContext。有关更多详细信息,请参见TestContext Framework。
4.Spring MVC Test:一种框架,也称为MockMvc,用于通过DispatcherServlet(即支持注释)测试带注释的控制器,该框架具有Spring MVC基础结构,但没有HTTP服务器。有关更多详细信息,请参见Spring MVC Test。
5.客户端REST:spring-test提供一个MockRestServiceServer,您可以用作模拟服务器来测试内部使用的客户端代码RestTemplate。有关更多详细信息,请参见客户端REST测试。
6.WebTestClient:专为测试WebFlux应用程序而设计,但也可以用于通过HTTP连接到任何服务器的端到端集成测试。它是一个无阻塞的反应式客户端,非常适合测试异步和流传输方案。
7.WebClient
与相比RestTemplate,WebClient支持以下内容:
非阻塞I / O。
反应性产生背压。
高并发,硬件资源更少。
利用Java 8 lambda的功能风格,流畅的API。
同步和异步交互。
从服务器流向上或向下流。
三、WebSockets
1.WebSocket介绍
WebSocket协议RFC 6455提供了一种标准化的方法,可以通过单个TCP连接在客户端和服务器之间建立全双工的双向通信通道。它是与HTTP不同的TCP协议,但旨在通过端口80和443在HTTP上工作,并允许重复使用现有的防火墙规则。
WebSocket交互始于一个HTTP请求,该请求使用HTTPUpgrade标头进行升级,或者在这种情况下切换到WebSocket协议。以下示例显示了这种交互:
GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080
该Upgrade头。
使用Upgrade连接。
具有WebSocket支持的服务器代替通常的200状态代码,返回类似于以下内容的输出:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp
协议切换
成功握手后,HTTP升级请求的基础TCP套接字将保持打开状态,客户端和服务器均可继续发送和接收消息。
WebSockets的工作原理的完整介绍超出了本文档的范围。请参阅RFC 6455,HTML5的WebSocket章节,或Web上的许多简介和教程中的任何一个。
请注意,如果WebSocket服务器在Web服务器(例如nginx)后面运行,则可能需要对其进行配置,以将WebSocket升级请求传递到WebSocket服务器。同样,如果应用程序在云环境中运行,请检查与WebSocket支持相关的云提供商的说明。
2.HTTP与WebSocket
尽管WebSocket被设计为与HTTP兼容并以HTTP请求开头,但重要的是要了解这两个协议导致了截然不同的体系结构和应用程序编程模型。
在HTTP和REST中,应用程序被建模为许多URL。为了与应用程序交互,客户端访问那些URL,即请求-响应样式。服务器根据HTTP URL,方法和标头将请求路由到适当的处理程序。
相比之下,在WebSockets中,初始连接通常只有一个URL。随后,所有应用程序消息都在同一TCP连接上流动。这指向了一个完全不同的异步,事件驱动的消息传递体系结构。
WebSocket也是一种低级传输协议,与HTTP不同,它不对消息的内容规定任何语义。这意味着除非客户端和服务器就消息语义达成一致,否则就无法路由或处理消息。
WebSocket客户端和服务器可以通过Sec-WebSocket-ProtocolHTTP握手请求上的标头协商使用更高级别的消息传递协议(例如STOMP)。在这种情况下,他们需要提出自己的约定。
何时使用WebSockets
WebSockets可以使网页具有动态性和交互性。但是,在许多情况下,结合使用Ajax和HTTP流或长时间轮询可以提供一种简单有效的解决方案。
例如,新闻,邮件和社交订阅源需要动态更新,但是每几分钟进行一次更新可能是完全可以的。另一方面,协作,游戏和金融应用程序需要更接近实时。
仅延迟并不是决定因素。如果消息量相对较少(例如,监视网络故障),则HTTP流或轮询可以提供有效的解决方案。低延迟,高频率和高音量的结合才是使用WebSocket的最佳案例。
还要记住,在Internet上,控件之外的限制性代理可能会阻止WebSocket交互,这可能是因为未将它们配置为传递 Upgrade标头,或者是因为它们关闭了长期处于空闲状态的连接。这意味着与面向公众的应用程序相比,将WebSocket用于防火墙内部的应用程序是一个更直接的决定。
3.WebSocket API
Spring框架提供了一个WebSocket API,可用于编写处理WebSocket消息的客户端和服务器端应用程序。
WebSocketHandler
创建WebSocket服务器就像实现一样简单,WebSocketHandler或者很可能扩展TextWebSocketHandler或BinaryWebSocketHandler。以下示例使用TextWebSocketHandler:
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
public class MyHandler extends TextWebSocketHandler {
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// ...
}
}
有专用的WebSocket Java配置和XML名称空间支持,用于将前面的WebSocket处理程序映射到特定的URL,如以下示例所示:
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler");
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}
以下示例显示了与先前示例等效的XML配置:
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
前面的示例用于Spring MVC应用程序,并且应包含在的配置中DispatcherServlet。但是,Spring的WebSocket支持不依赖于Spring MVC。WebSocketHandler在的帮助下,将a集成到其他HTTP服务环境中 相对简单WebSocketHttpRequestHandler。
当WebSocketHandler直接使用API或间接使用API(例如通过 STOMP消息传递)时,由于基础标准WebSocket会话(JSR-356)不允许并发发送,因此应用程序必须同步消息的发送。一种选择是将包裹WebSocketSession起来 ConcurrentWebSocketSessionDecorator。
WebSocket握手
定制初始HTTP WebSocket握手请求的最简单方法是通过HandshakeInterceptor,它公开了“握手之前”和“握手之后”的方法。您可以使用此类拦截器来阻止握手或使的任何属性可用WebSocketSession。以下示例使用内置的拦截器将HTTP会话属性传递到WebSocket会话:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyHandler(), "/myHandler")
.addInterceptors(new HttpSessionHandshakeInterceptor());
}
}
以下示例显示了与先前示例等效的XML配置:
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
一个更高级的选项是扩展,DefaultHandshakeHandler它执行WebSocket握手的步骤,包括验证客户端来源,协商子协议以及其他详细信息。如果应用程序需要配置自定义项RequestUpgradeStrategy以适应尚不支持的WebSocket服务器引擎和版本,则它可能还需要使用此选项(有关此主题的更多信息,请参阅部署)。Java配置和XML名称空间都使配置自定义成为可能 HandshakeHandler。
Spring提供了一个WebSocketHandlerDecorator基类,您可以使用它来装饰WebSocketHandler额外的行为。使用WebSocket Java配置或XML名称空间时,默认情况下会提供并添加日志记录和异常处理实现。在ExceptionWebSocketHandlerDecorator捕获了由任何出现的所有捕获的异常WebSocketHandler的方法,并关闭与状态WebSocket的会议1011,这表明服务器错误。
4.部署方式
Spring WebSocket API易于集成到Spring MVC应用程序中,在该应用程序中DispatcherServlet可以同时服务HTTP WebSocket握手和其他HTTP请求。通过调用也很容易集成到其他HTTP处理方案中WebSocketHttpRequestHandler。这是方便且易于理解的。但是,对于JSR-356运行时,需要特别注意。
Java WebSocket API(JSR-356)提供了两种部署机制。首先涉及启动时的Servlet容器类路径扫描(Servlet 3功能)。另一个是在Servlet容器初始化时使用的注册API。这两种机制都无法将单个“前端控制器”用于所有HTTP处理(包括WebSocket握手和所有其他HTTP请求)(例如Spring MVC)DispatcherServlet。
这是对JSR-356的重大限制,RequestUpgradeStrategy即使在JSR-356运行时中运行,Spring的WebSocket支持也可以通过服务器特定的实现来解决。Tomcat,Jetty,GlassFish,WebLogic,WebSphere和Undertow(以及WildFly)目前存在此类策略。
已经创建了一个克服Java WebSocket API中前述限制的请求,可以在eclipse-ee4j / websocket-api#211处进行跟踪 。Tomcat,Undertow和WebSphere提供了自己的API替代方案,使之可以做到这一点,而Jetty也可以实现。我们希望更多的服务器可以做到这一点。
另一个要考虑的因素是,期望支持JSR-356的Servlet容器执行ServletContainerInitializer(SCI)扫描,这可能会减慢应用程序的启动速度,在某些情况下会大大降低。如果在升级到支持JSR-356的Servlet容器版本后观察到重大影响,则应该可以通过使用中的
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
然后,您可以按名称有选择地启用Web片段,例如Spring自己的片段, SpringServletContainerInitializer它提供对Servlet 3 Java初始化API的支持。以下示例显示了如何执行此操作:
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
5.服务器配置
每个基础的WebSocket引擎都公开配置属性,这些属性控制运行时特征,例如消息缓冲区大小的大小,空闲超时等。
对于Tomcat,WildFly和GlassFish,可以将A添加ServletServerContainerFactoryBean到WebSocket Java配置中,如以下示例所示:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(8192);
container.setMaxBinaryMessageBufferSize(8192);
return container;
}
}
以下示例显示了与先前示例等效的XML配置:
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
对于客户端WebSocket配置,应使用WebSocketContainerFactoryBean (XML)或ContainerProvider.getWebSocketContainer()(Java配置)。
对于Jetty,您需要提供一个预先配置的Jetty,WebSocketServerFactory然后DefaultHandshakeHandler通过WebSocket Java配置将其插入Spring 。以下示例显示了如何执行此操作:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(echoWebSocketHandler(),
"/echo").setHandshakeHandler(handshakeHandler());
}
@Bean
public DefaultHandshakeHandler handshakeHandler() {
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setInputBufferSize(8192);
policy.setIdleTimeout(600000);
return new DefaultHandshakeHandler(
new JettyRequestUpgradeStrategy(new WebSocketServerFactory(policy)));
}
}
以下示例显示了与先前示例等效的XML配置:
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
6.允许的来源
从Spring Framework 4.1.5开始,WebSocket和SockJS的默认行为是仅接受同源请求。也可以允许所有或指定的来源列表。此检查主要用于浏览器客户端。没有任何措施可以阻止其他类型的客户端修改Origin标头值(有关更多详细信息,请参阅 RFC 6454:Web Origin概念)。
三种可能的行为是:
仅允许同源请求(默认):在此模式下,启用SockJS时,Iframe HTTP响应标头X-Frame-Options设置为SAMEORIGIN,并且JSONP传输被禁用,因为它不允许检查请求的来源。因此,启用此模式时,不支持IE6和IE7。
允许指定来源列表:每个允许的来源必须以http:// 或开头https://。在此模式下,启用SockJS时,将禁用IFrame传输。因此,启用此模式时,不支持IE6到IE9。
允许所有原点:要启用此模式,应提供*作为允许的原点值。在这种模式下,所有传输都可用。
您可以配置WebSocket和SockJS允许的来源,如以下示例所示:
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler").setAllowedOrigins("https://mydomain.com");
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}
以下示例显示了与先前示例等效的XML配置:
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">