本文中,我们将研究请求验证器库,它能够将用户输入与一组预定义的规则进行比较,并在有错误时返回错误。
依赖:
<dependency> <groupId>com.smattme</groupId> <artifactId>request-validator</artifactId> <version>0.0.2</version> </dependency>
|
验证JSON请求体
鉴于我们有一个简单的登录端点,需要一个有效的电子邮件和密码,作为一个好的工程师,我们要确保用户发送的两个字段和电子邮件是有效的。
我们可以通过request-validator库轻松实现这一目标。对于电子邮件输入字段,我们希望用户提供一个非空字段和一个有效的电子邮件地址,而对于密码字段,我们只希望用户提供一个非空值。
@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字符串。
如果API用户提供了一个无效的请求体,他们会收到一个400错误请求,并附有所有数据违规的详细列表。
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 }
|
请注意,返回的错误列表<String>可以以你和你的团队选择的任何方式作为你的响应的一部分。它并不局限于本文所演示的响应格式。
完整的源代码可在本文末尾找到,它将帮助你更好地理解本教程中的响应格式是如何形成的。
请求验证器库允许我们使用管道(|)字符作为分隔符,将一个或多个规则组合在一起。在上面的清单3.1中,我们使用|将required和email规则组合在一起。
唯一的例外是,当使用regex规则和其他规则时。它应该是最后一条规则,并且应该像||那样用双管字符分开。这是为了适应regex模式中可能存在的管道字符。
Regex Pattern:
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接口并执行自定义逻辑。
PrefixRuleValidator.java
public class PrefixRuleValidator implements RuleValidator { private static final String CUSTOM_PREFIX = "custom_"; @Override public ValidationResult isValid(Object value, Rule rule) { return value != null && String.class.isAssignableFrom(value.getClass()) && value.toString().startsWith(CUSTOM_PREFIX) ? ValidationResult.success() : ValidationResult.failed(rule.getKey() + " should start with " + CUSTOM_PREFIX); } }
|
我们需要的下一个组件是一个将扩展RequestValidator的类。我们将调用这个CustomRequestValidator,而不是库中的RequestValidator,来进行检查。
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()方法的副本,这将有效地使我们的规则与其他默认规则一起使用。
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
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中的编码。
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 上提供了完整的源代码。快乐的编码。