Spring MVC 基於模型-視圖-控制器(Model-View-Controller,MVC)模式實現,幫助構建靈活和鬆耦合的Web應用程序前端
Spring MVC框架將請求在調度Servler、處理器映射(handler mapping)、控制器以及視圖解析器(view resolver)之間移動java
1:請求訪問前端控制器(DispatcherServlet);
2:DispatcherServlet查詢一個或多個處理器映射(handler mapping),經過請求路徑肯定控制器(Controller);
3:DispatcherServlet將請求發送給控制器(Controller);
4:控制器對請求進行處理返回模型和視圖名(ModelAndView);
5:DispatcherServlet查詢視圖解析器(view resolver),經過視圖名匹配一個特定的視圖實現;
6:DispatcherServlet將模型發送給視圖;
7:視圖經過模型數據渲染輸出,經過響應對象傳遞給客戶端;git
DisPatcherServlet是Spring MVC的核心。負責將請求路由到指定控制器處理。
傳統方式,DispathcherServlet會配置在web.xml文件中;
藉助於Servlet 3規範和Spring3.1功能加強,可實現Java配置DispatcherServletweb
package demo; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class DemoWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected String[] getServletMappings() { return new String[]{ "/" }; //將DispatcherServlet 映射到 "/" } @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[]{ RootConfig.class }; //指定Spring配置類 } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[]{ WebConfig.class }; //指定Spring MVC配置類 } }
原理:
1:在Serlvet 3環境中,Servlet容器會在類路徑中查找實現javax.servlet.ServletContainerInitializer接口的類,用來配置Servlet容器;
2:Spring經過SpringServletContainerInitializer實現了該接口,SpringServletContainerInitializer又會在容器中查找實現WebApplicationInitializer接口的類並將配置任務交給它們來完成;
3:Spring3.2引入一個便利的WebApplicationInitializer基礎實現,即AbstractAnnotationConfigDispatcherServletIni-tializer,經過繼承該類,當部署到Servler3.0容器中時,容器就會自動發現它,並用它來配置Servlet上下文。正則表達式
繼承AbstractAnnotationConfigDispatcherServletInitializer需重寫三個方法:
1:getServletMappings() 設置DispatcherServlet映射、spring
在講另外兩個方法以前,先了解一下Dispatcher和一個Servler監聽器(ContextLoaderListener)的關係
關於兩個應用上下文的關係
DispatcherServlet啓動的時候,會建立Spring應用上下文容器,並加載配置文件或配置類中所聲明的bean。
Spring Web應用中,一般還有會另一個應用上下文,由ContextLoaderListener建立。後端
咱們一般但願DispathcerServlet加載包含Web組件的bean,如控制器、視圖解析器以及處理器映射。
而ContextLoaderListener加載應用中其餘bean,這些bean一般是加載驅動應用後端的中間層和數據層組件。數組
2:getServletConfigClasses() 返回@Configuration註解類並定義DispatcherServlet應用上下文中的bean。
3:getRootConfigClasses() 返回@Configuration註解類並定義ContextLoaderListener應用上下文中的bean。tomcat
完成配置DispatcherServlet後,需啓用Spring MVC。app
傳統方式:使用XML配置,使用<mvn:annotation-driven>啓用註解驅動的Spring MVC
使用Java配置:@EnableWebMvc註解 啓用Spring MVC
package demo; @Configuration @EnableWebMvc @ComponentScan(basePackages = "demo.web") // 控制器、視圖解析器以及處理器映射。 public void WebConfig extends WebMvcConfigurerAdapter { @Bean public ViewResolver viewResolver () { //設置視圖解析器 InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; } @Override //繼承自WebMvcConfigurerAdapter 用於配置靜態資源的處理 public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } } package demo; @Configuration @ComponentScan(basePackages = "demo", // 加載驅動應用後端的中間層和數據層組件 excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class) } ) public class RootConfig { }
package demo.web; @Controller //聲明爲一個控制器,與@Component做用相同,語義不一樣,更具備可讀性 public class HomeController { @RequestMapping(value = "/", method = RequestMethod.GET) // 處理對"/"的GET請求 public String home() { return "home"; //視圖名爲home } }
基於以上配置,咱們可使用一個簡單的Spring MVC訪問頁面,
爲助於讀者理解,提供一份開發部署流程,僅供參考:
1 配置DispatcherServlet,編寫DemoWebAppInitializer(src.main.java.demo包)
2 開啓Spring MVC,編寫WebConfig 和 RootConfig (src.main.java.demo包)
3 編寫控制器,HomeController(src.main.java.demo.web包)
4 編寫頁面,home.jsp(src.main.webapp.WEB-INF.views)
4 打war包(此過程應該會提示缺乏web.xml,可在WEB-INF下添加web.xml 或 配置maven-war-plugin插件忽略web.xml)
5 部署war包至tomcat便可(注意Tomcat版本。理論上至少須要支持Servlet 3的Tomcat容器)
//關於斷言 import static org.junit.Assert.assertEquals; //此處經過靜態引入assertEquals靜態方法 import org.junit.Test; import demo.web.HomeController; public class HomeControllerTest { @Test public void testHomePage() throws Exception { HelloController controller = new HelloController(); assertEquals("home",controller.home()); //經過斷言判斷controller.home()返回的值是否爲"home",不是則報錯。 }
上述測試僅調用home(),並斷言返回包含"home"值的String,而不是站在Spring MVC控制器的視角進行測試。
正確的測試應該是發送"/"的GET請求會調用home()方法,並真正判斷"home"是視圖的名稱。
Spring3.2開始支持第控制器視角的測試。經過mock Spring MVC並針對控制器執行HTTP請求的測試機制。
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*; import org.junit.Test; import org.springframework.test.web.servlet.MockMvc; import demo.web.HomeController; public class HomeControllerTest { @Test public void testHomePage() throws Exception { HelloController controller = new HelloController(); MockMvc mockMvc = standaloneSetup(controller).build(); //構建MockMvc mockMvc.perform(get("/")) // 執行 "/"GET請求 .andExpect(view().name("home")); // 預期獲得home視圖 }
@Controller @RequestMapping("demo") \\當控制器在類級別上添加該註解,這個註解會應用到控制器的全部處理器方法上。 public void DemoController { @RequestMapping("demo") \\此方法路徑爲\demo\demo public String demo () { return "demo"; } }
@RequestMapping({"/","/demo"}) 支持多個路徑映射
有三種方式
//方式1 Model(本質是一個Map,即 key-value 對的集合) public String demo(Model model) { //未指定key時,key依據值類型推斷得出(List<String>:stringList,String:string等) model.addAttribute(createList()); return "demo"; } //方式2 Map public String demo(Map model) { model.put("list",createList()); return "demo"; } //方式3 此方式即沒返回視圖名稱,也沒顯式設定模型 public List<String> demo() { //(視圖名稱由請求路徑決定,返回的對象會添加到模型中,key由其類型推斷,相似方式1) return createList(); } public List<String> createList() { List<String> list = new ArrayList<String>(); list.add("A"); list.add("B"); return list; }
Spring MVC容許以多種方式傳遞參數
1:查詢參數(Query Parameter)
2:表單參數(Form Parameter)
3:路徑變量(Path Variable)
1基本類型 2 包裝類型 3 java bean
默認以參數名接參
@RequestParam
value、name 設置參數名(與請求參數名匹配)
required 設置參數是否必傳
defaultValue 設置默認值
1 設置路徑參數佔位符
@RequestMapping("/book/{id}")
2 接受路徑參數
public String getBook(@PathVariable Long id) {...}
@PathVariable
value、name 設置參數名(與路徑參數名匹配)
required 設置參數是否必傳
傳輸少許數據時,查詢參數 和 路徑參數都很適合
傳遞不少數據時,一般是表單提交的數據
表單的數據每每較多,可以使用java Bean接受參數,Spring MVC會將請求參數中與bean屬性同名的進行賦值,並返回bean實例。
避免校驗邏輯弄亂處理器代碼,可以使用Spring對Java校驗API(Java Validation API,又稱JSR-303)的支持。
Spring3.0開始,Spring MVC中提供了對Java校驗API的支持。只需導入該Java API的實現便可,如Hibernate Validator
將註解定義到Java Bean字段屬性上,在接受參數處對待檢驗的參數添加 @Valid 便可
@AssertFalse | 所註解的元素必須爲Boolean類型,且值爲false |
@AssertTrue | 所註解的元素必須爲Boolean類型,且值爲true |
@DecimalMax | 所註解的元素必須爲數字,且值要小於或等於給定的BigDecimalString的值 |
@DecimalMin | 所註解的元素必須爲數字,且值要大於或等於給定的BigDecimalString的值 |
@Max | 所註解的元素必須爲數字,而且它的值要小於或等於給定的值 |
@Min | 所註解的元素必須爲數字,而且它的值要大於或等於給定的值 |
@Digits | 所註解的元素必須爲數字,且值必須有指定的位數 |
@Future | 所註解的元素必須爲一個未來的日期 |
@Past | 所註解元素必須爲一個已過去的日期 |
@NotNull | 所註解元素的值必須不能爲null |
@Null | 所註解元素的值必須爲null |
@Pattern | 所註解元素必須匹配給定的正則表達式 |
@Size | 所註解的元素的值必須是String、集合或數組,而且它的長度要符合給定的範圍 |
校驗出錯時,能夠經過Errors對象進行訪問,此對象已做爲processRegistration()方法參數。(需注意,Errors參數要緊跟在帶有@Valid註解的參數後面)
processRegistration()方法所作的第一件事就是調用Errors.hasErrors()來檢查是否有錯誤。
請求轉發 forward:請求重定向 redirect: