Spring Boot验证注释@Valid和@NotBlank无效

66

以下是我的主控制器,我从中调用getPDFDetails方法。

@RequestMapping(value=PATH_PRINT_CONTRACTS, method=RequestMethod.POST)
    public ResponseEntity<?> printContracts(@RequestBody final UpdatePrintContracts updatePrintContracts) throws Exception {
    
        System.out.println("contracts value is "+ updatePrintContracts);
        
        Integer cancellationReasons = service.getPDFDetails(updatePrintContracts);
        
        System.out.println("success!");
        
        return ResponseEntity.ok(cancellationReasons);
    }   

以下是 UpdatePrintContracts 类,我已经使用验证注释定义了所有变量和相应的 getter/setter 方法。

public class UpdatePrintContracts {
    
    @Valid
    @NotBlank
    @Pattern(regexp = "\\p{Alnum}{1,30}")
    String isReprint;
    
    @Valid
    @NotBlank
    Integer dealerId;
    
    @Valid
    @NotBlank
    @Pattern(regexp = "\\p{Alnum}{1,30}")
    String includeSignatureCoordinates;
    
    @Valid
    @NotBlank
    java.util.List<Integer> contractNumbers;

    public String getIsReprint() {
        return isReprint;
    }

    public void setIsReprint(String isReprint) {
        this.isReprint = isReprint;
    }

    public Integer getDealerId() {
        return dealerId;
    }

    public void setDealerId(Integer dealerId) {
        this.dealerId = dealerId;
    }

    public String getIncludeSignatureCoordinates() {
        return includeSignatureCoordinates;
    }

    public void setIncludeSignatureCoordinates(String includeSignatureCoordinates) {
        this.includeSignatureCoordinates = includeSignatureCoordinates;
    }

    public java.util.List<Integer> getContractNumbers() {
        return contractNumbers;
    }

    public void setContractNumbers(java.util.List<Integer> contractNumbers) {
        this.contractNumbers = contractNumbers;
    }
    
}

我试图通过在项目上右键单击(运行为)并通过Soap UI传递变量isReprintincludeSignatureCoordinates的空值来将应用程序作为Spring Boot应用程序运行。 但是验证似乎不起作用,并且Soap UI没有抛出任何验证错误。 我错过了什么? 感谢任何帮助!


2
@NotBlank is for text only, not integer. Try to start from the simplest, with only one field for validation like @NotBlank String foo; if that works, move on to other more complicated ones like @Pattern - Tiina
在我的情况下,我忘记在控制器中添加@Valid标签。 - Rishabh Ryber
17个回答

129

如果您在最新版本的Spring Boot(2.3.0)中遇到此问题,请确保添加以下依赖项:

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

观察: 在较早版本的Spring Boot(1.4.7)中,javax.validation可以直接使用。但是,在升级到最新版本后,注释出现了问题。仅添加以下依赖项不起作用:

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
</dependency>

因为这提供了JSR规范但不提供实现。您还可以使用hibernate-validator代替spring-boot-starter-validation


6
添加spring-boot-starter-validation解决了我的问题。谢谢! - Rubén
1
这对我来说是解决方案。有没有办法减少关于验证错误的信息,我的意思是跟踪消息包含内部代码流程? - Ahmet Karakaya
这解决了我的问题!!我正在使用Spring Boot v2.6 - Jay Yadav

37

对于任何在2.0.1.Final版本中遇到此问题的人:

在所有SpringBoot 2.2以上版本中,验证启动器不再是Web启动器的一部分

在这里查看说明

所以,您需要在build.gradle/pom文件中添加此依赖项

GRADLE:

implementation 'org.springframework.boot:spring-boot-starter-validation'

MAVEN

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

我正在使用web-starter-2.6.5,显然没有适当的验证@NotNull@NotEmpty@NotBlank,但是有来自org.springframework.lang@NonNullValidated。我曾经困惑了一段时间,并验证了@NonNullValidated不是要使用的适当验证方式。感谢您的答案,它帮了我大忙。 - seedme

22

我遇到了相同的错误。

我只需使用以下两个依赖项:

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

在REST控制器级别上使用@Validated注释(import org.springframework.validation.annotation.Validated),并在方法参数级别上使用@Valid注释(import javax.validation.Valid)。

如果存在其他额外依赖项,例如javax.validation.validation-apiorg.hibernate.hibernate-validator等,则验证对我来说停止工作。因此,请确保从pom.xml中删除这些依赖项。


