将NodeJS异步代码转换为Spring Project Reactor

时间:2019-01-15 18:49:42

标签: node.js spring spring-boot project-reactor

我有下面的NodeJS代码:

// req and resp are http request, response objects
var uri = req.getURI()
var pageView = new PageView(uri)

var token = req.token
if (token) {
    UserRepository.findByToken(token, function(notFound, user){
        if(notFound) {  // means  user not found by specified token
            var newUser = new User('John Doe')
            user.foo = 'some value'
            processUser(newUser, pageView)

        } else {  // user found by token
            user.foo = 'some value'
            processUser(user, pageView)
        }
    })
} else {  // token does not exist
    token = new Token('some value')
    resp.setToken(token)
    var newUser = new User('John Doe')
    user.foo = 'some value'

    processUser(newUser, pageView)

}



 processUser(user, pageView) {

    PageViewRepositiry.save(pageView, function(error, savedPageView){
        if(error) {
            throw 'error'
        }
        user.pageViews.push(savedPageView) 
        // save the modified savedUser
        UserRepository.save(user , function(error, savedUser){

        })

     })

   }

它使用存储库模式作为数据库层的抽象(与Spring应用程序中的存储库模式相同)。 基本上,它通过传入令牌(从http req对象)找到用户。如果找到用户,则更新用户实体并添加保存的pageView实体并保存修改后的用户。如果没有通过令牌找到用户,则它将创建一个新用户,并使用保存的pageView更新该用户,然后保存该用户。

如何在Spring Project Reactor(Flux)中编写相同的代码?

是否可以在不使用block()的情况下解决此问题?理想情况下,我想要一个不使用block()的解决方案。

1 个答案:

答案 0 :(得分:2)

首先,如果不存在令牌,则有一些逻辑可以生成令牌。例如:

private Mono<String> getToken(String token) {
     return Mono
         .just(token)
         .switchIfEmpty(Mono.just("some token"));
}

在这种情况下,使用switchIfEmpty可能有点过头,但是我认为您生成令牌的过程要复杂一些,否则您可以使用Optional<String>代替(例如token.orElse("some token"))。

此外,我们还有一些逻辑,可以按其令牌查找用户,或者如果给定令牌中没有用户,则创建一个新用户:

private Mono<User> findUserByToken(String token) {
    return userRepository
        .findByToken(token)
        .switchIfEmpty(userRepository.save(new User("John Doe", token)));
}

现在有了这些方法,我们可以创建一个PageView并一路使用这些方法。我开始创建PageView的原因是,这是整个令牌中的第一个“常量”,无论是否找到令牌/用户:

return Mono
    .just(new PageView(uri))
    .flatMap(pageViewRepository::save)
    .flatMap(pageView -> getToken(token)
        .flatMap(this::findUserByToken)
        .doOnNext(user -> user.setFoo("foo"))
        .doOnNext(user -> user.getPageView().add(pageView)))
    .flatMap(userRepository::save)
    .map(User::getToken);

现在,由于您需要将令牌添加到响应中,并且我发现令牌以某种方式属于User对象的一部分(否则UserRepository.findByToken()无效?),它将只需在末尾使用User::getToken来获取令牌以传递给响应,就更容易了。


但是请注意,存储库模式在Spring上可以正常使用,但是仅对MongoDB,Cassandra,Couchbase和Redis提供响应式支持。除此之外,rdbc还对PostgreSQL提供了响应式支持,但我不认为Spring数据对此提供支持。