天天看點

Java架構之SpringMVC 03-RequestMapping-請求資料-響應資料

SpringMVC

SpringMVC是一種輕量級的、基于MVC的Web層應用架構。

通過一套 MVC 注解,讓 POJO 成為處理請求的控制器,而無須實作任何接口。

采用了松散耦合可插拔元件結構,比其他 MVC 架構更具擴充性和靈活性。

優點:

  1、天生與Spring架構內建,如:(IOC,AOP)

  2、支援Restful風格

  3、支援靈活的URL到頁面控制器的映射

  4、非常容易與其他視圖技術內建,如:Velocity、FreeMarker等等

  5、因為模型資料不存放在特定的API裡,而是放在一個Model裡(Map資料結構實作,是以很容易被其他架構使用)

  6、非常靈活的資料驗證、格式化和資料綁定機制、能使用任何對象進行資料綁定,

  7、更加簡單、強大的異常處理

  8、對靜态資源的支援

  9、支援靈活的本地化、主題等解析

 常用主要元件

  ① DispatcherServlet:前端控制器

  ② Controller:處理器/頁面控制器,做的是MVC中的C的事情,但控制邏輯轉移到前端控制器了,用于對請求進行處理

  ③ HandlerMapping:請求映射到處理器,找誰來處理,如果映射成功傳回一個HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象、多個HandlerInterceptor攔截器對象)

  ④ View Resolver : 視圖解析器,找誰來處理傳回的頁面。把邏輯視圖解析為具體的View,進行這種政策模式,很容易更換其他視圖技術;如InternalResourceViewResolver将邏輯視圖名映射為JSP視圖

  ⑤ LocalResolver:本地化、國際化

  ⑥ MultipartResolver:檔案上傳解析器

  ⑦ HandlerExceptionResolver:異常處理器

Spring MVC 的配置檔案

流程分析

Java架構之SpringMVC 03-RequestMapping-請求資料-響應資料

基本步驟:

  ①    用戶端請求送出到DispatcherServlet

  ②    由DispatcherServlet控制器查詢一個或多個HandlerMapping,找到處理請求的Controller

  ③    DispatcherServlet将請求送出到Controller(也稱為Handler)

  ④    Controller調用業務邏輯處理後,傳回ModelAndView

  ⑤    DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖

  ⑥    視圖負責将結果顯示到用戶端

标準的 HTTP 請求報頭

Java架構之SpringMVC 03-RequestMapping-請求資料-響應資料

@RequestMapping

1、使用@RequestMapping 注解來映射請求的 URL    

  @RequestMapping可以應用的地方

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {…}      

  請求的方式有

public enum RequestMethod {
        GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
    }      

  @RequestMapping可以為控制器指定可以處理哪些 URL 請求,将該注解中的 value 屬性值映射成URL,用戶端可以通過該URL請求到指定類中的方法。

    1)在控制器的類定義或方法定義處都可标注 @RequestMapping

      ① 标記在類上:提供初步的請求映射資訊。相對于 WEB 應用的根目錄

      ② 标記在方法上:提供進一步的細分映射資訊。相對于标記在類上的 URL。

    2)若類上未标注 @RequestMapping,則方法處标記的 URL 相對于 WEB 應用的根目錄 

    3)作用:DispatcherServlet 截獲請求後,就通過控制器上 @RequestMapping 提供的映射資訊确定請求所對應的處理方法。

  @RequestMapping屬性

    value:指定URL路徑

    method:指定請求方式 

    params:指定請求參數

    headers:指定請求頭資訊

  映射請求參數、請求方式或請求頭

    1)@RequestMapping 除了可以使用請求 URL 映射請求外,還可以使用請求方法、請求參數及請求頭來精确映射對應請求

    2)@RequestMapping 的 value【重點】、method【重點】、params【了解】 及 heads【了解】 分别表示請求 URL、請求方式、請求參數及請求頭的映射條件,他們之間是與的關系,聯合使用多個條件可讓請求映射更加精确化。即:需滿足所有映射條件才可比對到對應方法

    3)params 和 headers支援簡單的表達式:

      param1: 表示請求必須包含名為 param1 的請求參數

      !param1: 表示請求不能包含名為 param1 的請求參數

      param1 != value1: 表示請求包含名為 param1 的請求參數,但其值不能為 value1

      {"param1=value1", "param2"}: 請求必須包含名為 param1 和param2 的兩個請求參數,且 param1 參數的值必須為 value1

Ant 路徑風格

  Ant 風格資源位址支援 3 種比對符:【了解】

    ?:比對檔案名中的一個字元

    *:比對檔案名中的任意字元

    **:** 比對多層路徑

/user/*/**/createUser??
比對 /user/xxx/多層/createUserXX       

REST

