How to do sequence of operations and ensure one operation is complete before next one in Spring Reactor web app?

前端 未结 3 1497
半阙折子戏
半阙折子戏 2021-02-05 06:45

I have Spring Boot 2 web app in which I need to identify site visitor by cookie and gather page view stats. So I need to intercept every web request. The code I had to write is

3条回答
  •  离开以前
    2021-02-05 07:08

    Another variant which creates pageview and updates the user in the webfilter in a non-blocking way, before passing a request to the controller:

    @Bean
    public WebFilter filter() {
        return (exchange, chain) -> {
            ServerHttpRequest req = exchange.getRequest();
            String uri = req.getURI().toString();
            log.info("[i] Web Filter: received the request: {}", uri);
    
            var headers = req.getHeaders();
            List tokenList = headers.get("token");
    
            if (tokenList != null && tokenList.get(0) != null) {
                String token = tokenList.get(0);
                Mono foundUser = userRepo
                        .findByToken(token)
                        .doOnNext(user -> log.info("[i] Web Filter: {} has been found", user));
                return updateUserStat(foundUser, exchange, chain, uri);
            } else {
                String token = UUID.randomUUID().toString();
                Mono createdUser = userRepo
                        .save(new User(token))
                        .doOnNext(user -> log.info("[i] Web Filter: a new {} has been created", user));
                return updateUserStat(createdUser, exchange, chain, uri);
            }
        };
    }
    
    private Mono updateUserStat(Mono userMono, ServerWebExchange exchange, WebFilterChain chain, String uri) {
        return userMono
                .doOnNext(user -> exchange.getAttributes().put("_token", user.getToken()))
                .doOnNext(u -> {
                    String token = exchange.getAttribute("_token");
                    log.info("[i] Web Filter: token attribute has been set to '{}'", token);
                })
                .flatMap(user -> pageViewRepo.save(new PageView(uri)).flatMap(user::addPageView).flatMap(userRepo::save))
                .doOnNext(user -> {
                    int numberOfPages = 0;
                    List pageViews = user.getPageViews();
                    if (pageViews != null) {
                        numberOfPages = pageViews.size();
                    }
                    log.info("[i] Web Filter: {} has been updated. Number of pages: {}", user, numberOfPages);
                })
                .then(chain.filter(exchange));
    }
    

    This code produces the following results:

    1) Token is not present: create a new user, create a page view, update the new user, pass a request to controller

    2019-01-20 14:39:10.033 [ctor-http-nio-3] : [i] Web Filter: received the request: http://localhost:8080/users?test=784
    2019-01-20 14:39:10.110 [ctor-http-nio-3] : Inserting Document containing fields: [token, _class] in collection: user
    2019-01-20 14:39:10.206 [ntLoopGroup-2-2] : [i] Web Filter: a new User(id=5c446bee24c86426ac6c0ae5, token=fba944cd-decb-4923-9757-724da5a60061) has been created
    2019-01-20 14:39:10.212 [ntLoopGroup-2-2] : [i] Web Filter: token attribute has been set to 'fba944cd-decb-4923-9757-724da5a60061'
    2019-01-20 14:39:11.227 [     parallel-1] : Inserting Document containing fields: [URL, createdDate, _class] in collection: pageView
    2019-01-20 14:39:11.242 [ntLoopGroup-2-2] : Saving Document containing fields: [_id, token, pageViews, _class]
    2019-01-20 14:39:11.256 [ntLoopGroup-2-2] : [i] Web Filter: User(id=5c446bee24c86426ac6c0ae5, token=fba944cd-decb-4923-9757-724da5a60061) has been updated. Number of pages: 1
    2019-01-20 14:39:11.289 [ntLoopGroup-2-2] : [i] Controller: handling 'get all users' request. Token attribute is 'fba944cd-decb-4923-9757-724da5a60061'
    2019-01-20 14:39:11.369 [ntLoopGroup-2-2] : find using query: { } fields: Document{{}} for class: class io.github.cepr0.demo.User in collection: user
    

    2) Token is present: find an existing user, create a page view, update the user, pass a request to controller

    2019-01-20 14:51:21.983 [ctor-http-nio-3] : [i] Web Filter: received the request: http://localhost:8080/users?test=538
    2019-01-20 14:51:22.074 [ctor-http-nio-3] : Created query Query: { "token" : "b613b810-cc36-4961-ad2e-db44f52cd2dd" }, Fields: { }, Sort: { }
    2019-01-20 14:51:22.092 [ctor-http-nio-3] : find using query: { "token" : "b613b810-cc36-4961-ad2e-db44f52cd2dd" } fields: Document{{}} for class: class User in collection: user
    2019-01-20 14:51:22.102 [ntLoopGroup-2-2] : [i] Web Filter: User(id=5c434c2eb338ac3530cbd56d, token=b613b810-cc36-4961-ad2e-db44f52cd2dd) has been found
    2019-01-20 14:51:22.102 [ntLoopGroup-2-2] : [i] Web Filter: token attribute has been set to 'b613b810-cc36-4961-ad2e-db44f52cd2dd'
    2019-01-20 14:51:23.103 [     parallel-2] : Inserting Document containing fields: [URL, createdDate, _class] in collection: pageView
    2019-01-20 14:51:23.115 [ntLoopGroup-2-2] : Saving Document containing fields: [_id, token, pageViews, _class]
    2019-01-20 14:51:23.117 [ntLoopGroup-2-2] : [i] Web Filter: User(id=5c434c2eb338ac3530cbd56d, token=b613b810-cc36-4961-ad2e-db44f52cd2dd) has been updated. Number of pages: 13
    2019-01-20 14:51:23.118 [ntLoopGroup-2-2] : [i] Controller: handling 'get all users' request. Token attribute is 'b613b810-cc36-4961-ad2e-db44f52cd2dd'
    2019-01-20 14:51:23.119 [ntLoopGroup-2-2] : find using query: { } fields: Document{{}} for class: class User in collection: user
    

    3) Token is present but user is not found: pass a request to controller

    2019-01-20 14:52:41.842 [ctor-http-nio-3] : [i] Web Filter: received the request: http://localhost:8080/users?test=513
    2019-01-20 14:52:41.844 [ctor-http-nio-3] : Created query Query: { "token" : "-b613b810-cc36-4961-ad2e-db44f52cd2dd" }, Fields: { }, Sort: { }
    2019-01-20 14:52:41.845 [ctor-http-nio-3] : find using query: { "token" : "-b613b810-cc36-4961-ad2e-db44f52cd2dd" } fields: Document{{}} for class: class User in collection: user
    2019-01-20 14:52:41.850 [ntLoopGroup-2-2] : [i] Controller: handling 'get all users' request. Token attribute is 'null'
    2019-01-20 14:52:41.850 [ntLoopGroup-2-2] : find using query: { } fields: Document{{}} for class: class User in collection: user
    

    Demo: sb-reactive-filter-demo(branch: update-user-in-web-filter)

提交回复
热议问题