4

如何在Spring Boot中验证JSON请求内容? - Seun

 1 year ago
source link: https://www.jdon.com/63446
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

如何在Spring Boot中验证JSON请求内容?


本文中,我们将研究请求验证器库,它能够将用户输入与一组预定义的规则进行比较,并在有错误时返回错误。

依赖:

<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": "[email protected]",
    "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 上提供了完整的源代码。快乐的编码。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK