Spring中將@RequestParam綁定到對象(轉)

譯文:https://blog.csdn.net/dnc8371/article/details/106810876/

譯文作者:dnc8371

來源:CSDN

原文:https://www.javacodegeeks.com/2018/10/how-bind-requestparam-object-spring.html

您是否在請求映射方法中用@RequestParam註釋了多個參數,並認爲它不可讀?

當請求中需要一個或兩個輸入參數時,註釋看起來非常簡單,但是當列表變長時,您可能會感到不知所措。

您不能在對象內部使用@RequestParam批註,但這並不意味着您沒有其他解決方案。 在本文中,我將向您展示如何用object替換多個@RequestParams 。

1. @RequestParams的列表太長

無論是控制器還是其他類,我都相信您同意很難讀取一長串方法參數 。 另外,如果參數類型相同,則更容易出錯。

諸如Checkstyle之類的靜態代碼分析工具可以檢測方法中的大量輸入,因爲它被廣泛認爲是一種不好的做法。

通常,將一組參數一起傳遞到應用程序的不同層。 這樣的組通常可以形成一個對象 ,您要做的就是提取它並給它起一個適當的名稱 。

讓我們看一下用於搜索某些產品的示例GET端點:

@RestController
@RequestMapping("/products")
class ProductController {
 
   //...
 
   @GetMapping
   List<Product> searchProducts(@RequestParam String query,
                                @RequestParam(required = false, defaultValue = "0") int offset,
                                @RequestParam(required = false, defaultValue = "10") int limit) {
       return productRepository.search(query, offset, limit);
   }
 
}

三個參數不是一個令人關注的數字,但它可以輕鬆增長。 例如,搜索通常包括排序順序或一些其他過濾器。 在這種情況下,它們都被傳遞到數據訪問層,因此它們似乎是參數對象提取的理想選擇。

2. 將@RequestParam綁定到POJO

根本不用註解@RequestParams,如下,直接把POJO作爲輸入即可。

@GetMapping
List<Product> searchProducts(ProductCriteria productCriteria) {
   return productRepository.search(productCriteria);
}

POJO不需要任何其他註釋。 它應具有與將與HTTP請求綁定的請求參數匹配的字段列表,標準的getter / setter和無參數的構造函數。

class ProductCriteria {
 
   private String query;
   private int offset;
   private int limit;
 
   ProductCriteria() {
   }
 
   public String getQuery() {
       return query;
   }
 
   public void setQuery(String query) {
       this.query = query;
   }
 
   // other getters/setters
 
}

驗證POJO內部的請求參數

好的,但是我們不僅僅使用@RequestParam註釋來綁定HTTP參數。 註釋的另一個有用功能是可以根據需要標記給定參數。 如果請求中缺少參數,我們的端點可以拒絕它。

爲了使用 POJO達到相同的效果(甚至更多!),我們可以使用bean驗證 。 Java帶有許多內置約束,但是如果需要,您總是創建一個自定義驗證 。

讓我們回到POJO並向字段添加一些驗證規則。 如果只想模仿 @RequestParam(required = false) 的行爲,則只需在必填字段上使用 @NotNull 批註 。

在許多情況下,使用@NotBlack代替@NotNull更有意義,因爲它還涵蓋了不需要的空字符串問題(長度爲零的字符串)。

final class ProductCriteria {
 
   @NotBlank
   private String query;
   @Min(0)
   private int offset;
   @Min(1)
   private int limi;
 
   // ...
 
}

請注意:

添加字段的驗證註釋不足以使其起作用。

您還需要在控制器的方法中使用@Valid批註標記POJO參數。 這樣,您通知Spring它應該在綁定步驟上執行驗證。

@GetMapping
List<Product> searchProducts(@Valid ProductCriteria productCriteria) {
   // ...
}

POJO內部的默認請求參數值

@RequestParam批註的另一個有用的功能是能夠在HTTP請求中未提供參數時定義默認值。

當我們擁有POJO時,不需要特殊的魔術。 您只需將默認值直接分配給字段。 當請求中缺少參數時,沒有任何內容將覆蓋預定義的值。

private int offset = 0;
private int limit = 10;

3. 多個對象

