1. 程式人生 > >SpringMVC 參數綁定註解解析

SpringMVC 參數綁定註解解析

表單編碼 springmvc ref 自身 get val wal ont void

本文介紹了用於參數綁定的相關註解。

綁定:將請求中的字段按照名字匹配的原則填入模型對象。

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-Typex-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模板變量和類型轉換的方式來取得一個屬性是更方便的方式。

在不給定註解的情況下,參數是怎樣綁定的?

通過分析AnnotationMethodHandlerAdapterRequestMappingHandlerAdapter的源代碼發現,方法的參數在不給定參數的情況下:

  • 若要綁定的對象時簡單類型:調用@RequestParam來處理的。
    這裏的簡單類型指Java的原始類型(boolean, int 等)、原始類型對象(Boolean, Int等)、String、Date等ConversionService裏可以直接String轉換成目標對象的類型。也就是說沒有特別需求,不推薦使用@RequestParam
  • 若要綁定的對象時復雜類型:調用@ModelAttribute來處理的。也就是說如果不需要從model或者session中得到數據,@ModelAttribute可以不使用。

@RequestMapping支持的方法參數

下面這些參數Spring在調用請求方法的時候會自動給它們賦值,所以當在請求方法中需要使用到這些對象的時候,可以直接在方法上給定一個方法參數的申明,然後在方法體裏面直接用就可以了。

  1. HttpServlet 對象,主要包括HttpServletRequest 、HttpServletResponse 和HttpSession 對象。 但是有一點需要註意的是在使用HttpSession 對象的時候,如果此時HttpSession 對象還沒有建立起來的話就會有問題。
  2. Spring 自己的WebRequest 對象。 使用該對象可以訪問到存放在HttpServletRequest 和HttpSession 中的屬性值。
  3. InputStream 、OutputStream 、Reader 和Writer 。 InputStream 和Reader 是針對HttpServletRequest 而言的,可以從裏面取數據;OutputStream 和Writer 是針對HttpServletResponse 而言的,可以往裏面寫數據。
  4. 使用@PathVariable@RequestParam@CookieValue@RequestHeader 標記的參數。
  5. 使用@ModelAttribute 標記的參數。
  6. java.util.Map 、Spring 封裝的Model 和ModelMap 。 這些都可以用來封裝模型數據,用來給視圖做展示。
  7. 實體類。 可以用來接收上傳的參數。
  8. Spring 封裝的MultipartFile 。 用來接收上傳文件的。
  9. Spring 封裝的Errors 和BindingResult 對象。 這兩個對象參數必須緊接在需要驗證的實體對象參數之後,它裏面包含了實體對象的驗證結果。

一個參數傳多個值

在瀏覽器輸入此URLhttp://localhost:8080/admin/login.action?username=geek&password=geek&password=geek

結果得到的對象為 : Manager{username=‘geek‘, password=‘geek,geek‘}

參考文檔:

  1. @RequestParam @RequestBody @PathVariable 等參數綁定註解詳解
  2. SpringMVC之Controller常用註解功能全解析
  3. @ModelAttribute使用詳解

SpringMVC 參數綁定註解解析