1. 程式人生 > >不同的contentType下SpringMVC如何獲取到引數

不同的contentType下SpringMVC如何獲取到引數

版本:Java + Springboot2.0
快速測試環境:github地址

1. Jquery版本Ajax請求的格式

程式碼如下:

    $.ajax({
        type: "get"
        , url: "/test"
        , data: ""
        ,contentType: "application/json; charset=utf-8"
        , dataType: 'json'
        , success: function (res) {
           
        }
    });
  • type 控制請求的方式
  • url 是請求的連結
  • data 傳送的資料
  • contentType 傳送資料的格式
  • dataType 服務端返回資料的格式

可以看得到我們怎麼傳送資料,服務端怎麼接收資料最直接的影響就是contentType的設定,我們下面以兩種常見的ContentType為界限,來看各種型別(type:post/get等)的請求如何傳送引數。

2. 預設(不寫)ContentType

在jquery的ajax方法中,預設的ContentType的值為:application/x-www-form-urlencoded; charset=UTF-8
此格式為表單提交格式,最終提交給後臺的資料為key1=value1&key2=value2的格式 。
雖然ajax的data屬性值格式為:{key1:value1,key2:value2},但最後會轉為key1=value1&key2=value2的格式提交到後臺 ,如果ajax要和springmvc互動,key1=value1&key2=value2的格式,後臺springmvc只需要定義物件或者引數就行了,框架會自動對映。
下面是一個例子:
傳送的資料是data

變數,ajax請求如下,注意沒有寫contentType

function test() {
    var data = {
        code : "code",
        name : "name"
    };
    $.ajax({
        type: "get"
        , url: "/test"
        , data: data
        , dataType: 'json'
        , success: function (res) {
        }
    });
}

我們用chrome瀏覽器看看到底發給後臺的資料是什麼,截圖如下:
1.png

注意看URL,由於是GET請求,所以會把引數拼接在後面,或者看下面的紅框中的引數也是同樣的。
後臺的接收方式如下:

@RequestMapping(value = "/test", method = RequestMethod.GET)
public void test(String code, String name) {
    System.out.println(code);
    System.out.println(name);
}

並且打印出來了

code
name

上面是GET方式請求的例子,那麼我們再繼續測試RESTFUL風格中的其他請求方式。
其中RESTFUL風格的寫法如下:

  • 獲取:使用GET方法獲取資源。GET請求從不改變資源的狀態。無副作用。GET方法是冪等的。GET方法具有隻讀的含義。因此,你可以完美的使用快取。
  • 建立:使用POST建立新的資源。
  • 更新:使用PUT更新現有資源。
  • 刪除:使用DELETE刪除現有資源。
2.1 POST請求 (用複雜物件接收)

傳送的請求和資料如下:
可以看到我們把資料變化了下,code傳入的是一個js object物件了

	function test() {
        var code = {
          key : "11",
          value : 12
        };
        var data = {
            code : code,
            name : "name"
        };
        $.ajax({
            type: "post"
            , url: "/test"
            , data: data
            // ,contentType: "application/json; charset=utf-8"
            , dataType: 'json'
            , success: function (res) {
            }
        });
    }

看一下請求頭髮送的都是什麼:
2.png

所以這樣後臺獲取code就獲取不到了,分析一下上面傳遞過去的格式,明顯code是一個鍵值對的格式,我們用一個物件去接收。物件程式碼如下:

public class ViewModel {
    private Map<String, Object> code;
    private String name;
   }

後臺接收如下:

@RequestMapping(value = "/test", method = RequestMethod.POST)
    public void test(Map<String, Object> viewModel) {
        System.out.println(iewModel);
    }
// 列印結果:
// 值為:ViewModel{code={key=11, value=12}, name='name'}

這樣可以接收到傳遞過去的資料,但是如果直接在引數把code寫成一個Map的形式式獲取不到值的:

	@RequestMapping(value = "/test", method = RequestMethod.POST)
    public void test(Map<String, Object> code, String name) {
        System.out.println("code為:" + code);
        System.out.println("name為:" + name);
    }
    // 列印結果:
    //  code為:{}
	//  name為:name

原因後面繼續追蹤。

2.2 PUT請求 (如何獲取Json字串)

這次我們用put進行請求,並且我們想獲取到的code不再是一個js物件,而是一個JSON字串,我們需要用**JSON.stringify(code)**方法把一個js物件處理成字串。

	function test() {
        var code = {
          key : "11",
          value : 12
        };
        var data = {
            code : JSON.stringify(code),
            name : "name"
        };
        $.ajax({
            type: "put"
            , url: "/test"
            , data: data
            , dataType: 'json'
            , success: function (res) {
            }
        });
    }