您沒有被迫將所有HTTP參數放在單個對象中。 您可以在多個POJO中對參數進行分組。

爲了說明這一點,讓我們向端點添加排序條件。 首先,我們需要一個單獨的對象。 就像之前一樣,它具有一些驗證約束。

final class SortCriteria {
 
   @NotNull
   private SortOrder order;
   @NotBlank
   private String sortAttribute;
 
   // constructor, getters/setters
 
}

在控制器中,只需將其添加爲單獨的輸入參數即可。 請注意,@ Valid批註在每個應驗證的參數上都是必需的。

@GetMapping
List<Product> searchProducts(@Valid ProductCriteria productCriteria, @Valid SortCriteria sortCriteria) {
   // ...
}

4. 嵌套對象

作爲多個輸入請求對象的替代,我們也可以使用組合。 參數綁定也適用於嵌套對象。

在下面,您可以找到一個示例,其中先前引入的排序條件已移至產品條件POJO。

要驗證所有嵌套屬性,應將@Valid批註添加到該字段。 請注意,如果該字段爲null,Spring將不會驗證其屬性。 如果所有嵌套屬性都是可選的,那可能是理想的解決方案。 如果不是,只需將@NotNull批註放在該嵌套對象字段上。

final class ProductCriteria {
 
   @NotNull
   @Valid
   private SortCriteria sort;
 
   // ...
 
}

HTTP參數必須使用點符號匹配字段名稱。 在我們的情況下,它們應如下所示:

sort.order=ASC&sort.attribute=name

5. 不變的DTO

如今,您可以看到一種趨勢,它傾向於使用不固定對象,而使用二傳手來取代傳統的POJO。

不可變的對象有很多好處(還有缺點……但是……)。 我認爲,最大的一項是維護簡單 。

您是否曾經在應用程序的數十個層中進行過跟蹤,以瞭解哪些條件導致了對象的特定狀態? 這個或那個字段在哪裏改變了? 爲什麼要更新? setter方法的名稱什麼也沒解釋。 二傳手沒有任何意義。

考慮到創建Spring框架的事實,Spring強烈依賴POJO規範就不會讓人感到驚訝。 然而,時代變了,舊的模式變成了反模式。

沒有簡單的方法可以使用參數化的構造函數將HTTP參數神奇地綁定到POJO。 非參數構造函數是不可避免的。 但是,我們可以將該構造函數設爲私有 (但遺憾的是不能在嵌套對象中使用)並刪除所有的setter。 從公衆的角度來看,該對象將變得不可變。

默認情況下,Spring需要使用setter方法將HTTP參數綁定到字段。 幸運的是,可以重新配置綁定程序並使用直接字段訪問(通過反射)。

爲了爲整個應用程序全局配置數據綁定器,您可以創建一個控制器建議組件。 您可以在以@InitBinder批註註釋的方法內部更改綁定程序配置,該方法接受綁定程序作爲輸入。

@ControllerAdvice
class BindingControllerAdvice {
 
   @InitBinder
   public void initBinder(WebDataBinder binder) {
       binder.initDirectFieldAccess();
   }
 
}

創建該小類後,我們可以返回到POJO並從該類中刪除所有setter方法,以使其變爲只讀狀態以供公衆使用。

final class ProductCriteria {
 
   @NotBlank
   private String query;
   @Min(0)
   private int offset = 0;
   @Min(1)
   private int limit = 10;
 
   private ProductCriteria() {
   }
 
   public String getQuery() {
       return query;
   }
 
   public int getOffset() {
       return offset;
   }
 
   public int getLimit() {
       return limit;
   }
 
}

重新啓動您的應用程序,並使用HTTP請求的參數。 它應該像以前一樣工作。

6. 結論

在本文中,您可以看到使用@RequestParam綁定在Spring MVC控制器中的HTTP請求參數可以輕鬆地替換爲對多個屬性進行分組的參數對象,僅不過是簡單的POJO或可選的不可變DTO。

您可以在GitHub存儲庫中找到描述的樣本 。 我希望所介紹的案例是不言自明的,但是如果有任何疑問或您想花兩分錢,我強烈建議您將您的評論留在帖子下方。

翻譯自: https://www.javacodegeeks.com/2018/10/how-bind-requestparam-object-spring.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章