1. 程式人生 > 其它 >@RequestParam 如何將引數繫結到物件上

@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