1
可以运行。但文档中完全没有提到这一点,好像我们应该已经知道了这些东西。 - Ojonugwa Jude Ochalifu
这个评论让我免于陷入调试地狱,因为我有javax.validation.validation-apiorg.hibernate.hibernate-validator作为依赖项。通过执行其他步骤(拥有spring-boot-starter-validation、@Validated和@Valid注释),一切都神奇地解决了!非常感谢!:D - Lavinia
我也遇到了同样的问题,尝试了所有方法,但只有在从classpath中删除org.hibernate.hibernate-validator后才能正常工作。 - George Barbosa

21

首先,在UpdatePrintContracts类变量上不需要使用@Valid注释。您可以将其删除。

要触发验证@Controller输入,只需将输入参数标注为@Valid或@Validated:

@RequestMapping(value=PATH_PRINT_CONTRACTS, method=RequestMethod.POST)
public ResponseEntity<?> printContracts(@Valid @RequestBody  final UpdatePrintContracts updatePrintContracts) throws Exception {

点击此处了解在Spring Boot中验证模型的完整理解。

如果要检查一个字符串是否只包含特定的字符,则必须添加锚点(^用于字符串的开头,$用于字符串的结尾),以确保您的模式匹配整个字符串。花括号仅用于表示数量。

@Pattern(regexp = "^[\\p{Alnum}]{1,32}$")

最后我假设您的类路径中包含以下jar包:

.validation-api.jar(包含抽象API和注释扫描器)

.hibernate-validator.jar(包含具体实现)


1
尝试不发送isReprint/includeSignatureCoordinates,看看是否会出现错误。请注意,不发送和发送空白是两回事,希望你知道我的意思。 - surya
在类声明上方使用@validated注释不是可以达到相同的效果吗? - Nate T

11

在使用@RequestBody之前,请确保使用@Valid注释。

对于较新版本的Spring Boot,请确保所有验证注释都来自 jakarta.validation.* 包,而不是 javax.validation.*。因为这两者的注释名称相同。


1
我正在使用Spring Boot 3和Hibernate-Validator 8.0.0.Final,并且导入jakarta.validation.*而不是javax.validation.*注释解决了我的问题。 - luizfzs
@Adarsh R Jayan 的回答非常完美,这是唯一可行的解决方案。请记得在控制器中添加 @Validated,同时在控制器中使用 jakarta 导入 @Valid - Emmanuel Njorodongo

10

我在使用Spring Boot的验证依赖时遇到了问题,但它没有起作用。

<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>

我将其替换为spring-boot-starter-validation,然后它就能正常工作了。

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot- 
starter-validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.4.0</version>

请在REST控制器中的请求体上添加@Validated代码,以便进行验证。 - Sandeep Jain
这就是我的问题所在。在按照上述更改依赖项后,它可以正常工作了。 - Nipuna Upeksha

8
这段内容是关于解决IT技术问题的提示:如果在按照上述步骤后,问题仍然存在,请重新启动我的IDE(IntelliJ),以使更改生效。

6
如果您使用的是Spring版本大于3,并且使用Kotlin,您应该添加@field:Annotation。
例如:
@field:NotEmpty
@field:NotNull
@field:NotBlank(message = "Email is required")
@field:Email(message = "Please provide a valid email")
val email: String,
@field:NotEmpty
@field:NotNull
@field:NotBlank(message = "Password is required")
val password: String,

问题被标记为“java”(而不是“kotlin”),因此我不知道发布Kotlin代码会有多大帮助。 - Abra
1
太有帮助了,谢谢! - Mike Muske
1
谢谢!我遇到了同样的问题,不过是在使用Kotlin时。你关于@field:Annotation的评论帮了我很多。 - Marcos

5

这解决了我的问题。 当我们在类内部使用需要验证的类时,所有相关的类都需要注释@Valid更多细节请看链接


4

步骤1:在pom.xml文件中添加以下两个依赖项

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
    </dependency>

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

步骤2:创建一个自定义异常类,如下所示。
package com.bjit.salon.auth.service.exceptions;


import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.stream.Collectors;

@ControllerAdvice
public class AnynameApplicationException {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseEntity<List<String>> processUnmergeException(final 
MethodArgumentNotValidException ex) {

        List<String> list = ex.getBindingResult().getAllErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.toList());

        return new ResponseEntity<>(list, HttpStatus.BAD_REQUEST);
    }
}

步骤三:将@Valid注解添加到方法参数中,就像这样。
public ResponseEntity<?> registerAccount(@Valid @RequestBody UserRegisterDto 
      registerDto) {
       
    // rest of the codes
}

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