【问题标题】:Not able to validate request body in Spring boot with @Valid无法使用 @Valid 在 Spring Boot 中验证请求正文
【发布时间】:2019-12-11 00:31:24
【问题描述】:

我想用 @Valid 注释验证我的请求正文,但它在 Spring Boot 中不起作用

我在 JAR 文件中有一个请求类,我无法使用两个字段进行修改。一个字段是对象类型。我的控制器类接受这个类对象作为请求体。当我将下面的 JSON 传递给控制器​​时,验证不起作用。以下是代码示例。

请求类:

public class Request {

    Object data;
    Map<String, Object> meta;

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

另一个类:

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
}

控制器类:

@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);
}

调用代码设置请求如下:

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

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

这是我发送的请求:

名字超过 64 个字符:

示例 JSON:

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

不包括名字的地方:

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

这里@Size@NotNull 注释都不起作用。

有什么办法吗?

【问题讨论】:

    标签: java spring spring-boot jackson bean-validation


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      首先使用@NotEmpty@Notblank 表示字符串。然后确保你导入javax.validation.constraints 而不是hibernate。如果您使用自定义验证器,则需要 (final BindingResult bindingResult) 作为控制器方法变量的一部分。

      【讨论】:

      • 不,我没有使用自定义验证。我已经导入了 javax.validation 类。
      【解决方案3】:

      如果 Request 类是这样的,验证会起作用;

      public class Request {
      
          @Valid
          StudentSignUpRequest data;
      
          // other stuff
      }
      

      您没有data 的类类型这一事实使得无法对其应用验证,忽略了该字段上甚至没有@Valid 注释的事实。 @Valid 注解用于传播验证级联。

      但是由于您无法修改Request 对象,让我们继续使用另一种方式来处理验证,而无需手动进行。


      另一种方法是在从request 对象中获取StudentSignUpRequest 后触发验证;

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

      你可以做的如下;

      @Service
      @Validated
      public class LoginRegistrationService {
      
          public void signUpStudent(@Valid StudentSignUpRequest signUpRequest) {
              // some logic
          }
      }
      

      使用@Validated 注释,您将激活该类中public 方法中任何@Valid 注释参数的验证检查。

      可以与方法级别的验证一起使用,表明一个 特定的类应该在方法级别进行验证(代理 作为相应验证拦截器的切入点)

      这可能代价高昂,因为您希望尽快违反任何约束,而不为已经注定的请求做任何代价高昂的工作。

      【讨论】:

        【解决方案4】:

        这里有几件事: 在Request 类中dataObject 类型使得验证器不可能知道它是StudentSignUpRequest 类型。所以改变数据类型。

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

        其次,虽然您在控制器方法中添加了@Valid,但为了验证StudentSignUpRequest 中的字段,您还必须在此处添加@Valid。现在,如果在 API 请求中传递数据,则将对其进行验证。如果不存在,则不会进行验证。如果要强制传递数据,也可以添加@NotNull。

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

        【讨论】:

          【解决方案5】:

          所以你可以使用下面的代码来验证它。

          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
          }
          

          【讨论】:

            猜你喜欢
            • 2020-10-18
            • 2020-03-14
            • 2018-08-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-11-02
            • 2022-01-01
            • 1970-01-01
            相关资源
            最近更新 更多