REST是什麼?因為REST的内涵非常豐富,是以很難用一兩句話解釋清楚這個問題。首先,REST是Web自身的架構風格。

參考資料:了解本真的REST架構風格  

  REST:即 Representational State Transfer。(資源)表現層狀态轉化。是目前最流行的一種網際網路軟體架構。它結構清晰、符合标準、易于了解、擴充友善

  資源(Resources):資源是一種看待伺服器的方式。是網絡上的一個實體,可以是一段文本、一張圖檔,可以用一個URI(統一資源定位符,獨一無二的識别符)指向它,擷取這個資源,通路它的URI就可以了

  表現層:資源的表述(Representation)是一段對于資源在某個特定時刻的狀态的描述,即把資源具體呈現出來的形式, 比如,文本可以用 txt 、JSON 格式表現,甚至可以采用二進制格式。

  狀态轉化(State Transfer):狀态轉移說的是:在用戶端和伺服器端之間轉移(transfer)代表資源狀态的表述。通過轉移和操作資源的表述,來間接實作操作資源的目的。如:每發出一個請求,就代表了用戶端和伺服器的一次互動過程。HTTP協定,是一個無狀态協定,即所有的狀态都儲存在伺服器端。是以,如果用戶端想要操作伺服器,必須通過某種手段,讓伺服器端發生“狀态轉化”。而這種轉化是建立在表現層之上的,是以就是 “表現層狀态轉化”。

  統一接口(Uniform Interface)REST要求,必須通過統一的接口來對資源執行各種操作。對于每個資源隻能執行一組有限的操作。例如:HTTP/1.1協定定義了一個操作資源的統一接口。REST還要求,對于資源執行的操作,其操作語義必須由HTTP消息體之前的部分完全表達,不能将操作語義封裝在HTTP消息體内部。這樣做是為了提高互動的可見性

  超文本驅動(Hypertext Driven)将Web應用看作是一個由很多狀态(應用狀态)組成的有限狀态機。資源之間通過超連結互相關聯,超連結既代表資源之間的關系,也代表可執行的狀态遷移。即:用戶端應該依賴的是超媒體的狀态遷移語義,而不應該對于是否存在某個URI或URI的某種特殊構造方式作出假設。一切都有可能變化,隻有超媒體的狀态遷移語義能夠長期保持穩定。

  具體對于HTTP來說,就是 HTTP 協定裡面對應的四種常用基本操作:GET 用來擷取資源,POST 用來建立資源,PUT 用來更新資源,DELETE 用來删除資源。應使用由用戶端定義的請求方式指定對應的某種操作,而不應該通過某種特殊構造方式進行指定

HiddenHttpMethodFilter過濾器

  浏覽器 form 表單隻支援 GET 與 POST 請求,HiddenHttpMethodFilter 可以将POST請求轉換為标準的 http 方法以達到REST風格

使用步驟

  1. 必須将form表單中的method設定為POST

  2. 送出表單時,必須送出"_method"參數,一般使用隐藏域

    原因:HiddenHttpMethodFilter過濾器将HttpServletRequest中的getMethod()方法,重寫啦。

<!--    配置處理請求方式-->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>      

處理請求資料

  Spring MVC 架構會将 HTTP 請求的資訊綁定到相應的方法入參中,并根據方法的傳回值類型做出相應的後續處理。

  可以對方法及方法入參标注相應的注解( @PathVariable 、@RequestParam、@RequestHeader 等)

@PathVariable請求占位符

  是 Spring3.0 新增的功能,通過 @PathVariable 可以将 URL 中占位符參數綁定到控制器處理方法的入參中

//@PathVariable 注解可以将請求URL路徑中的請求參數,傳遞到處理請求方法的入參中
// 浏覽器的請求為:  testPathVariable/1001
@RequestMapping(value="/testPathVariable/{id}",method=RequestMethod.DELET)
public String testPathVariable(@PathVariable("id") Integer id) {}      

@RequestParam請求參數

  如果請求參數與形參不一緻時,可以使用@RequestParam注解實作擷取參數值

  書寫位置:标注在方法的參數中,springMVC預設會将請求參數注入(綁定)到方法形參中(兩個參數名一緻)

  一旦使用該注解,必須為相應參數傳參數。如果未傳參,會報錯:400,因為required預設為 true,

  value:用于映射請求參數名稱

  required:是否必須。預設為 true, 表示請求參數中必須包含對應的參數,若不存在,将抛出異常

  defaultValue: 預設值,當沒有傳遞參數時使用該值作為預設值,不設預設為 null

@RequestMapping(value="/testRequestParam?username=guigu&age=10")
    public String testRequestParam(
            @RequestParam(value="username") String username,
            @RequestParam(value="age",required=false,defaultValue="0") int age){
        return "success";
    }      

