Преобразование асинхронного кода NodeJS в Spring Project Reactor - PullRequest
0 голосов
/ 15 января 2019

у меня ниже 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 в качестве абстракции над слоем базы данных (аналогично шаблону Repository в приложениях Spring). В основном он находит пользователя по входящему токену (из объекта http req). Если пользователь найден, он обновляет сущность пользователя и добавляет сохраненную сущность pageView и сохраняет измененного пользователя. Если пользователь не найден по токену, он создает нового пользователя, обновляет пользователя с сохраненным pageView, сохраняет пользователя.

Как тот же код будет написан в Spring Project Reactor (Flux)?

Возможно ли решить эту проблему без использования block ()? В идеале я хотел бы решение, которое не использует block ().

1 Ответ

0 голосов
/ 16 января 2019

Прежде всего, у вас есть логика для генерации токена, если токена нет. Например:

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

В этом случае немного излишне использовать switchIfEmpty для этого, но я предполагаю, что ваш процесс генерации токена немного сложнее, в противном случае вы могли бы работать с Optional<String> вместо (например, * 1006). *).

Кроме того, у нас также есть некоторая логика, чтобы либо найти пользователя по его токену, либо создать нового пользователя, если по данному токену нет пользователя:

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. Кроме того, есть и реактивная поддержка PostgreSQL через rdbc , но я не думаю, что в данных Spring есть поддержка.

...