觀察請求頭的內容如下:

3.png

可見我們以及傳送一個String型別的code過去了,我們用老方式去接收,如下:

@RequestMapping(value = "/test", method = RequestMethod.PUT)
    public void test(String code, String name) {
        System.out.println("code為:" + code);
        System.out.println("name為:" + name);
    }
    // 列印結果
    // code為:{"key":"11","value":12}
	// name為:name

拿到了JSON字串我們在利用Gson等工具包處理成我們想要的類即可。

2.3 DELETE請求(和其他的不太一樣)

我們按照以上的方式去請求,一切都和以前一樣,結果居然後臺code和name都獲取不到。

	function test() {
        var data = {
            code : "code"
            name : "name"
        };
        $.ajax({
            type: "delete"
            , url: "/test"
            , data: data
            , success: function (res) {
            }
        });
    }

很奇怪,去網上查了一下資料發現,jquery對delete處理比較獨特,DELETE請求方式是基於POST請求方式,必須在表單提交中寫上一個隱藏域,而且必須將name設定為**_method**,value屬性值寫上對應的請求方式。
具體寫法如下,注意看與上面程式碼不同的地方:

function test() {
        var data = {
            code : "code",
            name : "name"
        };
        // DELETE方式獨有
        data["_method"] = 'DELETE';
        $.ajax({
	        // 注意改為了post
            type: "post"
            , url: "/test"
            , data: data
            , success: function (res) {
            }
        });
    }

這樣按照原來的後臺,結果如下:

	@RequestMapping(value = "/test", method = RequestMethod.DELETE)
    public void test(String code, String name) {
        System.out.println("code為:" + code);
        System.out.println("name為:" + name);
    }
    // 列印結果:
    // code為:code
    // name為:name

3. ContentType 設定為 application/json; charset=UTF-8

如果springmvc的引數有@RequestBody註解(接收json字串格式資料),則ajax請求必須將data屬性值轉為json字串,不能為json物件(js物件,會自動轉為key=value形式)。
然後再修改contentType的值為:application/json; charset=UTF-8,這樣加了@RequestBody註解的屬性才能自定對映到值。

3.1 以POST請求為例

我們傳送請求的資料如下:
這其中需要注意的是

  • 設定了contentTpye
  • data是一個js物件,傳過去必須要JSON.stringify(data),轉化成json字串才行。
	function test() {
        var code = {
          key : "11",
          value : 12
        };
        var data = {
            code : code,
            name : "name"
        };
        $.ajax({
            type: "post"
            , url: "/test"
            , data: JSON.stringify(data)
            ,contentType: "application/json; charset=utf-8"
            , success: function (res) {
            }
        });
    }

以這樣為請求方式,我們看一下發送的請求頭的樣子:
4.png
可以看到,傳送過去的資料確確實實變成了json格式的,然後springmvc會自動呼叫Jackson,將json字串轉化成我們想要的格式。所以我們後頭接收如下:

	@RequestMapping(value = "/test", method = RequestMethod.POST)
    public void test(@RequestBody Map<String, Object> viewModel) {
        System.out.println("值為:" + viewModel);
    }
    // 列印結果:
    // 值為:{code={key=11, value=12}, name=name}

同樣,如果我們想用自定義的類去接收,去定義好類,並且把json中的健和值對應上即可。

4. HTTP頭 Content-Type

  • 作用:contentType的作用是用來標識傳送或者接收資料的MIME型別。
  • 格式:type/subtype(;parameter)? type
    • 樣例:Content-Type:application/json;charset=GBK
    • type代表主型別,比如application
    • subtype代表副型別,比如json
    • parameter可選,比如charset
    • 其中*代表所有型別

5. 常見的contentType型別

  1. 主型別為text的
    text/html : HTML格式
    text/plain :純文字格式
    text/xml : XML格式
    image/gif :gif圖片格式
    image/jpeg :jpg圖片格式
    image/png:png圖片格式
  2. 以application開頭的媒體格式型別:
    application/xml : XML資料格式
    application/atom+xml :Atom XML聚合格式
    application/json : JSON資料格式
    application/pdf :pdf格式
    application/msword : Word文件格式
    application/octet-stream : 二進位制流資料(如常見的檔案下載)

END

參考