@RequestHeader 請求頭

  擷取請求頭資訊,請求頭包含了若幹個屬性,伺服器可據此獲知用戶端的資訊,通過 @RequestHeader 即可将請求頭中的屬性值綁定到處理方法的入參中 

Java架構之SpringMVC 03-RequestMapping-請求資料-響應資料

@CookieValue 

  擷取指定的Cookie資訊,可讓處理方法入參綁定某個 Cookie 值

Java架構之SpringMVC 03-RequestMapping-請求資料-響應資料

使用POJO作為參數

  Spring MVC 會按請求參數名和 POJO 屬性名進行自動比對,自動為該對象填充屬性值。支援級聯屬性。

@RequestMapping(value = "/emps",method = RequestMethod.PUT)
    public String updateEmp(Employee employee){
        employeeDao.save(employee);
        return "redirect:/emps";
    }
   //Spring MVC 會按請求參數名和 Employee 屬性名進行自動比對, 自動為該對象填充屬性值。支援級聯屬性      

配置字元編碼過濾器

<!--    處理POST請求和響應亂碼-->
    <filter>
        <filter-name>characterEncodingFilter</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>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>      

GET請求亂碼

  • GET請求參數是在位址後面的。我們需要修改tomcat的配置檔案。需要在server.xml檔案修改Connector标簽,添加URIEncoding="utf-8"屬性。

使用Servlet原生API

/**
     * 可以使用 Serlvet 原生的 API 作為目标方法的參數 具體支援以下類型
     * HttpServletRequest 
     * HttpServletResponse 
     * HttpSession
     * java.security.Principal 
     * Locale 
   * InputStream 
     * OutputStream 
     * Reader 
     * Writer
     */
    @RequestMapping("/testServletAPI")
    public void testServletAPI(HttpServletRequest request,HttpServletResponse response, Writer out) throws IOException {
        System.out.println("testServletAPI, " + request + ", " + response);
        out.write("hello springmvc");
    }      

處理響應資料

2、傳回值會通過視圖解析器解析為實際的實體視圖

輸出模型資料類型

  1)    ModelAndView: 作為傳回值類型,響應資料:處理方法傳回值類型為 ModelAndView 時, 方法體即可通過該對象添加模型資料

  2)  String: 作為傳回值類型,即為視圖資訊直接找字元串映射 URL 路徑,轉發或重定向

  3)    Map 或 Model: 作為參數,響應資料:入參為 Model、ModelMap 或  Map,處理方法傳回時,Map 中的資料會自動添加到模型中。

ModelAndView

  控制器處理方法的傳回值如果為 ModelAndView, 則其既包含視圖資訊,也包含模型資料資訊。

  1)  兩個重要的成員變量:

    private Object view;                       【視圖資訊】

    private ModelMap model;              【模型資料】

  2)添加模型資料:

    MoelAndView addObject(String attributeName, Object attributeValue)   【設定模型資料】

    ModelAndView addAllObject(Map<String, ?> modelMap)

  4)設定視圖:

    void setView(View view)                         【設定視圖對象】

    void setViewName(String viewName)            【設定視圖名字】

  5)擷取模型資料

    protected Map<String, Object> getModelInternal()   【擷取模型資料】

    public ModelMap getModelMap()

    public Map<String, Object> getModel()

@RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        String viewName = "success";
        ModelAndView mv = new ModelAndView(viewName);
        mv.addObject("time",new Date().toString()); //實質上存放到request域中 
        return mv;
    }      

ModelAndView 底層工作原理,不論控制器傳回一個String,ModelAndView,View都會轉換為ModelAndView對象,将資料放到request域中,再通過轉發實作頁面跳轉

Map   Model

  Spring MVC 在内部使用了一個 org.springframework.ui.Model 接口存儲模型資料

  Spring MVC 在調用方法前會建立一個隐含的模型對象作為模型資料的存儲容器。

  如果方法的入參為 Map 或 Model 類型,Spring MVC 會将隐含模型的引用傳遞給這些入參。

  在方法體内,開發者可以通過這個入參對象通路到模型中的所有資料,也可以向模型中添加新的屬性資料

//目标方法的傳回類型也可以是一個Map類型參數(也可以是Model,或ModelMap類型)
    @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map) { //【重點】
        System.out.println(map.getClass().getName());
    //org.springframework.validation.support.BindingAwareModelMap
        map.put("names", Arrays.asList("Tom", "Jerry", "Kite"));
        return "success";
    }      

注意問題:Map集合的泛型,key為String,Value為Object,而不是String

由源碼可知:不論用那個類型作為資料模型,其内部都會轉化為BindingAwareModelMap類型使其指向同一map對象

BindingAwareModelMap底層支援兩種接口(Map&Model)推薦使用 Map 便于架構移植

Java架構之SpringMVC 03-RequestMapping-請求資料-響應資料