在传统的Web应用程序中,很容易在控制器方法中验证请求主体,例如。
ResponseEntity create(@Valid @ResponseBody Post post) {
}
如果它是MVC应用程序,我们可以通过注入BindingResult
来收集错误,并确定输入表单中是否存在某些验证错误。
在页面中,Freemarker和Thymeleaf都有一些助手来显示消息。
但是当我来到Webflux并尝试使用RouterFunction
来定义应用程序中的路由时。例如,
Mono<ServerResponse> create(ServerRequest req) {
return req.bodyToMono(Post.class)
.flatMap { this.posts.save(it) }
.flatMap { ServerResponse.created(URI.create("/posts/".concat(it.getId()))).build() }
}
@Bean
RouterFunction<ServerResponse> routes(PostHandler postController) {
return route(GET("/posts"), postController.&all)
.andRoute(POST("/posts"), postController.&create)
.andRoute(GET("/posts/{id}"), postController.&get)
.andRoute(PUT("/posts/{id}"), postController.&update)
.andRoute(DELETE("/posts/{id}"), postController.&delete)
}
一种可行的方法是将请求数据(Mono
或Flux
)转换为阻止并注入Validator
并手动验证它们。
但我觉得这些代码看起来有点难看。
如何处理请求正文或表单数据验证正常?
是否更好地验证请求正文或表单数据,并且不会丢失WEB(呈现视图)和REST应用程序的功能和反应功能?
答案 0 :(得分:2)
我在我的应用程序中设法完成的方法之一是(代码在Kotlin,但想法是一样的)。我已声明RequestHandler
类执行验证:
@Component
class RequestHandler(private val validator: Validator) {
fun <BODY> withValidBody(
block: (Mono<BODY>) -> Mono<ServerResponse>,
request: ServerRequest, bodyClass: Class<BODY>): Mono<ServerResponse> {
return request
.bodyToMono(bodyClass)
.flatMap { body ->
val violations = validator.validate(body)
if (violations.isEmpty())
block.invoke(Mono.just(body))
else
throw ConstraintViolationException(violations)
}
}
}
请求对象可以通过以下方式包含java验证注释:
data class TokenRequest constructor(@get:NotBlank val accessToken: String) {
constructor() : this("")
}
处理程序类使用RequestHandler
执行验证:
fun process(request: ServerRequest): Mono<ServerResponse> {
return requestHandler.withValidBody({
tokenRequest -> tokenRequest
.flatMap { token -> tokenService.process(token.accessToken) }
.map { result -> TokenResponse(result) }
.flatMap { ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(Mono.just(it), TokenResponse::class.java)
}
}, request, TokenRequest::class.java)
}
从blog post获得了这个想法。
答案 1 :(得分:2)
我为此目的开发了“另一个验证器”。
https://github.com/making/yavi
如果YAVI能够满足您的期望,那就太好了。
验证代码如下:
static RouterFunction<ServerResponse> routes() {
return route(POST("/"), req -> req.bodyToMono(User.class) //
.flatMap(body -> validator.validateToEither(body) //
.leftMap(violations -> {
Map<String, Object> error = new LinkedHashMap<>();
error.put("message", "Invalid request body");
error.put("details", violations.details());
return error;
})
.fold(error -> badRequest().syncBody(error), //
user -> ok().syncBody(user))));
}