我們將研究 request-validator 庫,它能夠將用戶輸入與預定義的一組規則(如 required、max、min、email 等)進行比較。
我們有時會遇到由于用戶提供的輸入長于數據庫列大小甚至不存在的 ENUM 值而導致的服務器錯誤。不信任用戶輸入是一種流行的陳詞濫調,如果實施,將節省大量時間和資源。
這就是為什么在本文中,我們將研究request-validator庫,它能夠將用戶輸入與一組預定義的規則進行比較,并在有錯誤時返回錯誤。
依賴安裝
為了讓我們使用request-validator,我們需要將它添加到我們項目的pom.xml中:
清單 2.1 pom.xml
<dependency>
<groupId>com.smattme</groupId>
<artifactId>request-validator</artifactId>
<version>0.0.2</version>
</dependency>
最新版本的依賴項在Maven 中心可用。
驗證 JSON 請求正文
鑒于我們有一個簡單的登錄端點,需要有效的電子郵件和密碼,并且作為一名優秀的工程師,我們希望確保用戶發送兩個字段并且電子郵件是有效的。
我們可以使用request-validator 庫輕松實現這一點。對于電子郵件 輸入字段,我們希望用戶提供一個非空字段和一個有效的電子郵件地址,而對于密碼字段,我們只希望用戶提供一個非空值:
清單 3.1 LoginController.JAVA
@RestController
public class LoginController {
@PostMApping("/auth/login")
public ResponseEntity<GenericResponse> login(@RequestBody LoginRequest request) {
Map<String, String> rules = new HashMap<>();
rules.put("email", "required|email");
rules.put("password", "required");
List<String> errors = RequestValidator.validate(request, rules);
if (!errors.isEmpty()) {
GenericResponse genericResponse = new GenericResponse();
genericResponse.setStatus(false);
genericResponse.setCode(
HttpStatus.BAD_REQUEST.value());
genericResponse.setErrors(errors);
genericResponse.setMessage("Missing required parameter(s)");
return ResponseEntity.badRequest().body(genericResponse);
}
//otherwise all is well, process the request
//loginService.login()
return ResponseEntity.ok(
GenericResponse.generic200Responseobj("Login successful"));
}
}
從上面的清單 3.1 中,我們使用Map<String, String>來存儲每個預期請求字段的規則。映射的鍵是 API 用戶應提供的字段名稱,而值包含驗證規則。
然后我們調用RequestValidator.validate()方法來檢查傳入的請求對象是否符合定義的規則。該方法返回一個List<String>,如果存在違規,它將包含所有錯誤消息。
該庫的一大優勢是它為每個規則返回一個單獨的描述性錯誤消息,并在一次調用中檢查所有規則。
因為RequestValidator.validate()需要Object數據類型,所以請求對象可以是Map、POJO 甚至是 JSON String。
如果 API 用戶提供了無效的請求正文,他們將收到 400 錯誤請求,其中包含所有數據違規的詳細列表:
清單 3.2 curl請求/響應
Request:
curl --location --request POST 'http://localhost:8080/auth/login'
--header 'Content-Type: application/json'
--data-raw '{
"email": "john"
}'
Response:
{
"status": false,
"message": "Missing required parameter(s)",
"errors": [
"password is required",
"email supplied is invalid"
],
"code": 400
}
但是,正如預期的那樣,有效的請求正文將返回成功:
清單 3.3 curl請求/響應
Request:
curl --location --request POST 'http://localhost:8080/auth/login'
--header 'Content-Type: application/json'
--data-raw '{
"email": "john@example.com",
"password": "changeit"
}'
Response:
{
"status": true,
"message": "Login successful",
"code": 200
}
請注意,返回的List<String>錯誤可以以您和您的團隊選擇的任何方式用作您的響應的一部分。它不限于本文中演示的響應格式。
本文末尾提供了完整的源代碼,它將幫助您更好地理解本教程中的響應格式是如何格式化的。
請求驗證器庫允許我們使用豎線 (|) 字符作為分隔符將一個或多個規則組合在一起。從上面的清單 3.1 中,我們使用|將required和email規則組合在一起。.
唯一的例外是在將正則表達式規則與其他規則一起使用時。它應該是最后一條規則,并且應該用雙豎線字符分隔,如 || . 這是為了適應正則表達式模式中管道字符的潛在存在:
清單 3.3 正則表達式模式:
Map<String, String> rules = new HashMap<>();
rules.put("dob", "required||regex:[0-9]{2}-[0-9]{2}-[0-9]{4}");
完整的規則列表可在此處獲得。
定義自定義規則
假設我們要添加一個默認不在庫中的自定義驗證規則,我們可以通過繼承 RequestValidator 類并實現RuleValidator接口輕松實現它。
鑒于我們需要添加一條規則以確保用戶提供的值以custom_ 開頭,首先,我們需要創建一個PrefixRuleValidator 類,該類將實現RuleValidator接口并執行自定義邏輯:
清單 4.1 PrefixRuleValidator.java
public class PrefixRuleValidator implements RuleValidator {
我們需要的下一個組件是一個擴展RequestValidator 的類。 我們將調用這個CustomRequestValidator,而不是庫的RequestValidator,來進行我們的檢查:
清單 4.2
CustomRequestValidator.java
public class CustomRequestValidator extends RequestValidator {
static {
ruleValidatorMap.put("customprefix", PrefixRuleValidator.class);
}
public static List<String> validate(Object target, Map<String, String> rules) {
String jsonRequest =
convertObjectRequestToJsonString(target);
return validate(jsonRequest, rules, ruleValidatorMap);
}
}
CustomRequestValidator的結構很簡單,我們將PrefixRuleValidator類靜態添加到父級的ruleValidatorMap中。然后我們繼續創建父級的validate()方法的副本,這將有效地使我們的規則與其他默認規則一起可用。
最后,讓我們在控制器中使用我們的自定義規則:
清單 4.3
CustomPrefixController.java
@RestController
public class CustomPrefixController {
@PostMapping("/custom")
public ResponseEntity<GenericResponse> formCustomPrefix(@RequestBody Map<String, Object> request) {
Map<String, String> rules = Collections.singletonMap("objectType", "customprefix");
List<String> errors =
CustomRequestValidator.validate(request, rules);
if(!errors.isEmpty()) {
GenericResponse genericResponse = new GenericResponse();
genericResponse.setStatus(false);
genericResponse.setCode(
HttpStatus.BAD_REQUEST.value());
genericResponse.setErrors(errors);
genericResponse.setMessage("Missing required parameter(s)");
return ResponseEntity.badRequest().body(genericResponse);
}
return ResponseEntity.ok(
GenericResponse.generic200ResponseObj("Operation successful"));
}
}
發布有效請求將返回 200 OK:
清單 4.4 Curl請求/響應
Request:
curl --location --request POST 'http://localhost:8080/custom'
--header 'Content-Type: application/json'
--data-raw '{
"objectType": "custom_john"
}'
Response:
{
"status": true,
"message": "Operation successful",
"code": 200
}
另一方面,發布無效請求將返回錯誤消息,如代碼清單 4.1 PrefixRuleValidator.java 所示:
清單 4.5 Curl請求/響應
Request:
curl --location --request POST 'http://localhost:8080/custom'
--header 'Content-Type: application/json'
--data-raw '{
"objectType": "john"
}'
Response:
{
"status": false,
"message": "Missing required parameter(s)",
"errors": [
"objectType should start with custom_"
],
"code": 400
}
結論
在本文中,我們了解了如何輕松驗證 JSON 請求正文并確保 API 使用者發送我們期望的數據以及實際示例。完整的源代碼可在GitHub
https://github.com/SeunMatt/smattme-tutorials/tree/master/spring-boot-request-validator上獲得。快樂編碼。