@RequestParam 如何將引數繫結到物件上
有這麼一個場景,假設前臺傳遞給我們三個引數 id、name、age ,我們很自然的會想到使用 @RequestParam 來接收前臺傳遞過來的引數,具體示例如下
@GetMapping("/getUserInfo") public String getUserInfo( // 將前臺傳遞過來的引數 id 對應的值繫結至 Integer 型別的引數 id // required 的預設值是 true,如果前臺傳遞過來沒有該引數,那麼就會進行校驗並報錯 // 當 required = false 時,如果沒有傳遞引數 id,那麼它不會報錯,而是使用預設值 10086 @RequestParam(value="id",required = false,defaultValue = "10086") Integer id, @RequestParam(value="name",required = false,defaultValue = "xiaomaomao") String name, @RequestParam(value = "age",required = false,defaultValue = "21") Integer age) { return "id===" + id + " name===" + name + " age===" + age; }
上面的示例看起來沒有什麼問題,可是實際上我們不難發現,如果前臺傳遞過來的引數不是三個,而是十個,如果繼續使用 @RequestParam 的方式來接收請求引數,就需要十個 @RequestParam ,我們的程式碼可讀性將會變得很差,並且當引數型別相同時,十分容易出錯,有沒有什麼好的解決方案呢?
這個時候可能你會想到使用實體類來接收傳遞過來的十個引數,想法是正確的,可是 @RequestParam 不支援直接傳遞實體類的方式,那麼有其它的解決辦法嗎?
答案是有的,具體示例如下
@GetMapping("/getUserInfo") // 將請求引數中的 id、name、age 與實體類 saleman 進行繫結 public String getUserInfo(Saleman saleman) { return saleman.toString(); }
很簡單,只需要定義一個實體類就能完美解決,可是,如果要實現類似於 @RequestParam(required=true) 的校驗該怎麼辦呢?
其實也好辦,我們可以在實體類裡面進行校驗
@Data public class Saleman { // id 最小值為 100 @Min(1) // id 不能為空,否則會報錯 @NonNull private Integer id; // 如果是字串型別的資料,使用 @NotBlank 比 @NoNull 更好,因為 @NotBlank 不僅會校驗 null 值,它還會校驗空字串 @NotBlank private String name; // age 最大值為 30 @Max(30) // age 不能為空,否則校驗不通過 @NonNull private Integer age; }
注意你如果想要這些實體類中的註解生效,就必須要加上 @Valid 註解
@GetMapping("/getUserInfo")
// 要想實體類中的註解生效,必須要在實體類加上 @Valid 註解
public String getUserInfo(@Valid Saleman saleman) {
return saleman.toString();
}
這樣,我們就模擬出了 @RequestParam(required=true) 的情形了,但是 @RequestParam 註解的作用還包括,如果未提供具體的引數,它會有預設值,這個該怎麼實現呢?
做法很簡單,只需要在宣告實體類屬性的時候給一個預設值即可,類似 private Integer id = 2
@Data
public class Saleman {
// id 最小值為 100
@Min(1)
// id 不能為空,否則會報錯
@NonNull
// 如果前臺沒有傳遞 id 引數,那麼 id 會有預設值 2,注意這裡的預設值一定要符合上面 @Min、@Nonnull 等註解的校驗,否則該預設值設定的是不合理的
private Integer id = 2;
// 如果是字串型別的資料,使用 @NotBlank 比 @NoNull 更好,因為 @NotBlank 不僅會校驗 null 值,它還會校驗空字串
@NotBlank
private String name = "xiaomaomi";
// age 最大值為 30
@Max(30)
// age 不能為空,否則校驗不通過
@NonNull
private Integer age = 28;
}
@GetMapping("/getUserInfo")
// 要想實體類中的註解生效,必須要在實體類加上 @Valid 註解
public String getUserInfo(@Valid Saleman saleman) {
return saleman.toString();
}
到此,我們就已經模擬出了 @RequestParam 註解的所有功能(空值校驗、空值時的預設值)
有時候根據業務需求,不會把所有的請求引數封裝進同一個實體類中,我們可以將其封裝進多個實體類中,具體的用法同上面一個實體類的相同
@Data
public class Saleman {
// id 最小值為 100
@Min(1)
// id 不能為空,否則會報錯
@NonNull
// 如果前臺沒有傳遞 id 引數,那麼 id 會有預設值 2,注意這裡的預設值一定要符合上面 @Min、@Nonnull 等註解的校驗,否則該預設值設定的是不合理的
private Integer id = 2;
// 如果是字串型別的資料,使用 @NotBlank 比 @NoNull 更好,因為 @NotBlank 不僅會校驗 null 值,它還會校驗空字串
@NotBlank
private String name = "xiaomaomi";
// age 最大值為 30
@Max(30)
// age 不能為空,否則校驗不通過
@NonNull
private Integer age = 28;
}
@Data
public class Product {
@Min(100)
@NonNull
private Integer id = 10001;
@NotBlank
private String productName = "yishengwenhou";
}
@GetMapping("/getUserInfo")
// 要想實體類中的註解生效,必須要在實體類加上 @Valid 註解
public String getUserInfo(@Valid Saleman saleman,@Valid Product product) {
return saleman.toString() + "--------" + product.toString();
}
但是有一個需要注意的地方,如果兩個實體類中有相同的屬性,那麼前臺傳入的引數值會同時封裝進入兩個實體類中,例如前臺傳入一個 id,而 Saleman、Product 兩個實體類都有 id 這個屬性,那麼 id 對應的引數值就同時封裝進了 saleman、product