SpringMVC 參數綁定註解解析
本文介紹了用於參數綁定的相關註解。
綁定:將請求中的字段按照名字匹配的原則填入模型對象。
SpringMVC就跟Struts2一樣,通過攔截器進行參數匹配。
代碼在 https://github.com/morethink/MySpringMVC
URI模板變量
這裏指uri template中variable(路徑變量),不含queryString部分
@PathVariable
當使用@RequestMapping
URI template 樣式映射時, 即 someUrl/{paramId}, 這時的paramId可通過 @Pathvariable
註解綁定它傳過來的值到方法的參數上。
示例代碼:
@RestController
@RequestMapping("/users")
public class UserAction {
@GetMapping("/{id}")
public Result getUser(@PathVariable int id) {
return ResultUtil.successResult("123456");
}
}
上面代碼把URI template 中變量 ownerId的值和petId的值,綁定到方法的參數上。若方法參數名稱和需要綁定的uri template中變量名稱不一致,需要在@PathVariable("name")指定uri template中的名稱
請求頭
@RequestHeader
@RequestHeader
註解,可以把Request請求header部分的值綁定到方法的參數上。
示例代碼:
這是一個Request 的header部分:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 Cache-Control:max-age=0 Connection:keep-alive Host:localhost:8080 Upgrade-Insecure-Requests:1 User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36
@GetMapping("/getRequestHeader")
public Result getRequestHeader(@RequestHeader("Accept-Encoding") String encoding) {
return ResultUtil.successResult(encoding);
}
上面的代碼,把request header部分的 Accept-Encoding的值,綁定到參數encoding上。
@CookieValue
可以把Request header中關於cookie的值綁定到方法的參數上。
例如有如下Cookie值:
JSESSIONID=588DC770E582A3189B7E6210102EAE02
參數綁定的代碼:
@RequestMapping("/getCookie")
public Result getCookie(@CookieValue("JSESSIONID") String cookie) {
return ResultUtil.successResult(cookie);
}
即把JSESSIONID的值綁定到參數cookie上。
請求體
@RequestParam
- 常用來處理簡單類型的綁定,通過Request.getParameter() 獲取的String可直接轉換為簡單類型的情況( String--> 簡單類型的轉換操作由ConversionService配置的轉換器來完成);因為使用request.getParameter()方式獲取參數,所以可以處理get 方式中queryString的值,也可以處理post方式中 body data的值;
- 用來處理Content-Type: 為
application/x-www-form-urlencoded
編碼的內容,提交方式GET、POST; - 該註解有兩個屬性: value、required; value用來指定要傳入值的id名稱,required用來指示參數是否必須綁定;
示例代碼:
@GetMapping("/tesRequestParam")
public Result tesRequestParam(@RequestParam("username") String username) {
return ResultUtil.successResult(username);
}
@RequestBody
該註解常用來處理Content-Type: 不是application/x-www-form-urlencoded編碼的內容,例如application/json, application/xml等;
它是通過使用HandlerAdapter 配置的HttpMessageConverters來解析post data body,然後綁定到相應的bean上的。
因為配置有FormHttpMessageConverter,所以也可以用來處理 application/x-www-form-urlencoded的內容,處理完的結果放在一個MultiValueMap
示例代碼:
@PostMapping("/tesRequestBody")
public Result tesRequestBody(@RequestBody User user) {
return ResultUtil.successResult(user);
}
結果截圖:
@RequestBody
通過list接收對象數組
在我們傳遞對象的時候,無論Content-Type
是x-www-form-urlencoded
還是application/json
其實沒有多大的關系,可是當我們需要傳遞對象數組的時候,表單編碼就不行了,這時我們是可以采用json傳遞,然後後臺使用@RequestBody
註解,通過list接收來對象數組。
前端代碼:
index.html
//打開頁面時運行
$(document).ready(function () {
var users = [];
var user1 = {"username": "dd", "password": "123"};
var user2 = {"username": "gg", "password": "123"};
users.push(user1);
users.push(user2);
$.ajax({
type: "POST",
url: "users/saveUsers",
timeout: 30000,
dataType: "json",
contentType: "application/json",
data: JSON.stringify(users),
success: function (data) {
//將返回的數據展示成table
showTable(data);
},
error: function () { //請求出錯的處理
$("#result").text("請求出錯");
}
});
});
後臺代碼:
@PostMapping("saveUsers")
public Result saveUsers(@RequestBody List<User> users) {
return ResultUtil.successResult(users);
}
結果截圖:
@SessionAttribute
該註解用來綁定HttpSession中的attribute對象的值,便於在方法中的參數裏使用。該註解有value、types兩個屬性,可以通過名字和類型指定要使用的attribute 對象
示例代碼:
@PostMapping("/setSessionAttribute")
public Result setSessionAttribute(HttpSession session, String attribute) {
session.setAttribute("attribute", attribute);
return ResultUtil.SUCCESS_RESULT;
}
@GetMapping("/getSessionAttribute")
public Result getSessionAttribute(@SessionAttribute("attribute") String attribute) {
return ResultUtil.successResult(attribute);
}
我們首先給session添加一個attribute,然後再取出這個attribute。
@ModelAttribute
@ModelAttribute標註可被應用在方法或方法參數上。
方法使用@ModelAttribute標註
標註在方法上的@ModelAttribute
說明方法是用於添加一個或多個屬性到model上。這樣的方法能接受與@RequestMapping
標註相同的參數類型,只不過不能直接被映射到具體的請求上。
在同一個控制器中,標註了@ModelAttribute
的方法實際上會在@RequestMapping
方法之前被調用。
以下是示例:
// Add one attribute
// The return value of the method is added to the model under the name "account"
// You can customize the name via @ModelAttribute("myAccount")
@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountManager.findAccount(number);
}
// Add multiple attributes
@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
model.addAttribute(accountManager.findAccount(number));
// add more ...
}
@ModelAttribute
方法通常被用來填充一些公共需要的屬性或數據,比如一個下拉列表所預設的幾種狀態,或者寵物的幾種類型,或者去取得一個HTML表單渲染所需要的命令對象,比如Account等。
@ModelAttribute標註方法有兩種風格:
- 在第一種寫法中,方法通過返回值的方式默認地將添加一個屬性;
- 在第二種寫法中,方法接收一個Model對象,然後可以向其中添加任意數量的屬性。
可以在根據需要,在兩種風格中選擇合適的一種。
一個控制器可以擁有多個@ModelAttribute
方法。同個控制器內的所有這些方法,都會在@RequestMapping
方法之前被調用。
@ModelAttribute
方法也可以定義在@ControllerAdvice
標註的類中,並且這些@ModelAttribute
可以同時對許多控制器生效。
屬性名沒有被顯式指定的時候又當如何呢?在這種情況下,框架將根據屬性的類型給予一個默認名稱。舉個例子,若方法返回一個Account類型的對象,則默認的屬性名為"account"。可以通過設置@ModelAttribute標註的值來改變默認值。當向Model中直接添加屬性時,請使用合適的重載方法addAttribute(..)-即帶或不帶屬性名的方法。
@ModelAttribute標註也可以被用在@RequestMapping
方法上。這種情況下,@RequestMapping
方法的返回值將會被解釋為model的一個屬性,而非一個視圖名,此時視圖名將以視圖命名約定來方式來確定。
方法參數使用@ModelAttribute
標註
標註在方法參數上的@ModelAttribute
說明了該方法參數的值將由model中取得。如果model中找不到,那麽該參數會先被實例化,然後被添加到model中。在model中存在以後,請求中所有名稱匹配的參數都會填充到該參數中。
這在Spring MVC中被稱為數據綁定,一個非常有用的特性,我們不用每次都手動從表格數據中轉換這些字段數據。
@PostMapping
public Result saveUser(@ModelAttribute User user) {
return ResultUtil.successResult(user);
}
以上面的代碼為例,這個User類型的實例可能來自哪裏呢?有幾種可能:
- 它可能因為
@SessionAttributes
標註的使用已經存在於model中 - 它可能因為在同個控制器中使用了
@ModelAttribute
方法已經存在於model中,正如上一小節所敘述的 - 它可能是由URI模板變量和類型轉換中取得的
- 它可能是調用了自身的默認構造器被實例化出來的
@ModelAttribute方法常用於從數據庫中取一個屬性值,該值可能通過@SessionAttributes
標註在請求中間傳遞。在一些情況下,使用URI模板變量和類型轉換的方式來取得一個屬性是更方便的方式。
在不給定註解的情況下,參數是怎樣綁定的?
通過分析AnnotationMethodHandlerAdapter
和RequestMappingHandlerAdapter
的源代碼發現,方法的參數在不給定參數的情況下:
- 若要綁定的對象時簡單類型:調用
@RequestParam
來處理的。
這裏的簡單類型指Java的原始類型(boolean, int 等)、原始類型對象(Boolean, Int等)、String、Date等ConversionService裏可以直接String轉換成目標對象的類型。也就是說沒有特別需求,不推薦使用@RequestParam
。 - 若要綁定的對象時復雜類型:調用
@ModelAttribute
來處理的。也就是說如果不需要從model或者session中得到數據,@ModelAttribute可以不使用。
@RequestMapping
支持的方法參數
下面這些參數Spring在調用請求方法的時候會自動給它們賦值,所以當在請求方法中需要使用到這些對象的時候,可以直接在方法上給定一個方法參數的申明,然後在方法體裏面直接用就可以了。
- HttpServlet 對象,主要包括HttpServletRequest 、HttpServletResponse 和HttpSession 對象。 但是有一點需要註意的是在使用HttpSession 對象的時候,如果此時HttpSession 對象還沒有建立起來的話就會有問題。
- Spring 自己的WebRequest 對象。 使用該對象可以訪問到存放在HttpServletRequest 和HttpSession 中的屬性值。
- InputStream 、OutputStream 、Reader 和Writer 。 InputStream 和Reader 是針對HttpServletRequest 而言的,可以從裏面取數據;OutputStream 和Writer 是針對HttpServletResponse 而言的,可以往裏面寫數據。
- 使用
@PathVariable
、@RequestParam
、@CookieValue
和@RequestHeader
標記的參數。 - 使用
@ModelAttribute
標記的參數。 - java.util.Map 、Spring 封裝的Model 和ModelMap 。 這些都可以用來封裝模型數據,用來給視圖做展示。
- 實體類。 可以用來接收上傳的參數。
- Spring 封裝的MultipartFile 。 用來接收上傳文件的。
- Spring 封裝的Errors 和BindingResult 對象。 這兩個對象參數必須緊接在需要驗證的實體對象參數之後,它裏面包含了實體對象的驗證結果。
一個參數傳多個值
在瀏覽器輸入此URLhttp://localhost:8080/admin/login.action?username=geek&password=geek&password=geek
結果得到的對象為 : Manager{username=‘geek‘, password=‘geek,geek‘}
參考文檔:
- @RequestParam @RequestBody @PathVariable 等參數綁定註解詳解
- SpringMVC之Controller常用註解功能全解析
- @ModelAttribute使用詳解
SpringMVC 參數綁定註解解析