在Spring控制器方法中,我们可以使用@Valid
和这样的东西进行REST请求参数验证
@PostMapping(REGISTER)
public ResponseEntity<SomeData> registerSomeData(@RequestBody @Valid final SomeData someData) {
...................
}
public class SomeData {
@Size(min = 2, max = 20)
private String firstname;
@Digits(fraction = 0, integer = 10)
private Integer customerID;
@NotNull
private Customer customer;
}
如果请求与这些约束不匹配,那么Spring框架将抛出Bad Request Exception(400)。
使用Spring5路由器功能,我不明白我们如何做到这一点,因为我们无法在路由器功能中提供@Valid
。
答案 0 :(得分:1)
我创建了 GeneralValidator
类,它可以工作 javax.validation.Validator
@Component
@RequiredArgsConstructor
public class GeneralValidator {
private final Validator validator;
private <T> void validate(T obj) {
if (obj == null) {
throw new IllegalArgumentException();
}
Set<ConstraintViolation<T>> violations = this.validator.validate(obj);
if (violations != null && !violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
}
/**
* @param obj object we will validate
* @param next Publisher we will call if don't have any validation hits
*/
public <T> Mono<ServerResponse> validateAndNext(T obj, Mono<ServerResponse> next) {
try {
validate(obj);
return next;
} catch (IllegalArgumentException ex) {
return ServerResponse.badRequest()
.body(new ErrorResponse("Request body is empty or unable to deserialize"), ErrorResponse.class);
} catch (ConstraintViolationException ex) {
return ServerResponse.badRequest()
.body(new ValidationErrorResponse(
"Request body failed validation",
ex.getConstraintViolations()
.stream()
.map(v -> "Field '%s' has value %s but %s"
.formatted(v.getPropertyPath(), v.getInvalidValue(),v.getMessage()))
.collect(Collectors.toList())
), ValidationErrorResponse.class);
}
}
}
使用方法:
...
.POST("/", req -> req.bodyToMono(RequestObject.class)
.flatMap(r -> validator.validateAndNext(r,routeFunction.execute(r)))
)
...
routeFunction.execute
:
public @NotNull Mono<ServerResponse> execute(RequestObject request) {
//handling body
}
答案 1 :(得分:0)
您无法使用(功能性)Spring Webflux进行基于注释的验证。请参阅this answer。
如果你绝对需要基于注释的验证,你应该知道你可以继续使用传统的Spring MVC和Spring 5(或非功能性的Webflux)。
答案 2 :(得分:0)
有点恼人的是,这种有用的功能似乎还没有被带入功能世界,但是您自己实施验证步骤确实并不难。就是这样。
创建一个bean来执行验证:
@Component
public class RequestValidator {
@Inject
Validator validator;
public <T> Mono<T> validate(T obj) {
if (obj == null) {
return Mono.error(new IllegalArgumentException());
}
Set<ConstraintViolation<T>> violations = this.validator.validate(obj);
if (violations == null || violations.isEmpty()) {
return Mono.just(obj);
}
return Mono.error(new ConstraintViolationException(violations));
}
}
现在,您的处理程序函数中将包含执行验证的步骤。在此示例中,FindRequest
类是JSON域模型类,其中包含诸如@NotEmpty
和@NotNull
等验证批注。根据此虚拟示例,调整构造ServerResponse
的方式调用反应式数据存储库。
@Component
public class MyHandler {
@Inject
RequestValidator validator;
public Mono<ServerResponse> findAllPeople(ServerRequest request) {
return request.bodyToMono(FindRequest.class)
.flatMap(this.validator::validate)
.flatMap(fr -> ServerResponse
.ok()
.body(this.repo.findAllByName(fr.getName()), Person.class));
}
}
可以使用相同的方法来扩展功能以处理Flux
和Mono
。