根据当前文档(5.0.0.RELEASE),Spring Webflux 在使用带注释的控制器时支持验证:
默认情况下,如果 Bean Validation 存在于类路径中 — 例如 Hibernate Validator,LocalValidatorFactoryBean 被注册为 全局验证器与 @Valid 一起使用并在 @Controller 上进行验证 方法参数。
但是没有提及如何使用功能端点实现自动化。事实上,文档中唯一的输入处理示例并不能验证任何内容:
public Mono<ServerResponse> createPerson(ServerRequest request) {
Mono<Person> person = request.bodyToMono(Person.class);
return ServerResponse.ok().build(repository.savePerson(person));
}
我们应该手动执行此操作还是有某种自动方法可以执行此操作?
在 Spring 5.0 版本中,没有自动方法在功能端点中进行验证,因此必须手动完成此类验证。
虽然目前没有具体计划这样做,但我们将来可能会添加某种验证。但即便如此,它也将是一个显式的方法调用,而不是一个自动机制。总体而言,功能端点模型的设计比基于注释的模型更加明确。
正如 arjen-poutsma 所说,似乎无法在 Spring 5 功能端点上运行自动验证。
Spring 文档对此不是很清楚,并且没有建议任何方法。
在这篇 Baeldung 文章中,您将找到有关如何使用此方法运行验证的想法(免责声明:我是本文的作者:))
简而言之,您可以按照以下步骤操作:
编辑:
我一直在关注这个相关的 Spring 问题,看来我们现在依赖于有关此主题的官方文档:https://docs.spring.io/spring-framework/reference/web/webflux-featured.html #webflux-fn-handler-validation
建议的方法是使用文章中解释的验证器:
验证
功能端点可以使用 Spring 的验证工具将验证应用于请求正文。
在当前版本(2.0.4.RELEASE)中,没有办法使用句柄进行自动验证,但是您始终可以像这样进行手动验证:
@Slf4j
@Component
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@RequiredArgsConstructor
public class MyHandlerValidator implements HandlerValidator<MyResource> {
Validator validator;
@Override
public void callValidator(final MyResource fdr) {
final DataBinder binder = new DataBinder(fdr);
binder.setValidator(validator);
binder.validate();
if (binder.getBindingResult().hasErrors()) {
final String reason = binder.getBindingResult().getFieldError().toString();
log.error(reason);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, reason);
}
}
}
与此相关的事情是,您应该像自动验证一样抛出 WebExchangeBindException,但是我无法创建 MethodParameter 女巫是创建此异常的依赖项。
更新: Spring 向我们展示了一种方法来做到这一点,这与我的解决方案类似,但是,我认为在文档
方面还不够只是为了演示一些工作代码。如果您需要基于对象注释的简单验证,例如:
@Value
@Builder
@Jacksonized
public class SigninRequest {
@NotBlank(message = "The username is mandatory")
@Email(message = "The username should be valid Email")
String username;
@NotBlank(message = "The password is mandatory")
String password;
}
在处理程序中,您只需要一个简单的附加操作符 doOnNext:
@Component
@RequiredArgsConstructor
public class AuthHandler {
private final AuthService authService;
private final ObjectValidator validator;
public Mono<ServerResponse> signin(ServerRequest request) {
return ok().body(
request.bodyToMono(SigninRequest.class)
.doOnNext(validator::validate) //<-- just one single line
.flatMap(login -> authService.authenticate(login.getUsername(), login.getPassword())),
AuthResult.class);
}
}
ObjectValidator 正在执行实际验证,并在出现验证错误时抛出运行时异常并显示 4xx 错误:
@Component
@RequiredArgsConstructor
public class ObjectValidator {
private final Validator validator;
public <T> T validate(T object) {
var errors = validator.validate(object);
if (errors.isEmpty()) {
return object;
} else {
String errorDetails = errors.stream().map(er -> er.getMessage()).collect(Collectors.joining(", "));
throw new ObjectValidationException(errorDetails);
}
}
}
例外:
@ResponseStatus(code = HttpStatus.UNPROCESSABLE_ENTITY)
public class ObjectValidationException extends RuntimeException {
public ObjectValidationException(String errorDetails) {
super("Please supply the valid data: " + errorDetails);
}
}
如果正确设置全局错误处理,您可以保持处理程序代码干净并在所有处理程序中重用对象验证器。