Проверка бина не работает для весеннего webflux
Я реорганизовал мой код для использования 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 вместо плохого запроса, который я возвращаю из совета диспетчера.
Изменить 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: не найден экстрактор значения для параметра типа 'T' типа реактора.core.publisher.Mono.
4 ответа
Ничто не сработало для меня. Поэтому я проверил это вручную с помощью 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;
}
Для меня
@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());
}
Аннотация @Valid проверяет объект. Итак, вы пытаетесь проверить Mono, вам нужно перейти на объект LoginModel, например:
..getUserContacts(@RequestBody Mono<@Valid LoginModel> loginDetail) {
...
}
Используйте @Validated в классе обслуживания и @Valid в параметре Entity/DTO метода, для которого вам нужна проверка. Библиотеки: jakarta.validation-api и Spring-boot-starter-validation.