這一篇文章講的是Spring Web MVC各部分的配置方法,包括Java代碼配置和XML文件配置以及MVC命名空間的使用方法。
啟用MVC Java配置和XML命名空間
默認(rèn)配置
要啟用MVC Java配置(@Controller等各種注解)和XML命名空間,如果使用的是Java配置,在配置類(lèi)上再添加@EnableWebMvc注解即可。
1
2
3
4
5
|
@Configuration @EnableWebMvc public class WebAppConfig { } |
如果使用XML配置文件的話(huà),添加下面一行即可。
1
|
< mvc:annotation-driven /> |
不論使用哪種方式,都會(huì)在Spring中注冊(cè)一些組件來(lái)提供最基本的MVC功能。這些功能在文檔中說(shuō)的很清楚。我簡(jiǎn)單翻譯了一下:
上面的配置會(huì)注冊(cè)一個(gè)RequestMappingHandlerMapping,一個(gè)RequestMappingHandlerAdapter和一個(gè)ExceptionHandlerExceptionResolver來(lái)提供注解控制器和注解方法(比如@RequestMapping和@ExceptionHandler等)處理請(qǐng)求的功能。
還會(huì)啟用以下功能:
- 通過(guò)一個(gè)ConversionService實(shí)例,來(lái)進(jìn)行Spring 3 方式的類(lèi)型轉(zhuǎn)換及數(shù)據(jù)綁定支持。
- @NumberFormat格式化數(shù)字字段的支持
- @DateTimeFormat格式化Date、Calendar、Long、JodaTime類(lèi)型字段的支持。
- 在控制器方法上使用@Valid驗(yàn)證Bean的支持,如果檢測(cè)到JSR-303 Bean驗(yàn)證的實(shí)現(xiàn)。
- 一組HttpMessageConverter,用于在字符串和所需Java類(lèi)型之間進(jìn)行類(lèi)型轉(zhuǎn)換,具體的列表參見(jiàn)Spring文檔 22.16.1. Enabling the MVC Java Config or the MVC XML Namespace。
通過(guò)這些默認(rèn)配置,我們即可開(kāi)始最基本的Spring MVC使用。
自定義配置
上面提供了最基本的配置。如果需要自定義某些配置也可以。如果使用Java配置的話(huà),讓配置類(lèi)實(shí)現(xiàn)WebMvcConfigurer接口,更常用的辦法是繼承WebMvcConfigurerAdapter基類(lèi),通過(guò)重寫(xiě)基類(lèi)中的方法即可配置相關(guān)功能。
1
2
3
4
5
6
7
|
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { //有很多個(gè)方法可以重寫(xiě),來(lái)提供自定義功能 } |
如果使用XML配置文件,通過(guò)IDE的自動(dòng)補(bǔ)全功能查看一下<mvc:annotation-driven/>有哪些子屬性和子元素。
類(lèi)型轉(zhuǎn)換和格式化
默認(rèn)情況下Spring注冊(cè)了Number(包括所有基本數(shù)字類(lèi)型)和java.util.Date的類(lèi)型轉(zhuǎn)換和格式化功能。要提供類(lèi)型的轉(zhuǎn)換和格式化功能,就需要自己注冊(cè)相應(yīng)的類(lèi)型轉(zhuǎn)換器和格式化器。
如果使用Java配置的話(huà),重寫(xiě)addFormatters(FormatterRegistry registry)方法并添加相應(yīng)功能即可。
1
2
3
4
5
6
7
8
9
10
|
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addFormatters(FormatterRegistry registry) { // Add formatters and/or converters } } |
如果使用XML配置的話(huà),需要注冊(cè)一個(gè)ConversionService,然后添加到<mvc:annotation-driven>節(jié)點(diǎn)中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
< mvc:annotation-driven conversion-service = "conversionService" /> < bean id = "conversionService" class = "org.springframework.format.support.FormattingConversionServiceFactoryBean" > < property name = "converters" > < set > < bean class = "org.example.MyConverter" /> </ set > </ property > < property name = "formatters" > < set > < bean class = "org.example.MyFormatter" /> < bean class = "org.example.MyAnnotationFormatterFactory" /> </ set > </ property > < property name = "formatterRegistrars" > < set > < bean class = "org.example.MyFormatterRegistrar" /> </ set > </ property > </ bean > |
驗(yàn)證功能
Spring自己提供了一組接口和類(lèi)提供了一套驗(yàn)證功能。不過(guò)更通用的方法是使用Bean Validation進(jìn)行Java對(duì)象的驗(yàn)證,Bean Validation的一個(gè)實(shí)現(xiàn)就是Hibernate Validator。
默認(rèn)情況下當(dāng)@EnableWebMvc或<mvc:annotation-driven/>配置之后,如果Spring檢測(cè)到Bean Validation,就會(huì)自動(dòng)注冊(cè)一個(gè)LocalValidatorFactoryBean來(lái)提供驗(yàn)證功能。如果我們希望手動(dòng)處理驗(yàn)證過(guò)程,可能希望將驗(yàn)證器實(shí)例注入到控制器中,這時(shí)候就不能使用自動(dòng)注冊(cè)的LocalValidatorFactoryBean了。這時(shí)候我們可以選擇手動(dòng)注冊(cè)一個(gè)LocalValidatorFactoryBeanBean實(shí)例,然后注解@Primary讓自定義LocalValidatorFactoryBean被優(yōu)先使用。
還有一種辦法就是直接覆蓋Spring的默認(rèn)驗(yàn)證器配置。如果使用Java配置的話(huà),重寫(xiě)getValidator()方法即可。
1
2
3
4
5
6
7
8
9
10
|
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public Validator getValidator() { // return "global" validator } } |
如果使用XML配置文件,定義一個(gè)Validator然后添加到<mvc:annotation-driven>中。
1
|
< mvc:annotation-driven validator = "globalValidator" /> |
上面定義的都是全局驗(yàn)證器,我們也可以在某個(gè)控制器中定義一個(gè)局部驗(yàn)證器,然后和全局驗(yàn)證器結(jié)合起來(lái)使用。這時(shí)候需要使用@InitBinder注解方法。
1
2
3
4
5
6
7
8
9
|
@Controller public class MyController { @InitBinder protected void initBinder(WebDataBinder binder) { binder.addValidators( new FooValidator()); } } |
配置好驗(yàn)證器之后。當(dāng)Spring識(shí)別到@Valid注解的方法參數(shù)之后,就會(huì)執(zhí)行驗(yàn)證,將驗(yàn)證結(jié)果綁定到BindingResult上,我們可以在方法中訪(fǎng)問(wèn)BindingResult來(lái)獲取驗(yàn)證結(jié)果。
攔截器
我們實(shí)現(xiàn)了攔截器之后,就可以將其應(yīng)用到Web程序中。使用Java配置的話(huà),重寫(xiě)addInterceptors(InterceptorRegistry registry)方法,然后在其中添加自己的攔截器即可。如果要配置攔截路徑和排除路徑也可以在這里配置。
1
2
3
4
5
6
7
8
9
10
11
12
|
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor( new LocaleInterceptor()); registry.addInterceptor( new ThemeInterceptor()).addPathPatterns( "/**" ).excludePathPatterns( "/admin/**" ); registry.addInterceptor( new SecurityInterceptor()).addPathPatterns( "/secure/*" ); } } |
使用XML配置文件的話(huà)可以使用MVC命名空間,配置也比較簡(jiǎn)單。
1
2
3
4
5
6
7
8
9
10
11
12
|
< mvc:interceptors > < bean class = "org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /> < mvc:interceptor > < mvc:mapping path = "/**" /> < mvc:exclude-mapping path = "/admin/**" /> < bean class = "org.springframework.web.servlet.theme.ThemeChangeInterceptor" /> </ mvc:interceptor > < mvc:interceptor > < mvc:mapping path = "/secure/*" /> < bean class = "org.example.SecurityInterceptor" /> </ mvc:interceptor > </ mvc:interceptors > |
視圖控制器
這是一種定義ParameterizableViewController的簡(jiǎn)單方式,當(dāng)該控制器被請(qǐng)求的時(shí)候不會(huì)執(zhí)行任何邏輯操作,直接轉(zhuǎn)到相應(yīng)視圖。視圖控制器的常見(jiàn)用法是將網(wǎng)站的首頁(yè)直接和/請(qǐng)求映射。
使用Java配置可以這樣寫(xiě),下面的配置將/映射到名為index的視圖。
1
2
3
4
5
6
7
8
9
10
|
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController( "/" ).setViewName( "index" ); } } |
使用XML配置也很簡(jiǎn)單。
1
|
< mvc:view-controller path = "/" view-name = "index" /> |
視圖解析器
使用Java配置,只需要重寫(xiě)configureViewResolvers(ViewResolverRegistry registry)方法即可。下面配置了JSP視圖。如果需要其它視圖解析器可以參見(jiàn)其相應(yīng)文檔,以及ViewResolverRegistry的JavaDoc。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.enableContentNegotiation( new MappingJackson2JsonView()); registry.jsp() .prefix( "/WEB-INF/jsp/" ) .suffix( ".jsp" ) .viewClass(JstlView. class ); } } |
如果使用XML配置文件可以使用MVC命名空間簡(jiǎn)化配置。除了內(nèi)置的JSP解析器外,其它視圖解析器可能還需要額外的配置,這里不再細(xì)述。
1
2
3
4
5
|
< mvc:view-resolvers > < mvc:jsp prefix = "/WEB-INF/jsp/" suffix = ".jsp" view-class = "org.springframework.web.servlet.view.JstlView" /> </ mvc:view-resolvers > |
資源處理
靜態(tài)資源處理
這里說(shuō)的主要是靜態(tài)資源的處理。前面說(shuō)了很多關(guān)于控制器、視圖的知識(shí),但是如何映射CSS、JS文件,前面沒(méi)有說(shuō)明。配置方法在這里說(shuō)明。
使用Java配置的話(huà),重寫(xiě)addResourceHandlers(ResourceHandlerRegistry registry)方法,然后添加相應(yīng)的映射即可。
1
2
3
4
5
6
7
8
9
10
|
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler( "/static/**" ).addResourceLocations( "/resources/static/" ); } } |
使用XML配置文件 也同樣簡(jiǎn)單。
1
|
< mvc:resources mapping = "/static/**" location = "/resources/static/" /> |
這樣映射之后,假如我們有/resources/static/bootstrap.css文件,那么就可以使用/static/bootstrap.css路徑來(lái)訪(fǎng)問(wèn)該文件了。同樣的在視圖文件中也可以如此引用。還可以使用cache-period設(shè)置資源的過(guò)期時(shí)間,單位是秒。如果需要指定多個(gè)資源位置,可以使用逗號(hào)分隔。
資源的版本控制
有些頻繁更新的資源可能需要版本控制,強(qiáng)制讓客戶(hù)端使用最新的資源。Spring框架也支持資源的版本控制,我們需要定義資源鏈來(lái)實(shí)現(xiàn)這個(gè)功能。資源鏈由一個(gè)ResourceResolver實(shí)例和多個(gè)ResourceTransformer實(shí)例組成。內(nèi)建的VersionResourceResolver能滿(mǎn)足我們的大部分需求,它可以定義一些策略來(lái)配置版本控制,例如FixedVersionStrategy會(huì)依據(jù)日期、版本號(hào)或者其他東西作為版本;ContentVersionStrategy會(huì)計(jì)算資源的MD5值。
ContentVersionStrategy策略是一個(gè)不錯(cuò)的策略,不過(guò)由于它會(huì)計(jì)算MD5,所以開(kāi)銷(xiāo)比較大, 因此在使用這種策略的時(shí)候最好打開(kāi)緩存來(lái)提高性能。
如果使用Java配置的話(huà),和前面的例子差不多,只不過(guò)需要多調(diào)用resourceChain(true)等方法并添加相應(yīng)的版本資源解析器和版本策略。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler( "/static/**" ) .addResourceLocations( "/resources/static/" ) .resourceChain( true ).addResolver( new VersionResourceResolver().addContentVersionStrategy( "/**" )); } } |
下面是使用XML配置的例子。
1
2
3
4
5
6
7
8
9
10
|
< mvc:resources mapping = "/static/**" location = "/resources/static/" > < mvc:resource-chain > < mvc:resource-cache /> < mvc:resolvers > < mvc:version-resolver > < mvc:content-version-strategy patterns = "/**" /> </ mvc:version-resolver > </ mvc:resolvers > </ mvc:resource-chain > </ mvc:resources > |
默認(rèn)Servlet
開(kāi)啟這個(gè)選項(xiàng)可以讓DispatcherServlet處理根路徑/下的靜態(tài)資源請(qǐng)求,說(shuō)的詳細(xì)點(diǎn)就是假如靜態(tài)文件是webapp/css/site.css,那么我們可以直接通過(guò)/css/site.css來(lái)訪(fǎng)問(wèn)這個(gè)文件。如果不啟用這個(gè)功能,那么靜態(tài)文件就只能映射到其他路徑下比如/static。
這個(gè)配置項(xiàng)實(shí)際上會(huì)配置一個(gè)DefaultServletHttpRequestHandler,映射到路徑/**,并具有最低的優(yōu)先級(jí)。由于DefaultServletHttpRequestHandler會(huì)將所有請(qǐng)求轉(zhuǎn)發(fā)到默認(rèn)Servlet,所以它必須被配置為最后一個(gè)處理映射才行。
使用Java配置的話(huà),重寫(xiě)configureDefaultServletHandling(...)方法并開(kāi)啟該選項(xiàng)。
1
2
3
4
5
6
7
8
9
10
|
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } } |
如果使用XML配置的話(huà),添加以下行。
1
|
< mvc:default-servlet-handler /> |
消息轉(zhuǎn)換
如果我們需要覆蓋Spring默認(rèn)的消息轉(zhuǎn)換器,可以重寫(xiě)configureMessageConverters(List<HttpMessageConverter<?>> converters)方法,然后向converters參數(shù)添加我們自己的消息轉(zhuǎn)換器。如果僅僅希望增加自己的類(lèi)型轉(zhuǎn)換器,重寫(xiě)extendMessageConverters()方法。
使用XML配置文件的話(huà),可以使用MVC命名空間。
1
2
3
4
5
6
7
8
9
10
|
< mvc:annotation-driven > < mvc:message-converters > < bean class = "org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" > < property name = "objectMapper" ref = "objectMapper" /> </ bean > < bean class = "org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter" > < property name = "objectMapper" ref = "xmlMapper" /> </ bean > </ mvc:message-converters > </ mvc:annotation-driven > |
高級(jí)自定義配置
上面的配置使用Spring提供的簡(jiǎn)化類(lèi)或者M(jìn)VC命名空間,幫助我們快速配置功能。有時(shí)候可能需要更高級(jí)的功能定制,這樣就需要自己處理這些底層Bean的初始化和屬性設(shè)置。
Java配置自定義
我們先來(lái)看一看@EnableWebMvc注解的定義。可以看到它還使用了一個(gè)@Import注解,引用了DelegatingWebMvcConfiguration類(lèi)。當(dāng)我們注解@EnableWebMvc的時(shí)候,實(shí)際上初始化和配置的底層類(lèi)就是DelegatingWebMvcConfiguration。
1
2
3
4
5
6
|
@Retention (RetentionPolicy.RUNTIME) @Target (ElementType.TYPE) @Documented @Import (DelegatingWebMvcConfiguration. class ) public @interface EnableWebMvc { } |
因此我們?nèi)绻远xMVC的話(huà),第一件事就是移除注解@EnableWebMvc。然后繼承DelegatingWebMvcConfiguration類(lèi)并實(shí)現(xiàn)它的requestMappingHandlerAdapter()方法。
1
2
3
4
5
6
7
8
9
10
|
@Configuration public class WebConfig extends DelegatingWebMvcConfiguration { @Override @Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { // 在這里進(jìn)行高級(jí)配置 } } |
在項(xiàng)目中DelegatingWebMvcConfiguration子類(lèi)和@EnableWebMvc注解配置類(lèi)只能存在一個(gè),因?yàn)樗鼈冏龅氖虑閷?shí)際上是一樣的。而且這里的配置并不影響Spring MVC的其他配置。
自定義MVC命名空間配置
這里的自定義配置更困難,因?yàn)镾pring沒(méi)有提供相應(yīng)的配置機(jī)制。如果實(shí)在需要自定義MVC命名空間配置,可以考慮使用Spring提供的BeanPostProcessor機(jī)制,在檢測(cè)到Bean之后修改它的值。
1
2
3
4
5
6
7
8
9
10
|
@Component public class MyPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException { if (bean instanceof RequestMappingHandlerAdapter) { // 在這里自定義屬性 } } } |
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://www.jianshu.com/p/f9925c4e6211