Han*_*tsy 5 spring functional-programming bean-validation project-reactor spring-webflux
在传统的Web应用程序中,很容易通过控制器方法来验证请求主体。
ResponseEntity create(@Valid @ResponseBody Post post) {
}
Run Code Online (Sandbox Code Playgroud)
如果它是一个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)
}
Run Code Online (Sandbox Code Playgroud)
一种可能的方法是将请求数据(Mono或Flux)转换为阻止并注入Validator并手动验证它们。
但是我认为代码看起来有些丑陋。
如何优雅地处理请求正文或表单数据的验证?
是否有更好的方法来验证请求正文或表单数据,并且不会丢失WEB(呈现视图)和REST应用程序的功能和响应功能?
我为这个 porpose 开发了“Yet Another Validator”。
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))));
}
Run Code Online (Sandbox Code Playgroud)
我在应用程序中设法做到这一点的方法之一如下(代码是用 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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
请求对象可以通过以下方式包含 java 验证注释:
data class TokenRequest constructor(@get:NotBlank val accessToken: String) {
constructor() : this("")
}
Run Code Online (Sandbox Code Playgroud)
处理程序类用于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)
}
Run Code Online (Sandbox Code Playgroud)
从这篇博文中得到了这个想法。
| 归档时间: |
|
| 查看次数: |
3483 次 |
| 最近记录: |