无法在Spring boot中使用@Valid验证请求主体

问题描述 投票:0回答:8

我想使用

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

这是我发送的请求:

对于超过 64 个字符的名字:

示例 JSON:

{
    "data": {
        "firstName": "student111111111111111111111111111111111111111111111111111111111111",
        "lastName": "somesurname",
        "email": "[email protected]"
    }
}

不包括名字的:

{
    "data": {
        "lastName": "somesurname",
        "email": "[email protected]"
    }
}

这里

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

有什么解决办法吗?

java spring spring-boot jackson bean-validation
8个回答
12
投票

如果

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
注释参数的验证检查。

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

这可能代价高昂,因为您希望尽快解决任何约束违规问题,而不需要为已经注定的请求做任何昂贵的工作。


2
投票

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

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

如果没有这种依赖关系,Spring Boot 将不会自动处理请求数据并对其应用验证规则,这就是为什么您没有获得预期的验证行为。所以现在您不需要使用 @Validated 注释,只需使用 @Valid 旁边的注释@RequestBody


1
投票

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


1
投票

首先对字符串使用

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


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
}

1
投票

您是否添加了以下依赖项?

spring-boot-starter-validation

另请检查https://www.baeldung.com/spring-boot-bean-validation


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

0
投票

@Valid
注释可以被完全忽略的另一个原因是缺少实际的验证器库。如果您的 Spring 项目不需要与数据库相关的启动器,并且因此错过了像
org.hibernate.validator:hibernate-validator
这样的库,则可能会发生这种情况。

Spring 甚至尝试告诉您日志中缺少验证器,但该消息可能会在 Spring 吐出的许多其他消息中丢失。

© www.soinside.com 2019 - 2024. All rights reserved.