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

时间:2019-08-02 11:19:30

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

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

我在JAR文件中有一个Request类,无法使用两个字段进行修改。一个字段是对象类型。我的控制器类接受该类对象作为请求主体。当我将下面的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);

这是我发送的请求:

对于firstName,超过64个字符:

示例JSON:

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

不包括名字的地方

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

此处@Size@NotNull注释均无效。

有解决方案吗?

5 个答案:

答案 0 :(得分:5)

如果Request类是什么样的,验证就可以了;

public class Request {

    @Valid
    StudentSignUpRequest data;

    // other stuff
}

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

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


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

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批注,您将激活该类内@Valid方法中任何带有public注释的参数的验证检查。

  

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

这可能是昂贵的,因为您希望尽快得到任何违反约束的信息,而不必为已经注定的请求做任何昂贵的工作。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

因此,您可以使用以下代码进行验证。

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
}

答案 3 :(得分:0)

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

答案 4 :(得分:0)

这里有几件事: Object类中data的类型Request使验证者无法知道它的类型为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;
}