有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

我在JAR文件中有一个请求类,不能用两个字段修改它。一个字段的类型为Object。我的控制器类接受该类对象作为请求主体。当我将下面的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) 个答案

  1. # 1 楼答案

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

  2. # 2 楼答案

    因此,您可以使用下面的代码来验证相同的代码

    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. # 3 楼答案

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

  4. # 4 楼答案

    如果Request类是这样的,那么验证就会起作用

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

    由于没有data的类类型,因此无法对其应用验证,而忽略了字段上甚至没有^{}注释的事实。@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
        }
    }
    

    使用^{}注释,您将激活该类中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)

    这可能代价高昂,因为您希望尽快获得任何违反约束的行为,而不必为已经注定失败的请求执行任何代价高昂的工作

  5. # 5 楼答案

    这里有几件事: 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;
    }