Spring in Action——SpringMVC起步
跟蹤Spring MVC請求 每當使用者在Web瀏覽器中點選連結或者提交表單的時候,請求就開始工作了。
對請求的工作描述就像是快遞投送員。請求是一個非常繁忙的傢伙。從離開瀏覽器開始到獲取響應返回,它會經歷好多站。在每站會留下一些資訊的同時,也會帶上其他資訊。
在請求離開瀏覽器時①,會帶有使用者所請求內容的資訊,至少會包含請求的URL。還可能帶有其他資訊,如使用者提交的表單資訊。
請求的第一站是Spring的DispatcherServlet。與大多數基於Java的Web框架一樣,SpringMVC所有請求會通過前端控制器(front controller)Servlet。在這裡一個單例項的Servlet將請求委託給應用程式的其他元件來執行實際的處理。
DispatcherSevlet的任務是將請求傳送給Spring MVC 控制器。控制器controller是用於處理請求的Spring元件。在典型的應用程式中可能有多個控制器。DispatcherServlet需要知道應該將請求傳送給哪個控制器
搭建SpringMVC
DispatcherServlet是Spring MVC的核心。在這裡請求會第一次接觸到框架,它要負責將請求路由到其他的元件之中。 按照傳統的方式,像DispatcherServlet這樣的Servlet會配置在web.xml檔案中,這個檔案會放到應用的war包裡。當然這是其中的方法之一。 另一個方法是使用Java將DispatcherServlet配置在Servlet容器中,而不會使用web.xml檔案:
package spittr.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpittrWebAppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer{
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {RootConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {WebConfig.class};
}
protected String[] getServletMappings() {
//將dispathcer對映到“/”
return new String[]{"/"};
}
}
這裡需要知道3個方法分別代表什麼: 第一個是getServletMappings(),它會將一個或多個路徑對映到DispatvherServlet上。在本例中,它對映的是"/",表示它會應用預設Servlet。它會處理進入應用的所有請求。 要知道第二個第三個方法,我們還需要重新認識一下AbstractAnnotationConfigDispatcherServletInitializer:
AbstractAnnotationConfigDispatcherServletInitializer會同時建立兩個應用上下文,一個(DispatcherServlet)用於載入包含Web元件的bean,如控制器、檢視解析器以及處理器對映;另一個(ContextLoaderListener)用於載入其他bean,這些bean通常是驅動應用後端的中間層和資料層元件。
第二個方法getServletConfigClasses()會返回帶有@Configuration註解的類將會用來定義DispatcherServlet應用上下文中的bean。 第三個方法getRootConfigClasses()會返回帶有@Configuration註解的類將會用來配置ContextLoaderLisener建立的應用上下文中的bean。
啟動SpringMVC
我們所能建立的最簡單的SpringMVC配置就是一個帶有@EnableWebMvc
註解的類,這個類是使用第二個方法getServletConfigClasses()返回的:
package spittr.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@EnableWebMvc
public class WebConfig {
}
雖然這個配置可以執行起來,也的確可以啟用SpringMVC,但是還有不少問題要解決:
- 沒有配置檢視解析器。如果這樣的話,Spring會預設使用BeanNameViewResolver,這個檢視解析器會查詢ID與檢視名稱匹配的bean,並且查詢bean要實現的View介面,它以這樣的方式來解析檢視。
- 沒有啟用元件掃描。所以需要顯示宣告。
- DispatcherServlet會對映為預設的Servlert。這樣的話,它會處理所有的請求,包括對靜態資源的請求(大多數情況下,這可能不是你想要的效果)。
因此,我們需要在WebConfig中加入程式碼彌補以上三個缺點:
package spittr.config;
import ...
@Configuration
@EnableWebMvc//啟用springmvc
@ComponentScan("spittr.web")//掃描spittr.web包
public class WebConfig extends WebMvcConfigurerAdapter{
@Bean
public ViewResolver viewResolver(){
//配置JSP檢視解析器
InternalResourceViewResolver resolver=
new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views");//字首
resolver.setSuffix(".jsp");//字尾為jsp檔案
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer){
//配置靜態資源的處理
configurer.enable();
}
}
我們加入了@ComponentScan(包名)
來查詢元件。稍後你就會看到,我們所編寫的控制器將會帶有@Controller
註解,這會使其成為元件掃描時的候選bean。因此,我們不需要在配置類中顯示宣告任何的控制器。
另外除了在程式碼中詳細說明的檢視解析器。還有configureDefaultServletHandling (DefaultServletHandlerConfigurer configurer)方法, 它通過enable(),將對靜態資源的請求轉發的Servlet容器中預設的Servlet上,而不是使用DispatcherServlet本身來處理此類請求。
那麼RootConfig如何配置呢:
package spittr.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan(basePackages={"spittr"},
excludeFilters={
@Filter(type=FilterType.CUSTOM, value=EnableWebMvc.class)
})
public class RootConfig {
}