springboot webflux 過濾器(使用RouterFunction實(shí)現(xiàn))
webflux過濾器(RouterFunction實(shí)現(xiàn))
相關(guān)類與接口
HandlerFiterFunction
@FunctionalInterface public interface HandlerFilterFunction<T extends ServerResponse, R extends ServerResponse> { ? ? Mono<R> filter(ServerRequest var1, HandlerFunction<T> var2); ? ? ? default HandlerFilterFunction<T, R> andThen(HandlerFilterFunction<T, T> after) { ? ? ? ? Assert.notNull(after, "HandlerFilterFunction must not be null"); ? ? ? ? return (request, next) -> { ? ? ? ? ? ? HandlerFunction<T> nextHandler = (handlerRequest) -> { ? ? ? ? ? ? ? ? return after.filter(handlerRequest, next); ? ? ? ? ? ? }; ? ? ? ? ? ? return this.filter(request, nextHandler); ? ? ? ? }; ? ? } ? ? ? default HandlerFunction<R> apply(HandlerFunction<T> handler) { ? ? ? ? Assert.notNull(handler, "HandlerFunction must not be null"); ? ? ? ? return (request) -> { ? ? ? ? ? ? return this.filter(request, handler); ? ? ? ? }; ? ? } ? ? ? static HandlerFilterFunction<?, ?> ofRequestProcessor(Function<ServerRequest, Mono<ServerRequest>> requestProcessor) { ? ? ? ? Assert.notNull(requestProcessor, "Function must not be null"); ? ? ? ? return (request, next) -> { ? ? ? ? ? ? Mono var10000 = (Mono)requestProcessor.apply(request); ? ? ? ? ? ? next.getClass(); ? ? ? ? ? ? return var10000.flatMap(next::handle); ? ? ? ? }; ? ? } ? ? ? static <T extends ServerResponse, R extends ServerResponse> HandlerFilterFunction<T, R> ofResponseProcessor(Function<T, Mono<R>> responseProcessor) { ? ? ? ? Assert.notNull(responseProcessor, "Function must not be null"); ? ? ? ? return (request, next) -> { ? ? ? ? ? ? return next.handle(request).flatMap(responseProcessor); ? ? ? ? }; ? ? } }
HandlerFunction
@FunctionalInterface public interface HandlerFunction<T extends ServerResponse> { ? ? Mono<T> handle(ServerRequest var1); }
示例
config 層
CustomRouterConfig
@Configuration public class CustomRouterConfig { ? ? ? @Bean ? ? public RouterFunction<ServerResponse> initRouterFunction(){ ? ? ? ? return RouterFunctions.route() ? ? ? ? ? ? ? ? .GET("/test/**",serverRequest -> { ? ? ? ? ? ? ? ? ? ? System.out.println("path:"+serverRequest.exchange().getRequest().getPath().pathWithinApplication().value()); ? ? ? ? ? ? ? ? ? ? ? return ServerResponse.ok().bodyValue("hello world"); ? ? ? ? ? ? ? ? }) ? ? ? ? ? ? ? ? .filter((serverRequest, handlerFunction) -> { ? ? ? ? ? ? ? ? ? ? System.out.println("custom filter"); ? ? ? ? ? ? ? ? ? ? ? return handlerFunction.handle(serverRequest); ? ? ? ? ? ? ? ? }) ? ? ? ? ? ? ? ? .build(); ? ? } }
使用測(cè)試
localhost:8080/test/text,控制臺(tái)輸出:
2020-06-21 15:18:08.005 INFO 16336 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
2020-06-21 15:18:08.018 INFO 16336 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 1.807 seconds (JVM running for 2.641)
custom filter
path:/test/text
RouterFunction的webflux
RouterFunction可以運(yùn)行在servlet或netty上,所以我們需要將兩個(gè)容器間的不同點(diǎn)抽象出來。
整個(gè)開發(fā)過程有幾步:
1.HandleFunction,實(shí)現(xiàn)輸入ServerRequest,輸出ServerResponse
2.RouterFunction,把請(qǐng)求url和HandlerFunction對(duì)應(yīng)起來
3.把RouterFunction包裝成HttpHandler,交給容器Server處理。
代碼
實(shí)體類和倉庫不變
handler:
@Component public class UserHandler { ? ? private final UserRepository repository; ? ? ? public UserHandler(UserRepository repository) { ? ? ? ? this.repository = repository; ? ? } ? ? ? public Mono<ServerResponse> getAllUser(ServerRequest request){ ? ? ? ? return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) ? ? ? ? ? ? ? ? .body(repository.findAll() , User.class); ? ? } ? ? public Mono<ServerResponse> createUser(ServerRequest request){ ? ? ? ? Mono<User> userMono = request.bodyToMono(User.class); ? ? ? ? return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) ? ? ? ? ? ? ? ? .body(repository.saveAll(userMono) , User.class); ? ? } ? ? public Mono<ServerResponse> deleteUserById(ServerRequest request){ ? ? ? ? String id = request.pathVariable("id"); ? ? ? ? return this.repository.findById(id) ? ? ? ? ? ? ? ? .flatMap(user -> this.repository.delete(user) ? ? ? ? ? ? ? ? ? ? ? ? .then(ServerResponse.ok().build())) ? ? ? ? ? ? ? ? .switchIfEmpty(ServerResponse.notFound().build()); ? ? } }
router:
@Configuration public class AllRouters { ? ? @Bean ? ? RouterFunction<ServerResponse> userRouter(UserHandler handler){ ? ? ? ? return RouterFunctions.nest( ? ? ? ? ? ? ? ? //相當(dāng)于requestMapping ? ? ? ? ? ? ? ? RequestPredicates.path("/user") , ? ? ? ? ? ? ? ? RouterFunctions.route(RequestPredicates.GET("/") , handler::getAllUser) ? ? ? ? ? ? ? ? ? ? .andRoute(RequestPredicates.POST("/").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)) , handler::createUser) ? ? ? ? ? ? ? ? ? ? .andRoute(RequestPredicates.DELETE("/{id}") , handler::deleteUserById)); ? ? ? } }
接下來看看routerFunction下的參數(shù)校驗(yàn)
改造下代碼(這里只寫一個(gè)做例子)
public Mono<ServerResponse> createUser(ServerRequest request){ ? ? ? ? Mono<User> userMono = request.bodyToMono(User.class); ? ? ? ? return userMono.flatMap(user -> { ? ? ? ? ? ? //在這里做校驗(yàn) ? ? ? ? ? ? //xxx ? ? ? ? ? ? return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) ? ? ? ? ? ? ? ? ? ? .body(repository.saveAll(userMono) , User.class); ? ? ? ? }); ? ? }
異常捕獲,用aop的方式:
@Component @Order(-99) public class ExceptionHandler implements WebExceptionHandler { ? ? @Override ? ? public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) { ? ? ? ? ServerHttpResponse response = serverWebExchange.getResponse(); ? ? ? ? response.setStatusCode(HttpStatus.BAD_REQUEST); ? ? ? ? response.getHeaders().setContentType(MediaType.TEXT_PLAIN); ? ? ? ? String errorMsg = toStr(throwable); ? ? ? ? DataBuffer db = response.bufferFactory().wrap(errorMsg.getBytes()); ? ? ? ? return response.writeWith(Mono.just(db)); ? ? } ? ? ? private String toStr(Throwable throwable) { ? ? ? ? //已知異常,自定義異常,這里懶得寫了,就隨便找一個(gè)代替 ? ? ? ? if (throwable instanceof NumberFormatException){ ? ? ? ? ? ? NumberFormatException e = (NumberFormatException) throwable; ? ? ? ? ? ? return e.getMessage(); ? ? ? ? } ? ? ? ? //未知異常 ? ? ? ? else { ? ? ? ? ? ? throwable.printStackTrace(); ? ? ? ? ? ? return throwable.toString(); ? ? ? ? } ? ? } }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot3中Spring?WebFlux?SSE服務(wù)器發(fā)送事件的實(shí)現(xiàn)步驟
- SpringBoot深入分析webmvc和webflux的區(qū)別
- SpringBoot之webflux全面解析
- Springboot WebFlux集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的示例
- 詳解Spring Boot2 Webflux的全局異常處理
- 解決spring-boot2.0.6中webflux無法獲得請(qǐng)求IP的問題
- Spring?Boot?3.4.3?基于?Spring?WebFlux?實(shí)現(xiàn)?SSE?功能(代碼示例)
相關(guān)文章
SpringBoot多數(shù)據(jù)源讀寫分離的自定義配置問題及解決方法
這篇文章主要介紹了SpringBoot多數(shù)據(jù)源讀寫分離的自定義配置,我們可以通過自定義配置數(shù)據(jù)庫配置類來解決這個(gè)問題,方式有很多,不同的業(yè)務(wù)采用的方式也不同,下面我簡單的介紹我們項(xiàng)目的使用的方法2022-06-06基于Properties實(shí)現(xiàn)配置數(shù)據(jù)庫驅(qū)動(dòng)
這篇文章主要介紹了基于Properties實(shí)現(xiàn)配置數(shù)據(jù)庫驅(qū)動(dòng),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05spring boot基于DRUID實(shí)現(xiàn)數(shù)據(jù)源監(jiān)控過程解析
這篇文章主要介紹了spring boot基于DRUID實(shí)現(xiàn)數(shù)據(jù)源監(jiān)控過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12