简体   繁体   English

无法使用@Valid 在 Spring 引导中验证请求正文

[英]Not able to validate request body in Spring boot with @Valid

I want to validate my request body with @Valid annotation, but it's not working in Spring Boot我想使用@Valid注释验证我的请求正文,但它在 Spring Boot 中不起作用

I have a Request class within JAR file which I can't modify with two fields.我在 JAR 文件中有一个请求 class,我无法用两个字段对其进行修改。 One field is of type Object. My controller class accept this class object as a request body.一个字段的类型是 Object。我的 controller class 接受这个 class object 作为请求主体。 When I pass my below JSON to the controller, validation is not working.当我将下面的 JSON 传递给 controller 时,验证不起作用。 Below are code samples.以下是代码示例。

Request Class:请求 Class:

public class Request {

    Object data;
    Map<String, Object> meta;

    public <T> T getData() throws ClassCastException {
        return (T) this.data;
    }
}

Another Class:另一个Class:

public class StudentSignUpRequest {

     @NotNull(message = "First Name should not be empty")
     @Size(max = 64, message = "FirstName should not exceed 64 characters")
     private String firstName;

     @NotNull(message = "Last Name should not be empty")
     @Size(max = 64, message = "LastName should not exceed 64 characters")
     private String lastName;

     @NotNull(message = "Email cannot be empty")
     @Size(max = 50, message = "Email cannot exceed 50 characters")
     @Pattern(regexp = EMAIL_REGEX_PATTERN, message = "Email should contain a valid email address.")
     private String email;

     // other fields
}

Controller Class: Controller Class:

@PostMapping(value = Constants.STUDENT_SIGN_UP)
public Response signUpStudent(@Valid @RequestBody Request request, HttpServletRequest servletRequest) {

    // retrieving the actual resource from request payload
    StudentSignUpRequest signUpRequest = request.getData(StudentSignUpRequest.class);
    // call service to sign-up student
    return loginRegistrationService.signUpStudent(signUpRequest);
}

Calling code sets request as below:调用代码设置请求如下:

StudentSignUpRequest studentSignUpRequest = new StudentSignUpRequest();
//setter methods

Request payload = new Request();
payload.setData(studentSignUpRequest);

This is the request I am sending:这是我发送的请求:

For more than 64 chars for firstName:对于 firstName 超过 64 个字符:

Sample JSON:样本 JSON:

{
    "data": {
        "firstName": "student111111111111111111111111111111111111111111111111111111111111",
        "lastName": "somesurname",
        "email": "developer@gmail.com"
    }
}

Where first name not included:不包括名字的地方:

{
    "data": {
        "lastName": "somesurname",
        "email": "developer@gmail.com"
    }
}

Here both @Size as well as @NotNull annotation not working.这里@Size@NotNull注释都不起作用。

Any solution?任何解决方案?

Validation would've worked if the Request class was like;如果Request类是这样的,验证就会起作用;

public class Request {

    @Valid
    StudentSignUpRequest data;

    // other stuff
}

The fact that you have no class type for data makes it impossible for validation to be applied on it, ignoring the fact that there isn't even a @Valid annotation on the field.您没有data类类型这一事实使得无法对其应用验证,忽略字段上甚至没有@Valid注释的事实。 The @Valid annotation is used to propagate the validation cascade. @Valid注释用于传播验证级联。

But since you cannot modify Request object, let's continue with another way to handle validation without doing it manually.但是由于您无法修改Request对象,让我们继续使用另一种方法来处理验证,而无需手动进行。


Another way is to trigger validation after you get the StudentSignUpRequest from request object;另一种方法是在从request对象中获取StudentSignUpRequest后触发验证;

StudentSignUpRequest signUpRequest = request.getData(StudentSignUpRequest.class);
loginRegistrationService.signUpStudent(signUpRequest) // validation will trigger with this call

What you can do is as follows;你可以做的如下;

@Service
@Validated
public class LoginRegistrationService {

    public void signUpStudent(@Valid StudentSignUpRequest signUpRequest) {
        // some logic
    }
}

with @Validated annotation, you will activate the validation check for any @Valid annotated args in public methods within that class.使用@Validated批注,您将激活对该类中public方法中的任何@Valid批注参数的验证检查。

Can be used with method level validation, indicating that a specific class is supposed to be validated at the method level (acting as a pointcut for the corresponding validation interceptor)可与方法级别验证一起使用,表示应该在方法级别验证特定类(充当相应验证拦截器的切入点)

This can be costly since you'd want to get any constraint violation as soon as possible without doing any costly jobs for an already doomed request.这可能是昂贵的,因为您希望尽快获得任何违反约束的情况,而无需为已经注定的请求做任何昂贵的工作。

没有验证将按照您使用它的方式工作,您需要将 @valid 放在请求对象内的对象上,但由于您无法控制该类,因此另一种方法是扩展 Request 对象并覆盖 getData 方法并应用 @valid在这种方法上,它应该以这种方式工作。

So you can use below code for validating the same.因此,您可以使用以下代码进行验证。

public <T> T getData() throws ClassCastException, SomeCustomValidationException {
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    validator = factory.getValidator();
    Set s = validator.validate(this.data);
    //throw SomeCustomValidationException if set is not empty else return this.data
}

First use @NotEmpty , @Notblank for Strings.首先对字符串使用@NotEmpty@Notblank Then ensure you import javax.validation.constraints not that of hibernate.然后确保您导入javax.validation.constraints而不是 hibernate 的。 If you are using a custom validator, you will need (final BindingResult bindingResult) as part of your controller method variable.如果您使用自定义验证器,则需要(final BindingResult bindingResult)作为控制器方法变量的一部分。

A couple of things here: The type Object for data in Request class makes it impossible for the validator to know that it is of type StudentSignUpRequest .这里有几件事: Request类中data Object类型使验证器不可能知道它是StudentSignUpRequest类型。 So change the data type.所以改变数据类型。

public class Request {
    StudentSignUpRequest data;
    Map<String, Object> meta;
}

Secondly, though you have added @Valid in the controller method, in order to validate fields in StudentSignUpRequest you have to add @Valid here as well.其次,虽然你已经添加@Valid在控制器的方法,以在验证领域StudentSignUpRequest你必须添加@Valid这里。 Now, data will be validated if passed in the API request.现在,如果在 API 请求中传递数据,将对其进行验证。 In case it is absent validation won't take place.如果不存在,则不会进行验证。 If you want to make data to be mandatorily passed add @NotNull as well.如果你想让数据被强制传递,也添加@NotNull。

public class Request {

    @Valid
    @NotNull
    StudentSignUpRequest data;
    Map<String, Object> meta;
}

did you add following dependency?您是否添加了以下依赖项?

spring-boot-starter-validation

also check https://www.baeldung.com/spring-boot-bean-validation还要检查https://www.baeldung.com/spring-boot-bean-validation

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM