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/**"); } }; } }