Bean 验证不适用于 Spring Webflux

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

我已经重构了我的代码以使用 spring webflux,但现在

@Valid
停止工作。 它没有验证请求正文。

@PostMapping(value = "/getContactInfo",produces = "application/json",consumes = "application/json")
public Flux<UserContactsModel> getUserContacts(@Valid @RequestBody Mono<LoginModel> loginDetail) {

    loginDetail.log();
    return contactInfoService
        .getUserContacts(loginDetailApiMapper.loginModelMonoToLoginBoMono(loginDetail))
        .flatMapIterable(
            userContactsBO -> contactInfoMapper.userContactBoToModelList(userContactsBO));
}

我收到 200 OK 来代替我从控制器建议中返回的 Bad request。

编辑1:

   import javax.validation.constraints.NotNull;
   import javax.validation.constraints.Pattern;

    public class LoginModel implements Serializable {

      private String clientId;

      @Pattern(regexp = "^[a-zA-Z0-9]*$", message = "Login ID is invalid")
      @NotNull
      private String loginId;
    }

更新1: 像这样更改代码并在类级别添加 @Validated 后

@RestController
@Validated
public class ContactInfoController implements ContactInfoApi {
public Flux<UserContactsModel> getUserContacts(@RequestBody  Mono<@Valid  LoginModel> loginDetail) {

我收到 javax.validation.ConstraintDeclarationException: HV000197: 未找到类型为reactor.core.publisher.Mono 的类型参数“T”的值提取器。

java validation spring-boot spring-webflux reactive
4个回答
2
投票

没有什么对我有用。所以我使用 javax.validator 手动验证它。

@Autowired private Validator validator;

 public Flux<UserContactsModel> getUserContacts(@RequestBody Mono<@Valid LoginModel> loginDetail) {

    return loginDetail
        .filter(this::validate)
        .map(....);
}

 private boolean validate(LoginModel loginModel) {

    Set<ConstraintViolation<LoginModel>> constraintViolations = validator.validate(loginModel);

    if (CollectionUtils.isNotEmpty(constraintViolations)) {
      StringJoiner stringJoiner = new StringJoiner(" ");
      constraintViolations.forEach(
          loginModelConstraintViolation ->
              stringJoiner
                  .add(loginModelConstraintViolation.getPropertyPath().toString())
                  .add(":")
                  .add(loginModelConstraintViolation.getMessage()));
      throw new RuntimeException(stringJoiner.toString());
    }

    return true;
  }

2
投票

对我来说,

@Valid
开箱即用,缺少的部分是在类路径中添加
spring-boot-starter-validation

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

我有与这个问题完全相同的控制器代码,加上

ExceptionHandler
来处理 bean 验证错误:

@ResponseBody
@ExceptionHandler(WebExchangeBindException.class)
Mono<ResponseEntity<List<ErrorDTO>>> invalidRequestErrorHandler(@NotNull final WebExchangeBindException e) {
    log.error("Invalid request exception occurred", e);
    var errors = e.getBindingResult()
            .getAllErrors()
            .stream()
            .filter(Objects::nonNull)
            .map(this::getValidationErrorMessage)
            .toList();
    return Mono.just(ResponseEntity.status(BAD_REQUEST)
            .contentType(APPLICATION_JSON)
            .body(errors));
}

@NotNull
private ErrorDTO getValidationErrorMessage(@NotNull final ObjectError error) {
    final var errorMessage = new StringBuilder();
    if (error instanceof FieldError fe) {
        errorMessage.append(fe.getField()).append(" - ");
    }
    errorMessage.append(error.getDefaultMessage());
    return new ErrorDTO()
            .errorCode(GENERIC_ERROR).message(errorMessage.toString());
}

0
投票

在Service类中使用@Validated,并在需要验证的方法的Entity/DTO参数中使用@Valid。 库:jakarta.validation-api 和 spring-boot-starter-validation


-1
投票

@Valid 注解验证对象。所以你试图验证一个Mono,你需要更改为LoginModel对象,例如:

  ..getUserContacts(@RequestBody Mono<@Valid LoginModel> loginDetail) {
      ...
  }
© www.soinside.com 2019 - 2024. All rights reserved.