不同的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
function test() {
var data = {
code : "code",
name : "name"
};
$.ajax({
type: "get"
, url: "/test"
, data: data
, dataType: 'json'
, success: function (res) {
}
});
}
我們用chrome瀏覽器看看到底發給後臺的資料是什麼,截圖如下:
注意看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) {
}
});
}
看一下請求頭髮送的都是什麼:
所以這樣後臺獲取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) {
}
});
}
觀察請求頭的內容如下:
可見我們以及傳送一個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) {
}
});
}
以這樣為請求方式,我們看一下發送的請求頭的樣子:
可以看到,傳送過去的資料確確實實變成了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型別
- 主型別為text的
text/html : HTML格式
text/plain :純文字格式
text/xml : XML格式
image/gif :gif圖片格式
image/jpeg :jpg圖片格式
image/png:png圖片格式 - 以application開頭的媒體格式型別:
application/xml : XML資料格式
application/atom+xml :Atom XML聚合格式
application/json : JSON資料格式
application/pdf :pdf格式
application/msword : Word文件格式
application/octet-stream : 二進位制流資料(如常見的檔案下載)