SSM中 Spring MVC配置
傳統(tǒng)的web.xml配置
web.xml
<!-- 指定Spring Bean的配置文件所在目錄。默認(rèn)配置在WEB-INF目錄下 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<!-- 配置Spring監(jiān)聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 添加對(duì)SpringMVC的支持 -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 啟用annotation -->
<annotation-driven/>
<!-- spring掃描的包 -->
<context:component-scan base-package="spittr.web"/>
<!-- DispatcherServlet不處理靜態(tài)資源,交給服務(wù)器默認(rèn)的servlet處理 -->
<default-servlet-handler/>
<!-- 視圖渲染器 -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前綴 -->
<beans:property name="prefix" value="/WEB-INF/views/"/>
<!-- 后綴 -->
<beans:property name="suffix" value=".jsp"/>
</beans:bean>
</beans:beans>
基于java配置的方式
現(xiàn)在JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer可以看做是Web.xml的替代,它是一個(gè)接口。通過實(shí)現(xiàn)WebApplicationInitializer,在其中可以添加servlet,listener等,在加載Web項(xiàng)目的時(shí)候會(huì)加載這個(gè)接口實(shí)現(xiàn)類,從而起到web.xml相同的作用。
SpittrWebAppInitializer 主配置類
//擴(kuò)展自Abstrac~Initializer的任意類,都會(huì)自動(dòng)地配置Dispatcher-Servlet和Spring應(yīng)用上下文
//spring的應(yīng)用上下文會(huì)位于程序的Servlet上下文之中
public class SpittrWebAppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
//映射“/”,表示會(huì)使用默認(rèn)的Servlet
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
@Override
protected Filter[] getServletFilters() {
final CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceEncoding(true);
return new Filter[] { encodingFilter };
}
}
我們創(chuàng)建的SpittrWebAppInitializer這個(gè)類是繼承了
AbstractAnnotationConfigDispatcherServletInitializer,其繼承關(guān)系為:
AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer implements WebApplicationInitializer
AbstractDispatcherServletInitializer對(duì)DispatcherServlet進(jìn)行了自動(dòng)配置和初始化;AbstractContextLoaderInitializer初始化和配置了Spring應(yīng)用的上下文。因此,任意繼承自這個(gè)類的類都會(huì)通過創(chuàng)建DispatcherServlet和ContextLoaderListener,自動(dòng)配置DispatcherServlet和Spring應(yīng)用上下文,但是真正完成配置上下文的是WebApplicationInitializer接口。
WebApplicationInitializer接口
WebApplicationInitializer接口是如何完成配置的呢?其只有一個(gè)方法onStartup,看不出什么頭緒。但是,在這個(gè)包下有另外一個(gè)類,SpringServletContainerInitializer。
public interface WebApplicationInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer) waiClass.newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
SpringServletContainerInitializer實(shí)現(xiàn)了ServletContainerInitializer接口,其在web容器啟動(dòng)時(shí)為提供給第三方組件機(jī)會(huì)做一些初始化的工作,例如注冊(cè)servlet或者filtes等,servlet規(guī)范中通過ServletContainerInitializer實(shí)現(xiàn)此功能。每個(gè)框架要使用ServletContainerInitializer就必須在對(duì)應(yīng)的jar包的META-INF/services 目錄創(chuàng)建一個(gè)名為javax.servlet.ServletContainerInitializer的文件,文件內(nèi)容指定具體的ServletContainerInitializer實(shí)現(xiàn)類,那么,當(dāng)web容器啟動(dòng)時(shí)就會(huì)運(yùn)行這個(gè)初始化器做一些組件內(nèi)的初始化工作。
一般伴隨著ServletContainerInitializer一起使用的還有HandlesTypes注解,通過HandlesTypes可以將HandlesTypes指定的類或者實(shí)現(xiàn)該接口的類注入到SpringServletContainerInitializer的onStartup方法作為參數(shù)傳入。
Tomcat容器的ServletContainerInitializer機(jī)制的實(shí)現(xiàn),主要交由Context容器和ContextConfig監(jiān)聽器共同實(shí)現(xiàn),ContextConfig監(jiān)聽器負(fù)責(zé)在容器啟動(dòng)時(shí)讀取每個(gè)web應(yīng)用的WEB-INF/lib目錄下包含的jar包的META-INF/services/javax.servlet.ServletContainerInitializer,以及web根目錄下的META-INF/services/javax.servlet.ServletContainerInitializer,通過反射完成這些ServletContainerInitializer的實(shí)例化,然后再設(shè)置到Context容器中,最后Context容器啟動(dòng)時(shí)就會(huì)分別調(diào)用每個(gè)ServletContainerInitializer的onStartup方法,并將感興趣的類作為參數(shù)傳入。
Spring Web中通常會(huì)有兩種應(yīng)用上下文,一種是Spring MVC上下文,這種上下文通過DispatcherServlet加載,對(duì)應(yīng)上邊的getServletConfigClasses()方法,另一種上下文是spring容器本身的上下文,就要通過ContextLoaderListerner創(chuàng)建,對(duì)應(yīng)的是方法getRootConfigClasses()
WebConfig.java 類
@Configuration //標(biāo)明了該類是一個(gè)配置類并且會(huì)將該類作為一個(gè)SpringBean添加到IOC容器內(nèi)
@EnableWebMvc
//通過查看@EnableWebMvc的源碼,可以發(fā)現(xiàn)該注解就是為了引入一個(gè)DelegatingWebMvcConfiguration Java 配置類。并翻看DelegatingWebMvcConfiguration的源碼會(huì)發(fā)現(xiàn)該類似繼承于WebMvcConfigurationSupport的類。
@ComponentScan("spitter.web")
public class WebConfig extends WebMvcConfigurerAdapter {
/**
* 配置JSP視圖解析器,他會(huì)查找jsp文件,在查找的時(shí)候
* 他會(huì)在視圖名稱上加一個(gè)特定的前綴和后綴
* home的視圖——解析成為/WEB-INF/views/home.jsp
* @return
*/
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver=
new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
/**
* 通過調(diào)用enable方法,我們要求DispatcherServelet將
* 對(duì)靜態(tài)資源的請(qǐng)求轉(zhuǎn)發(fā)到Servlet容器中的默認(rèn)的Servlet上,
* 不是DispatcherServelet本身處理
* @param configurer
*/
public void configureDefaultServleHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
}
WebConfig中的配置其實(shí)就是對(duì)應(yīng)web.xml中spring-mvc.xml的配置。@EnableWebMvc注解內(nèi)部使用了@Import(DelegatingWebMvcConfiguration.class),其作用是會(huì)把WebMvcConfigurationSupport當(dāng)成配置文件來用,將其中所有標(biāo)識(shí)有@Bean注解的方法配置成bean,這就成了Spring mvc的默認(rèn)配置。
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
....//省略其他方法
}
DelegatingWebMvcConfiguration繼承了WebMvcConfigurationSupport類,其setConfigurers()方法在覆蓋父類的方法之前,它會(huì)尋找容器中所有的WebMvcConfigurer實(shí)現(xiàn)類,將所有WebMvcConfigurer實(shí)現(xiàn)類中的配置組合起來,組成一個(gè)超級(jí)配置(WebMvcConfigurerAdapter是WebMvcConfigurer的實(shí)現(xiàn)類)。這樣,WebMvcConfigurationSupport中的bean發(fā)布時(shí),就會(huì)把這所有配置都帶上了。
WebMvcConfigurer接口提供的功能如下表所示:
| 配置接口 | 接口說明 |
|---|---|
| configurePathMatch | 配置HandlerMapping路徑匹配參數(shù) |
| configureContentNegotiation | 配置路徑到請(qǐng)求內(nèi)容類型轉(zhuǎn)換的相關(guān)參數(shù),如.pdf結(jié)尾的請(qǐng)求解析成PDF類型或者其它等 |
| configureAsyncSupport | 配置異步請(qǐng)求處理相關(guān)參數(shù) |
| configureDefaultServletHandling | 配置是否需要以下功能:如果一個(gè)請(qǐng)求沒有被任何Handler處理,那是否使用DefaultServletHttpRequestHandler來進(jìn)行處理? |
| addFormatters | 增加額外的Converter和Formatter |
| addInterceptors | 增加攔截器 |
| addResourceHandlers | 增加處理靜態(tài)資源的Handler |
| addCorsMappings | 配置跨域請(qǐng)求相關(guān)參數(shù) |
| addViewControllers | 使用特殊的Controller來處理指定的URL請(qǐng)求; |
| configureViewResolvers | 配置將Controller返回的視圖名稱轉(zhuǎn)換成視圖的視圖解析器; 以便進(jìn)行視圖渲染 |
| addArgumentResolvers | 添加支持個(gè)性化配置Controller的方法參數(shù)類型的Resolver。 |
| addReturnValueHandlers | 添加支持個(gè)性化處理Controller返回?cái)?shù)據(jù)類型的處理器; |
| configureMessageConverters | 配置消息轉(zhuǎn)換器; |
| extendMessageConverters | 擴(kuò)展消息轉(zhuǎn)換器 |
| configureHandlerExceptionResolvers | 配置異常處理器 |
| extendHandlerExceptionResolvers | 擴(kuò)展異常處理器 |
注意:
spring-webmvc 從5.0開始已經(jīng)廢除了WebMvcConfigurerAdapter類,對(duì)于spring mvc的配置可以通過直接實(shí)現(xiàn)WebMvcConfigurer接口來實(shí)現(xiàn)。
public class WebConfig implements WebMvcConfigurer
Spring boot
在spring boot中通過WebMvcAutoConfiguration自動(dòng)配置類已經(jīng)將配置的大部分工作完成了,可以簡(jiǎn)單的認(rèn)為,WebMvcAutoConfiguration完成了之前SpittrWebAppInitializer和WebConfig的工作,提供適用于多數(shù)應(yīng)用的自動(dòng)配置功能。自動(dòng)配置添加了以下特性:
- 引入ContentNegotiatingViewResolver和BeanNameViewResolver beans。
- 對(duì)靜態(tài)資源的支持,包括對(duì)WebJars的支持。
- 自動(dòng)注冊(cè)Converter,GenericConverter,F(xiàn)ormatter beans。
- 對(duì)HttpMessageConverters的支持。
- 自動(dòng)注冊(cè)MessageCodeResolver。
- 對(duì)靜態(tài)index.html的支持。
如果想了解詳細(xì)信息參考:https://blog.csdn.net/qq_26000415/article/details/78998669
一般情況下是不需要改動(dòng)mvc的配置的,但是如果需要添加其他mvc配置,有兩種方法:
-
全面棄用spring boot的自動(dòng)配置
- 直接繼承WebMvcConfigurationSupport在擴(kuò)展的類中重寫父類的方法
- 使用注解@Configuration + @EnableWebMvc,并繼承WebMvcConfigurationAdapter,重寫父類的方法
在spring boot自動(dòng)配置的基礎(chǔ)上添加部分配置
繼承WebMvcConfigurationAdapter,在擴(kuò)展的類中重寫父類的方法
注意:
spring boot 從2.0使用spring-webmvc 5.0因此繼承WebMvcConfigurationAdapter需要替換為實(shí)現(xiàn)WebMvcConfigurer接口
public class WebConfig implements WebMvcConfigurer
