Spring注解@EnableWebMvc使用的坑點(diǎn)及解析
Spring注解@EnableWebMvc使用坑點(diǎn)
通過注解的方式來進(jìn)行Spring4 MVC開發(fā)時(shí),我們都會在配置文件中加入<mvc:annotation-driven/>標(biāo)簽,這個(gè)配置會自動注冊了一個(gè) RequestMappingHandlerMapping、一個(gè)RequestMappingHandlerAdapter、以及一個(gè)ExceptionHandlerExceptionResolver 以支持使用注解Controller的注解方法(如@RequestMapping、@ExceptionHandler)來處理request,并開啟一系列默認(rèn)功能設(shè)置。
<!-- 開啟SpringMVC注解模式 --> <!-- 提供一系列功能:數(shù)據(jù)綁定,數(shù)字和日期format @NumberFormat, @DataTimeFormat,xml/json默認(rèn)讀寫支持--> <mvc:annotation-driven/>
如果沒有配置<mvc:annotation-driven/>,org.springframework.web.servlet.DispatcherServlet無法找到控制器并把請求分發(fā)到控制器。
添加上<mvc:annotation-driven/>后,請求會被相應(yīng)的Controller處理。然而這時(shí)訪問靜態(tài)資源可能就不好使了,怎么辦?一般可以使用 <mvc:default-servlet-handler />這個(gè)標(biāo)簽
<!-- 靜態(tài)資源默認(rèn)servlet配置 1.加入對靜態(tài)資源的處理:js/gif 2.允許使用"/"做整體映射 --> <mvc:default-servlet-handler />
所以這兩個(gè)標(biāo)簽一般放在一起使用。
在Spring Boot中使用@EnableWebMvc也可能遇到類似的問題,@EnableWebMvc是使用注解方式快捷配置Spring Webmvc的一個(gè)注解。
在使用時(shí)你可能會遇到以下問題:
- Spring Boot在application文件中的配置失效
- 在Spring Boot的自定義配置類加上@EnableWebMvc后,發(fā)現(xiàn)自動配置的靜態(tài)資源路徑(classpath:/META/resources/,classpath:/resources/,classpath:/static/,classpath:/public/)資源無法訪問。
通過查看@EnableWebMvc的源碼,可以發(fā)現(xiàn)該注解就是為了引入一個(gè)DelegatingWebMvcConfiguration 配置類,而DelegatingWebMvcConfiguration又繼承于WebMvcConfigurationSupport。也就是說,如果我們使用@EnableWebMvc就相當(dāng)于導(dǎo)入了WebMvcConfigurationSupport類,這個(gè)時(shí)候,Spring Boot的自動裝配就不會發(fā)生了,我們能用的,只有WebMvcConfigurationSupport提供的若干個(gè)配置。其實(shí)不使用@EnableWebMvc注解也是可以實(shí)現(xiàn)配置Webmvc,只需要將配置類繼承于WebMvcConfigurationSupport類即可。
- 當(dāng)使用@EnableWebMvc時(shí),加載的是WebMvcConfigurationSupport中的配置項(xiàng)。
- 當(dāng)不使用@EnableWebMvc時(shí),使用的是WebMvcAutoConfiguration引入的配置項(xiàng)。
查看一下WebMvcAutoConfiguration 的源碼:
@Configuration @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { ... }
可以看到自動配置類 WebMvcAutoConfiguration 上有條件注解
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
這個(gè)注解的意思是在項(xiàng)目類路徑中缺少 WebMvcConfigurationSupport類型的bean時(shí)改自動配置類才會生效。
有時(shí)候我們需要自己定制一些項(xiàng)目的設(shè)置,可以有以下幾種使用方式:
- @EnableWebMvc+extends WebMvcConfigurationAdapter,在擴(kuò)展的類中重寫父類的方法即可,這種方式會屏蔽springboot的@EnableAutoConfiguration中的設(shè)置
- extends WebMvcConfigurationSupport,在擴(kuò)展的類中重寫父類的方法即可,這種方式會屏蔽springboot的@EnableAutoConfiguration中的設(shè)置
- extends WebMvcConfigurationAdapter/WebMvcConfigurer,在擴(kuò)展的類中重寫父類的方法即可,這種方式依舊使用springboot的@EnableAutoConfiguration中的設(shè)置
WebMvcConfigurer 沒有暴露高級設(shè)置,如果需要高級設(shè)置 需要第二種方式繼承WebMvcConfigurationSupport或者DelegatingWebMvcConfiguration,例如:
@Configuration @ComponentScan(basePackageClasses = { MyConfiguration.class }) public class MyConfiguration extends WebMvcConfigurationSupport { @Override public void addFormatters(FormatterRegistry formatterRegistry) { formatterRegistry.addConverter(new MyConverter()); } @Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { // Create or delegate to "super" to create and // customize properties of RequestMappingHandlerAdapter } }
所以無論是使用@EnableWebMvc還是WebMvcConfigurationSupport,都會禁止Spring Boot的自動裝配@EnableAutoConfiguration中的設(shè)置( 雖然禁止了Spring boot的自動裝配,但是WebMvcConfigurationSupport本身,還是會注冊一系列的MVC相關(guān)的bean的)。
@EnableAutoConfiguration是SpringBoot項(xiàng)目的啟動類注解@SpringBootApplication的子元素,@EnableAutoConfiguration實(shí)際是導(dǎo)入EnableAutoConfigurationImportSelector和Registar兩個(gè)類,主要功能是通過SpringFactoriesLoader.loadFactoryNames()導(dǎo)入jar下面配置文件META-INF/spring.factories。我們翻spring.factories,其中就包含WebMvc自動裝配類:
... # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\ ...
并且@EnableAutoConfiguration 注解,會自動讀取 application.properties 或 application.yml 文件中的配置。因此想想前面提到的第一個(gè)問題就很明白了。
如果想要使用自動配置生效,同時(shí)又要使用部分spring mvc默認(rèn)配置的話,比如增加 viewController ,則可以將自己的配置類可以繼承 WebMvcConfigurerAdapter 這個(gè)類。不過在Spring5.0版本W(wǎng)ebMvcConfigurerAdapter 后這個(gè)類被標(biāo)記為@Deprecated了 。
* @author Rossen Stoyanchev * @since 3.1 * @deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made * possible by a Java 8 baseline) and can be implemented directly without the * need for this adapter */ @Deprecated public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer { ... }
Spring 5.0后要使用Java8,而在Java8中接口是可以有default方法的,所以這個(gè)類就沒必要了。所以我們只需要在自定義配置類中直接實(shí)現(xiàn) WebMvcConfigurer 接口就好了
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class MyWebConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/hello").setViewName("helloworld"); } }
When we access URL /hello then helloworld.jsp will run.
對于第二個(gè)問題,如果使用@EnableWebMvc了,那么就會自動覆蓋了官方給出的/static, /public, META-INF/resources, /resources等存放靜態(tài)資源的目錄。
而將靜態(tài)資源定位于src/main/webapp。當(dāng)需要重新定義好資源所在目錄時(shí),則需要主動添加上述的那個(gè)配置類,來重寫 addResourceHandlers方法。
@Configuration @EnableWebMvc public class MyWebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**") .addResourceLocations("classpath:/public/"); } }
從上述可知在SpringBoot中大多數(shù)時(shí)我們并不需要使用@EnableWebMvc注解,來看下官方的一段說明:
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.
說明:
Spring Boot 默認(rèn)提供Spring MVC 自動配置,不需要使用@EnableWebMvc注解
如果需要配置MVC(攔截器、格式化、視圖等) 請使用添加@Configuration并實(shí)現(xiàn)WebMvcConfigurer接口.不要添加@EnableWebMvc注解。
@EnableWebMvc 只能添加到一個(gè)@Configuration配置類上,用于導(dǎo)入Spring Web MVC configuration
最后,如果Spring Boot在classpath里看到有 spring webmvc 也會自動添加@EnableWebMvc。
Normally you would add @EnableWebMvc for a Spring MVC app, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath. This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet.
http://spring.io/guides/gs/rest-service/
@enablewebmvc注解有什么用途
@EnableWebMvc是使用Java 注解快捷配置Spring Webmvc的一個(gè)注解。在使用該注解后配置一個(gè)繼承于WebMvcConfigurerAdapter的配置類即可配置好Spring Webmvc。
通過查看@EnableWebMvc的源碼,可以發(fā)現(xiàn)該注解就是為了引入一個(gè)DelegatingWebMvcConfiguration Java 配置類。并翻看DelegatingWebMvcConfiguration的源碼會發(fā)現(xiàn)該類似繼承于WebMvcConfigurationSupport的類。
其實(shí)不使用@EnableWebMvc注解也是可以實(shí)現(xiàn)配置Webmvc,只需要將配置類繼承于WebMvcConfigurationSupport類即可
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
MyBatis代碼自動生成器Mybatis-Generator的使用詳解
本文詳細(xì)介紹如何在SpringBoot項(xiàng)目中使用MyBatis-Generator進(jìn)行代碼生成,包括配置文件的添加、POM依賴配置、運(yùn)行配置等步驟,通過自動生成代碼,可以簡化MyBatis的繁瑣配置和SQL編寫,提高開發(fā)效率,注意要考慮MySQL版本兼容性,以及確保路徑配置正確2024-10-10為IntelliJ IDEA配置JVM參數(shù)的兩種方法
在使用IntelliJ IDEA進(jìn)行Java開發(fā)時(shí),合理配置JVM參數(shù)對于優(yōu)化項(xiàng)目性能和資源管理至關(guān)重要,IntelliJ IDEA提供了兩種方便的方式來設(shè)置JVM參數(shù),本文將詳細(xì)介紹這兩種方法:通過工具欄編輯配置和通過服務(wù)編輯配置,需要的朋友可以參考下2024-12-12java實(shí)現(xiàn)學(xué)生教師管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)學(xué)生教師管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10java集合類arraylist循環(huán)中刪除特定元素的方法
下面小編就為大家?guī)硪黄狫ava集合類ArrayList循環(huán)中刪除特定元素的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11dm.jdbc.driver.DMException網(wǎng)絡(luò)通信異常的解決過程
最近一個(gè)項(xiàng)目里面出現(xiàn)了一個(gè)比較詭異的問題,給大家分享下,這篇文章主要給大家介紹了關(guān)于dm.jdbc.driver.DMException網(wǎng)絡(luò)通信異常的解決過程,需要的朋友可以參考下2023-02-02Java中的StampedLock實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Java中的StampedLock實(shí)現(xiàn)原理詳解,ReentrantReadWriteLock采用悲觀讀,第一個(gè)讀線程拿到鎖后,第二個(gè)/第三個(gè)讀線程可以拿到鎖,特別是在讀線程很多,寫線程很少時(shí),需要的朋友可以參考下2024-01-01