Spring Web MVC framework(一般简称为“Spring MVC”)是一个丰富的“model 视图控制器”web framework。 Spring MVC 容许您建立特殊的@Controller
或@RestController
beans 来处理传入的 HTTP 请求。控制器中的方法使用@RequestMapping
annotations 映射到 HTTP。html
如下 code 显示了为 JSON 数据提供服务的典型@RestController
:java
@RestController @RequestMapping(value="/users") public class MyRestController { @RequestMapping(value="/{user}", method=RequestMethod.GET) public User getUser(@PathVariable Long user) { // ... } @RequestMapping(value="/{user}/customers", method=RequestMethod.GET) List<Customer> getUserCustomers(@PathVariable Long user) { // ... } @RequestMapping(value="/{user}", method=RequestMethod.DELETE) public User deleteUser(@PathVariable Long user) { // ... } }
Spring MVC 是核心 Spring Framework 的一部分,详细信息可在reference 文档中找到。还有几个 guides 覆盖了spring.io/guides的 Spring MVC。jquery
Spring Boot 为 Spring MVC 提供 auto-configuration,适用于大多数 applications。git
auto-configuration 在 Spring 的默认值之上添加如下 features:github
包含ContentNegotiatingViewResolver
和BeanNameViewResolver
beans。web
支持提供静态资源,包括对 WebJars 的支持(稍后在本文档中 ))。spring
自动注册Converter
,GenericConverter
和Formatter
beans。apache
支持HttpMessageConverters(稍后在本文档中)。json
自动注册MessageCodesResolver(稍后在本文档中).api
静态index.html
支持。
自定义Favicon
支持(稍后在本文档中)。
自动使用ConfigurableWebBindingInitializer
bean(稍后在本文档中)。
若是你想保留 Spring Boot MVC features 而且想要添加额外的MVC configuration(拦截器,格式化程序,视图控制器和其余 features),你能够添加本身的@Configuration
class 类型为WebMvcConfigurer
但而不是 @EnableWebMvc
。若是您但愿提供RequestMappingHandlerMapping
,RequestMappingHandlerAdapter
或ExceptionHandlerExceptionResolver
的自定义实例,则能够声明WebMvcRegistrationsAdapter
实例以提供此类组件。
若是要彻底控制 Spring MVC,能够添加本身的@Configuration
注释@EnableWebMvc
。
SpringBoot对SpringMVC的自动配置不须要了,全部都是咱们本身配置;全部的SpringMVC的自动配置都失效了
咱们须要在配置类中添加@EnableWebMvc便可;
//使用WebMvcConfigurerAdapter能够来扩展SpringMVC的功能 @EnableWebMvc @Configuration public class MyMvcConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { // super.addViewControllers(registry); //浏览器发送 /atguigu 请求来到 success registry.addViewController("/topcheer").setViewName("success"); } }
原理:
为何@EnableWebMvc自动配置就失效了;
1)@EnableWebMvc的核心
@Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc { }
2)、
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { }
3)、
@Configuration @ConditionalOnWebApplication @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class }) //容器中没有这个组件的时候,这个自动配置类才生效 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { }
4)、@EnableWebMvc将WebMvcConfigurationSupport组件导入进来;
5)、导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;
Spring MVC 使用HttpMessageConverter
接口转换 HTTP 请求和响应。明智的默认设置包含在开箱即用中。例如,objects 能够自动转换为 JSON(经过使用 Jackson library)或 XML(若是可用,则使用 Jackson XML 扩展,或者若是 Jackson XML 扩展不可用,则使用 JAXB)。默认状况下,strings 在UTF-8
中编码。
若是须要添加或自定义转换器,可使用 Spring Boot 的HttpMessageConverters
class,以下面的清单所示:
import org.springframework.boot.autoconfigure.web.HttpMessageConverters; import org.springframework.context.annotation.*; import org.springframework.http.converter.*; @Configuration public class MyConfiguration { @Bean public HttpMessageConverters customConverters() { HttpMessageConverter<?> additional = ... HttpMessageConverter<?> another = ... return new HttpMessageConverters(additional, another); } }
context 中存在的任何HttpMessageConverter
bean 都会添加到转换器列表中。您也能够以相同的方式覆盖默认转换器。
若是使用 Jackson 序列化和反序列化 JSON 数据,则可能须要编写本身的JsonSerializer
和JsonDeserializer
classes。自定义序列化程序一般是经过模块在 Jackson 注册,但 Spring Boot 提供了另外一种@JsonComponent
注释,能够更容易地直接注册 Spring Beans。
您能够直接在JsonSerializer
或JsonDeserializer
__mplement 上使用@JsonComponent
annotation。您也能够在包含 serializers/deserializers 做为内部 classes 的 classes 上使用它,以下面的示例所示:
import java.io.*; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; import org.springframework.boot.jackson.*; @JsonComponent public class Example { public static class Serializer extends JsonSerializer<SomeObject> { // ... } public static class Deserializer extends JsonDeserializer<SomeObject> { // ... } }
ApplicationContext
中的全部@JsonComponent
beans 都会自动在 Jackson 中注册。由于@JsonComponent
是 meta-annotated 和@Component
,因此适用一般的 component-scanning 规则。
也能够用FastJson进行序列化和反序列化
@Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { /* 先把JackSon的消息转换器删除. 备注: (1)源码分析可知,返回json的过程为: Controller调用结束后返回一个数据对象,for循环遍历conventers,找到支持application/json的HttpMessageConverter,而后将返回的数据序列化成json。 具体参考org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor的writeWithMessageConverters方法 (2)因为是list结构,咱们添加的fastjson在最后。所以必需要将jackson的转换器删除,否则会先匹配上jackson,致使没使用fastjson */ for (int i = converters.size() - 1; i >= 0; i--) { if (converters.get(i) instanceof MappingJackson2HttpMessageConverter) { converters.remove(i); } } FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter(); //自定义fastjson配置 FastJsonConfig config = new FastJsonConfig(); config.setSerializerFeatures( SerializerFeature.WriteMapNullValue, // 是否输出值为null的字段,默认为false,咱们将它打开 SerializerFeature.WriteNullListAsEmpty, // 将Collection类型字段的字段空值输出为[] SerializerFeature.WriteNullStringAsEmpty, // 将字符串类型字段的空值输出为空字符串 SerializerFeature.WriteNullNumberAsZero, // 将数值类型字段的空值输出为0 SerializerFeature.WriteDateUseDateFormat, SerializerFeature.DisableCircularReferenceDetect // 禁用循环引用 ); fastJsonHttpMessageConverter.setFastJsonConfig(config); // 添加支持的MediaTypes;不添加时默认为*/*,也就是默认支持所有 // 可是MappingJackson2HttpMessageConverter里面支持的MediaTypes为application/json List<MediaType> fastMediaTypes = new ArrayList<>(); MediaType mediaType = MediaType.parseMediaType("text/html;charset=UTF-8"); fastMediaTypes.add(mediaType); fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes); // fastJsonHttpMessageConverter.setDefaultCharset(Charset.forName("UTF-8")); converters.add(fastJsonHttpMessageConverter); }
Spring Boot 还提供了JsonObjectSerializer和JsonObjectDeserializer base classes,它们在序列化 objects 时为标准 Jackson 版本提供了有用的替代方法。有关详细信息,请参阅 Javadoc 中的JsonObjectSerializer和JsonObjectDeserializer。
Spring MVC 有一个生成错误代码的策略,用于从 binding 错误中呈现错误消息:MessageCodesResolver
。若是设置spring.mvc.message-codes-resolver.format
property PREFIX_ERROR_CODE
或POSTFIX_ERROR_CODE
,Spring Boot 会为您建立一个(请参阅DefaultMessageCodesResolver.Format中的枚举)。
默认状况下,Spring Boot 从 classpath 中的/static
(或/public
或/resources
或/META-INF/resources
)目录或ServletContext
的根目录中提供静态内容。它使用来自 Spring MVC 的ResourceHttpRequestHandler
,以便您能够经过添加本身的WebMvcConfigurer
并覆盖addResourceHandlers
方法来修改该行为。
在 stand-alone web application 中,容器中的默认 servlet 也被启用并充当回退,若是 Spring 决定不处理它,则从ServletContext
的根目录提供内容。大多数 time,这都不会发生(除非你修改默认的 MVC configuration),由于 Spring 老是能够经过DispatcherServlet
来处理请求。
默认状况下,资源映射到/**
,但您可使用spring.mvc.static-path-pattern
property 对其进行调整。例如,将全部资源从新定位到/resources/**
能够实现以下:
spring.mvc.static-path-pattern=/resources/**
您还可使用spring.resources.static-locations
property 自定义静态资源位置(将默认值替换为目录位置列表)。根 Servlet context 路径"/"
也会自动添加为位置。
除了前面提到的“标准”静态资源位置以外,还为Webjars 内容作了一个特例。若是 jar files 包含在 Webjars 格式中,则中包含路径的全部资源都将从 jar files 提供。
若是 application 打包为 jar,请不要使用
src/main/webapp
目录。虽然这个目录是一个 common 标准,但它只能用 war 打包,若是生成一个 jar,它会被大多数 build 工具默默忽略。
Spring Boot 还支持 Spring MVC 提供的高级资源处理 features,容许使用 cache-busting 静态资源等用例或使用 version 不可知 URL 进行 Webjars。
要为 Webjars 使用 version 不可知 URL,请添加webjars-locator-core
依赖项。而后声明你的 Webjar。使用 jQuery 做为 example,添加"/webjars/jquery/jquery.min.js"
会致使"/webjars/jquery/x.y.z/jquery.min.js"
。其中x.y.z
是 Webjar version。
若是使用 JBoss,则须要声明
webjars-locator-jboss-vfs
依赖项而不是webjars-locator-core
。不然,全部 Webjars 都将解析为404
。
要使用缓存清除,如下 configuration 会为全部静态资源配置缓存清除解决方案,从而在 URL 中有效添加内容哈希,例如``:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
因为
ResourceUrlEncodingFilter
对于 Thymeleaf 和 FreeMarker 来讲是 auto-configured,所以在运行时会在模板中重写资源连接。您应该在使用 JSP 时手动声明此过滤器。目前不支持其余模板引擎,但可使用自定义模板 macros/helpers 并使用ResourceUrlProvider。
当使用例如 JavaScript 模块加载器动态加载资源时,不能重命名 files。这就是为何其余策略也获得支持并能够合并的缘由。 “固定”策略在 URL 中添加静态 version string 而不更改文件 name,以下面的示例所示:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12
使用此 configuration,位于"/js/lib/"
下的 JavaScript 模块使用固定版本控制策略("/v12/js/lib/mymodule.js"
),而其余资源仍使用内容 1(``)。
有关更多支持的选项,请参阅资源属性。
这个 feature 已在专用的博客文章和 Spring Framework 的reference 文档中进行了详细描述。
Spring Boot 支持静态和模板化欢迎页面。它首先在配置的静态内容位置中查找index.html
文件。若是找不到,则查找index
模板。若是找到任何一个,它将自动用做 application 的欢迎页面。
Spring Boot 在配置的静态内容位置和 classpath 的根(在该 order 中)中查找favicon.ico
。若是存在这样的文件,它将自动用做 application 的 favicon。
Spring MVC 能够经过查看请求路径并将其与 application 中定义的映射相匹配来将传入的 HTTP 请求映射处处理程序(对于 example,注解在 Controller 方法上)。
Spring Boot 选择默认禁用后缀 pattern 匹配,这意味着像"GET /projects/spring-boot.json"
这样的请求将不会与@GetMapping("/projects/spring-boot")
映射匹配。这被认为是Spring MVC applications 的最佳实践。这个 feature 在过去主要用于 HTTP clients,它没有发送适当的“Accept”请求 headers;咱们须要确保将正确的 Content Type 发送到 client。现在,Content Negotiation 更加可靠。
还有其余方法能够处理不一致发送正确的“接受”请求 headers 的 HTTP 客户端。咱们可使用查询参数来确保像"GET /projects/spring-boot?format=json"
这样的请求将映射到@GetMapping("/projects/spring-boot")
,而不是使用后缀匹配:
spring.mvc.contentnegotiation.favor-parameter=true
# We can change the parameter name, which is "format" by default:
# spring.mvc.contentnegotiation.parameter-name=myparam
# We can also register additional file extensions/media types with:
spring.mvc.contentnegotiation.media-types.markdown=text/markdown
若是您了解警告并仍但愿您的 application 使用后缀 pattern 匹配,则须要如下 configuration:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-suffix-pattern=true
或者,不是打开全部后缀模式,而是仅支持已注册的后缀模式更安全:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-registered-suffix-pattern=true
# You can also register additional file extensions/media types with:
# spring.mvc.contentnegotiation.media-types.adoc=text/asciidoc
Spring MVC 使用WebBindingInitializer
为特定请求初始化WebDataBinder
。若是您建立本身的ConfigurableWebBindingInitializer
@Bean
,Spring Boot 会自动配置 Spring MVC 以使用它。
与 REST web services 同样,您也可使用 Spring MVC 来提供动态 HTML 内容。 Spring MVC 支持各类模板技术,包括 Thymeleaf,FreeMarker 和 JSP。此外,许多其余模板引擎包括他们本身的 Spring MVC 集成。
Spring Boot 包括对如下模板引擎的 auto-configuration 支持:
若是可能,应该避免使用 JSP。使用嵌入式 servlet 容器时有几个已知限制。
当您使用其中一个模板引擎和默认的 configuration 时,您的模板将从src/main/resources/templates
自动获取。
根据您运行 application 的方式,IntelliJ IDEA 以不一样方式命令 classpath。 从主方法中运行 IDE 中的 application 致使与使用 Maven 或 Gradle 或从其打包的 jar 运行 application 时不一样的 ordering。这可能致使 Spring Boot 没法在 classpath 上找到模板。若是遇到此问题,能够从新排序 IDE 中的 classpath 以首先放置模块的 classes 和 resources。或者,您能够配置模板前缀以搜索 classpath 上的每一个
templates
目录,以下所示:classpath*:/templates/
。
默认状况下,Spring Boot 提供/error
映射,以合理的方式处理全部错误,并在 servlet 容器中注册为“global”错误页面。对于机器客户端,它会生成一个 JSON 响应,其中包含错误,HTTP 状态和 exception 消息的详细信息。对于浏览器客户端,有一个“whitelabel”错误视图,以 HTML 格式呈现相同的数据(要自定义它,添加一个解析为error
的View
)。要彻底替换默认行为,能够实现ErrorController
并注册该类型的 bean 定义,或者添加ErrorAttributes
类型的 bean 以使用现有机制但替换内容。
BasicErrorController
能够用做自定义ErrorController
的 base class。若是要为新的 content type 添加处理程序(默认状况下是专门处理text/html
并为其余全部内容提供后备),这将特别有用。为此,请扩展BasicErrorController
,添加具备produces
属性的@RequestMapping
的公共方法,并建立新类型的 bean。
您还能够定义一个使用@ControllerAdvice
注释的 class,以便为特定控制器 and/or exception 类型自定义 JSON 文档 return,以下面的示例所示:
@ControllerAdvice(basePackageClasses = AcmeController.class) public class AcmeControllerAdvice extends ResponseEntityExceptionHandler { @ExceptionHandler(YourException.class) @ResponseBody ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) { HttpStatus status = getStatus(request); return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status); } private HttpStatus getStatus(HttpServletRequest request) { Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); if (statusCode == null) { return HttpStatus.INTERNAL_SERVER_ERROR; } return HttpStatus.valueOf(statusCode); } }
在前面的示例中,若是由与AcmeController
在同一个包中定义的控制器抛出,则使用CustomErrorType
POJO 的 JSON 表示而不是ErrorAttributes
表示。
若是要为给定状态 code 显示自定义 HTML 错误页面,能够将文件添加到/error
文件夹。错误页面能够是静态 HTML(即,添加到任何静态资源文件夹下),也可使用模板构建。文件的 name 应该是确切的状态 code 或系列掩码。
例如,要 map 404
到静态 HTML 文件,您的文件夹结构以下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
要使用 FreeMarker 模板 map 全部5xx
错误,您的文件夹结构以下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.ftl
+- <other templates>
对于更复杂的映射,您还能够添加实现ErrorViewResolver
接口的 beans,以下面的示例所示:
public class MyErrorViewResolver implements ErrorViewResolver {
您还可使用常规的 Spring MVC features,例如@ExceptionHandler 方法和@ControllerAdvice。 ErrorController
而后选择任何未处理的 exceptions。
对于不使用 Spring MVC 的 applications,可使用ErrorPageRegistrar
接口直接注册ErrorPages
。这种抽象直接与底层嵌入式 servlet 容器一块儿工做,即便你没有 Spring MVC DispatcherServlet
也能正常工做。
@Bean public ErrorPageRegistrar errorPageRegistrar(){ return new MyErrorPageRegistrar(); } // ... private static class MyErrorPageRegistrar implements ErrorPageRegistrar { @Override public void registerErrorPages(ErrorPageRegistry registry) { registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400")); } }
若是你注册一个
ErrorPage
的路径由Filter
处理(如 common 与bb 框架,如 Jersey 和 Wicket),那么Filter
必须显式注册为ERROR
调度程序,以下所示例:
@Bean public FilterRegistrationBean myFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new MyFilter()); ... registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class)); return registration; }
请注意,默认FilterRegistrationBean
不包括ERROR
调度程序类型。
CAUTION:When 部署到 servlet 容器,Spring Boot 使用其错误页面过滤器将具备错误状态的请求转发到相应的错误页面。若是还没有提交响应,则只能将请求转发到正确的错误页面。缺省状况下,WebSphere Application Server 8.0 及更高版本在成功完成 servlet 的服务方法后提交响应。您应该经过将com.ibm.ws.webcontainer.invokeFlushAfterService
设置为false
来禁用此行为。
若是您开发使用超媒体的 RESTful API,Spring Boot 为 Spring HATEOAS 提供 auto-configuration,适用于大多数 applications。 auto-configuration 取代了使用@EnableHypermediaSupport
的须要,并注册了许多 beans 以简化 building hypermedia-based applications,包括LinkDiscoverers
(用于 client 侧支持)和ObjectMapper
配置为正确地将响应编组到所需的表示中。经过设置各类spring.jackson.*
properties 或(若是存在)Jackson2ObjectMapperBuilder
bean 来自定义ObjectMapper
。
您可使用@EnableHypermediaSupport
控制 Spring HATEOAS 的 configuration。请注意,这样作会禁用前面描述的ObjectMapper
自定义。
Cross-origin 资源共享(CORS)是由大多数浏览器实现的W3C 规范,它容许您以灵活的方式指定哪一种 cross-domain 请求被受权,而不是使用一些安全性较低且功能较弱的方法,如 IFRAME 或 JSONP。
截至 version 4.2,Spring MVC 支持 CORS。在 Spring Boot application 中使用控制器方法 CORS configuration和@CrossOrigin annotations 不须要任何特定的 configuration。能够经过使用自定义的addCorsMappings(CorsRegistry)
方法注册WebMvcConfigurer
bean 来定义Global CORS configuration
@Configuration public class MyConfiguration { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**"); } }; } }