第五章構建Spring Web應用程序——SpringMVC起步
跟蹤Spring MVC的請求
註:流程:
1)請求離開瀏覽器到達的第一站就是前端控制器,在這裏一個單例的Servlet將請求委托給應用程序的其他組件來執行實際處理。DispatcherServlet就是Spring MVC中的前端控制器(front controller)。
2)DispatcherServlet將請求發送給Spring MVC的控制器(controller),控制器是用於處理請求的Spring組件,一個應用程序中會有一(多)個控制器。但是DispatcherServlet需要知道將請求發送給哪個控制器,所以DispatcherServlet會查詢一(多)個處理器映射
3)一旦選擇了合適的控制器,DispatcherServlet會將請求發送給選中的控制器。到了控制器,請求會卸下其負載(攜帶的用戶信息)並耐心等待控制器處理信息。實際上,設計良好的控制器本身只處理很少甚至不處理工作,而是將業務邏輯委托給一(多)個服務對象進行處理。
4)控制器在完成邏輯處理後,會產生信息,這些信息返回給用戶並在瀏覽器上顯示。這些信息稱為模型(model),信息也會發送給一個視圖(View)。
實際上如果采用前後端分離的話,那麽後端是不會返回視圖的,僅僅會返回json數據跟前端進行交互。
5)控制器做的最後一步是將數據模型打包,並且標示出用於渲染輸出的視圖名。它接下來會將請求同模型和視圖名一起發給DispatcherServlet,這樣控制器就不會與特定的視圖耦合,傳遞給DispatcherServlet的視圖名並不直接表示某個特定的JSP。實際上它並不確定視圖就是jsp。相反僅僅是只傳遞一個邏輯名稱,這個名字會查找並產生真正的視圖。DispatcherServlet會使用視圖解析器將邏輯名稱轉化為一個真正的視圖。
7)DispatcherServlet已經成功渲染了視圖,請求將交付給模型數據。請求的任務就完成了。視圖將使用模型數據渲染輸出,這個輸出會通過響應對象傳遞給客戶端。
搭建Spring MVC
配置DispatcherServlet
在Servlet3規範和Spring3.1的幫助下我們可以實現不使用web.xml,而是將DispatcherServlet配置在Servlet容器中。
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//將DispatcherServlet映射到"/"
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
//指定配置類
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{Webconfig.class};
}
}
AbstractAnnotationConfigDispatcherServletInitializer剖析
在Servlet3.0環境,容器會在類路徑中查找實現了javax.servlet.ServletContainerInitailizer接口的類。如果有的話就會用它來配置Servlet容器。
Spring提供了這個類的實現:SpringServletContainerInitializer,這個類又會查找實現WebApplicationInitializer的類並將配置的任務交給他們。
在Spring3.2又引入了一個WebApplicationInitializer基礎實現,這就是AbstractAnnotationConfigDispatcherServletInitializer。
我們自己的WebAppInitializer實現了AbstractAnnotationConfigDispatcherServletInitializer,所以只要部署到Servlet3.0容器中,容器就會自動發現他,並使用它來發現Servlet上下文。
只需要重寫其中的三個方法就ok了。
getServletMappings(),它會將一(多)個路徑映射到DispatcherServlet。
getRootConfigClasses():加載
getServletConfigClasses():
兩個應用上下文之間的關系
DispatcherServlet與ContextLoaderListener。
DispatcherServlet加載的上下文是當前Servlet的上下文。加載web組件的bean,如控制器、視圖解析器、以及處理器映射器等。
而ContextLoaderListener加載的上下文是全局上下文。加載的通常是驅動應用後端的中間層或者數據層組件。
註:DispatcherServlet是可以多實現的,每一個DispatcherServlet都有自己的上下文,就是通過getServletConfigClasses()獲取。而對於整個應用來說也有自己的上下文,這個上下文是由ContextLoaderListener進行加載的。
AbstractAnnotationConfigDispatcherServletInitializer會同時創建DispatcherServlet與ContextLoaderListener。
getServletConfigClasses()會返回帶有@Configuration註解的類將用來定義DispatcherServlet應用上下文的bean。
getRootConfigClasses()會返回帶有@Configuration註解的類將用來定義ContextLoaderListener創建的應用上下文的bean。
本例中,根配置定義在RootConfig中,DispatcherServlet的配置聲明在WebConfig中。
啟用Spring MVC
最簡單的SpringMVC配置(帶有@EnableWebMvc註解的類):
@Configuration
@EnableWebMvc
public class WebConfig {
}
可以通過它,運行SpringMVC,但是還有問題需要解決。
1)沒有視圖解析器。Spring會默認使用BeanNameView-Resolver,這個視圖解析器會查找ID與視圖名稱匹配的bean,並且查找的bean要實現View接口,他以這樣的方式解析視圖。
2)沒有啟動組件掃描。Spring只能找到顯示聲明在配置類中的控制器。
3)DispatcherServlet會映射為應用默認的Servlet,它會處理所以請求,包括靜態資源的請求。
修改一下:最小但可用的SpringMVC配置。
@Configuration
//啟用SpringMVC
@EnableWebMvc
//啟用組件掃描
@ComponentScan("com.learn.spring.five.dispatcherservlet.web")
public class WebConfig extends WebMvcConfigurerAdapter{
//配置jsp視圖解析器
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
//配置靜態資源的處理
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
我們添加了@ComponentScan註解,可以對對應包來查找組件。我們可以通過@Controller註解實現控制器組件。
添加了ViewResolver bean,其實是InternalResourceViewResolver,這個視圖解析器會幫助我們查找jsp文件,且會幫我們加上前後綴。
擴展了WebMvcConfigurerAdapter並重寫了configureDefaultServletHandling()方法,通過DefaultServletHandlerConfigurer的enable()方法,DispatcherServlet將對靜態資源的請求轉發到Servlet容器中默認的Servlet上,而不是DispatcherServlet本身處理此類方法。
本章節聚焦於web開發,RootConfig會相對簡單:
@Configuration
@ComponentScan(basePackages = {"com"},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = EnableWebMvc.class)
})
public class RootConfig {
}
模擬背景
User(應用用戶)和state(用戶發布的狀態)。
類似於微博的一款應用背景。
第五章構建Spring Web應用程序——SpringMVC起步