无法通过@Valid在Spring Boot中验证请求体

9

我希望使用@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);

这是我发送的请求:

如果firstName超过64个字符:

示例JSON:

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

当名字未包含时:

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

这里的@Size@NotNull注解都无法起作用。

有什么解决方案吗?

7个回答

12

如果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注释,您可以激活该类中所有公共方法中具有@Valid注释的参数的验证检查。

可用于方法级别的验证,表示特定类应在方法级别上进行验证(充当相应验证拦截器的切入点)

这可能很昂贵,因为您希望尽快获得任何约束违规,而不会对已经注定失败的请求执行任何昂贵的工作。


1
没有任何一种验证方式可以按照你的使用方式工作,你需要在请求对象中放置@valid标记,但由于你无法控制该类,另一种方法是扩展请求对象并覆盖getData方法,并在该方法上应用@valid标记,这样应该可以正常工作。

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

不,我没有使用自定义验证。我已经导入了javax.validation类。 - asp008

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
}

0

0
这里有几件事情需要注意: 在Request类中,data的类型为Object,这使得验证器无法知道它是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;
}

0

在Spring Boot应用程序中启用验证支持。您需要这个依赖项:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

没有这个依赖,Spring Boot 将不会自动处理和应用验证规则到你的请求数据上,这就是为什么你没有得到预期的验证行为。所以现在你不需要使用 @Validated 注解,只需要在 @RequestBody 旁边使用 @Valid。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接