《Spring In Action(第4版)》閱讀總結(三)Spring Web

構建Spring Web應用程序

  1. 映射請求到Spring控制器
  2. 透明地綁定表單參數
  3. 校驗表單提交

Spring MVC 基於模型-視圖-控制器(Model-View-Controller,MVC)模式實現,幫助構建靈活和鬆耦合的Web應用程序前端

Spring MVC起步

Spring MVC 請求流程

Spring MVC框架將請求在調度Servler、處理器映射(handler mapping)、控制器以及視圖解析器(view resolver)之間移動java

clipboard.png

1:請求訪問前端控制器(DispatcherServlet);
2:DispatcherServlet查詢一個或多個處理器映射(handler mapping),經過請求路徑肯定控制器(Controller);
3:DispatcherServlet將請求發送給控制器(Controller);
4:控制器對請求進行處理返回模型和視圖名(ModelAndView);
5:DispatcherServlet查詢視圖解析器(view resolver),經過視圖名匹配一個特定的視圖實現;
6:DispatcherServlet將模型發送給視圖;
7:視圖經過模型數據渲染輸出,經過響應對象傳遞給客戶端;git

搭建Spring MVC

配置DisPatcherServlet

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

啓用Spring MVC

完成配置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 {

}

編寫基本的控制器(Controller)

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:

相關文章
相關標籤/搜索