如何在Spring WebFlux项目(Netty)的WebFilter中调用反应流上的块?

时间:2019-01-19 14:50:58

标签: spring spring-boot project-reactor

我有一个用例,在传递到控制器端点之前,必须在webfilter的请求拦截器(WebFilter)中的用户保存操作上调用block()。这是因为webfilter需要使用用户自己的更新(页面浏览量统计信息)保存用户,并且控制器端点需要根据请求的查询字符串部分中的内容保存用户自己的更新。 Webfilter用户保存不能在其自己的线程中运行,否则控制器端点用户保存可能会被W​​ebfilter用户保存覆盖。

当前,使用下面给出的代码,浏览器将永远等待响应,日志显示 “开始更新...” 但是“用户已更新”。永远不会被记录。

这是显示webfilter的代码:

package mypackage.conf;


import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;

import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;

import lombok.extern.slf4j.Slf4j;
import mypackage.dao.PageViewRepository;
import mypackage.dao.UserRepository;
import mypackage.domain.PageView;
import mypackage.domain.User;


import mypackage.service.UserService;
import reactor.core.publisher.Mono;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration

@Slf4j
@ComponentScan(basePackages = "mypackage")
@EnableReactiveMongoRepositories(basePackages = "mypackage")
public class WebConfig implements WebFluxConfigurer {

    @Autowired
    @Lazy
    private UserRepository userRepository;

    @Autowired
    @Lazy
    private UserService userService;

    @Autowired
    @Lazy
    private PageViewRepository pageViewRepository;

    @Autowired
    @Lazy
    JwtProvider jwtProvider;

    @Value("${images..base}")
    String baseSytemImagePath;




    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/images/**").addResourceLocations("file:"+baseSytemImagePath+"/");

    }

    @Bean
    public WebFilter filter() {
        return (exchange, chain) -> {
            ServerHttpRequest req = exchange.getRequest();
            String uri = req.getURI().toString();

            String token;
            // get token from http cookie 
            // (code omitted)

            return userRepository.findByToken(token)
                    .map(user -> process(exchange, uri, token, user))

                    // if user not found by token
                    .switchIfEmpty(
                            userRepository.save(User.builder().createdDate(LocalDateTime.now())
                                    .token(jwtProvider.genToken("run23", UUID.randomUUID().toString())).build())
                                    .map(user -> process(exchange, uri, user.getToken(), user)))
                    .then(chain.filter(exchange));

        };
    }

    private User process(ServerWebExchange exchange, String uri, String token, User user) {

        log.info("Start updating...");

        PageView pg = PageView.builder().createdDate(LocalDateTime.now()).URL(uri).build();
        pageViewRepository.save(pg)
                .flatMap(user::addPageView)
                .blockOptional()
                .ifPresent(u -> userRepository.save(u).log("save user pageview").block());

        log.info("User updated.");

        return user;
    }


}

gradle构建文件的相关内容:

buildscript {
    ext {

        springBootVersion = '2.0.1.RELEASE'
    }
    repositories {
        mavenCentral()

    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

dependencies {

    compile('org.springframework.boot:spring-boot-starter-data-mongodb-reactive')
    compile('org.springframework.boot:spring-boot-starter-security')
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')

    compile('org.springframework.boot:spring-boot-starter-webflux')

    compile('org.springframework.security:spring-security-oauth2-client')
    compile('org.springframework.security.oauth:spring-security-oauth2:2.3.4.RELEASE')
    runtime('org.springframework.boot:spring-boot-devtools')
    compileOnly('org.projectlombok:lombok')
    compile "org.springframework.security:spring-security-jwt:1.0.9.RELEASE"
    compile "io.jsonwebtoken:jjwt:0.9.0"

    testCompile('org.springframework.boot:spring-boot-starter-test')

    testCompile('io.projectreactor:reactor-test')

    compile('com.fasterxml.jackson.core:jackson-databind')
}

Spring失去解决这个难题的能力,Spring社区的一些专家可以在这方面提供帮助吗?

还有什么原因导致浏览器在调用块时永远等待响应?

0 个答案:

没有答案