将 NodeJS 异步代码转换为 Spring Project Reactor
Convert NodeJS asynchronous code to Spring 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){
})
})
}
它使用 Repository 模式作为数据库层的抽象(与 Spring 应用程序中的 Repository 模式相同)。
基本上它通过传入令牌(来自 http req 对象)找到用户。如果找到用户,则更新用户实体并添加保存的 pageView 实体并保存修改后的用户。如果未通过令牌找到用户,则它会创建一个新用户,使用保存的 pageView 更新用户,保存用户。
如何在 Spring Project Reactor (Flux) 中编写相同的代码?
不使用block()是否可以解决这个问题?理想情况下,我想要一个不使用 block() 的解决方案。
首先,如果令牌不存在,您有一些生成令牌的逻辑。例如:
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
的原因是因为这是整个令牌中的第一个 "constant",无论是否找到 token/user:
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 数据不支持该功能。
我有以下 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){
})
})
}
它使用 Repository 模式作为数据库层的抽象(与 Spring 应用程序中的 Repository 模式相同)。 基本上它通过传入令牌(来自 http req 对象)找到用户。如果找到用户,则更新用户实体并添加保存的 pageView 实体并保存修改后的用户。如果未通过令牌找到用户,则它会创建一个新用户,使用保存的 pageView 更新用户,保存用户。
如何在 Spring Project Reactor (Flux) 中编写相同的代码?
不使用block()是否可以解决这个问题?理想情况下,我想要一个不使用 block() 的解决方案。
首先,如果令牌不存在,您有一些生成令牌的逻辑。例如:
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
的原因是因为这是整个令牌中的第一个 "constant",无论是否找到 token/user:
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 数据不支持该功能。