如何在Spring Boot中链接异步反应式WebClient调用

问题描述

当前,我正在探索响应式编程并使用Spring Boot构建简单的RESTful服务。我正在使用Json占位符服务(https://jsonplaceholder.typicode.com/)来获取数据。

以下是我的应用程序中使用的特定端点

在我的Spring Boot应用程序中,我正在尝试构建一个接受userId的终结点,并使用用户详细信息和帖子进行回复。我使用json占位符服务的上述端点(/ users / {userId}和/ users / {userId} / posts})来构造我的Api响应。以下是我的Api的示例响应有效负载

示例响应

{
   "id":1,"name":"Leanne Graham","username":"Bret","email":"[email protected]","address":{
      "street":"Kulas Light","suite":"Apt. 556","city":"Gwenborough","zipcode":"92998-3874","geo":{
         "lat":"-37.3159","lng":"81.1496"
      }
   },"phone":"1-770-736-8031 x56442","website":"hildegard.org","company":{
      "name":"Romaguera-Crona","catchPhrase":"multi-layered client-server neural-net","bs":"harness real-time e-markets"
   },"posts":[
      {
         "userId":1,"id":1,"title":"sunt aut facere repellat provident occaecati excepturi optio reprehenderit","body":"quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto"
      }
   ]
}

问题陈述::在用户服务层中,我试图对JSON占位符服务进行异步WebClient调用,以构建如上所述的汇总响应。首先,我尝试进行呼叫以获取用户信息,然后进行呼叫以获取帖子信息。故意,我想模拟依赖关系(仅在获取用户详细信息调用成功后才进行获取帖子Api调用)。但是,似乎我的webClient链已损坏,我可以看到用户的帖子信息不是响应json的一部分,尽管我的服务正在调用获取帖子的详细信息。

以下是我的服务代码

UserService

@Service
@Slf4j
public class UserService extends BaseJsonPlaceHolderService implements IUserService {

    @Autowired
    private IPostService postService;

    public UserService(@Autowired WebClient.Builder webClientBuilder) {
        super(webClientBuilder);
    }

    /**
     * Fetches user with given id from json place holder service
     *
     * @param userId
     * @return
     */
    @Override
    public Mono<User> fetchById(Integer userId) {
        log.info("Calling json place holder service with User Id : {}",userId);
        Mono<User> userMono = webClientBuilder
                .baseUrl(jsonPlaceHolderApiBaseUrl)
                .build()
                .get()
                .uri(JsonPlaceHolderResources.USERS.getUri() + "/" + userId) // This will be  https://jsonplaceholder.typicode.com/users/{userId}
                .retrieve()
                .onStatus(HttpStatus::is4xxClientError,clientResponse -> {
                    log.error("User with Id {} not found in json place holder service",userId);
                    return Mono.just(new UserNotFoundException("User " + userId + " is not found. Please pass valid user Id. To get all users in the system,use '/users' endpoint"));
                })
                .onStatus(HttpStatus::is5xxServerError,clientResponse -> {
                    log.error("Internal service error received from json place holder service for fetch all users call. Here is the message");
                    return Mono.just(new InternalServiceException("Internal service error occurred while fetching all users from the system"));
                })
                .bodyToMono(User.class);

       return userMono.doOnNext(user -> {
          postService
          .fetchByUserId(userId)
          .subscribe(post -> user.getPosts().add(post));
       });

    }
}

PostService


@Service
@Slf4j
public class PostService extends BaseJsonPlaceHolderService implements IPostService {

    @Autowired
    private ICommentService commentService;

    public PostService(@Autowired WebClient.Builder webClientBuilder) {
        super(webClientBuilder);
    }

    /**
     * Fetches all posts for a given user from json place holder service
     * @param userId
     * @return
     */
    @Override
    public Flux<Post> fetchByUserId(Integer userId) {
        log.info("Calling json placeholder service to fetch posts for UserId : {}",userId);
        Flux<Post> postFlux = webClientBuilder
                .baseUrl(jsonPlaceHolderApiBaseUrl)
                .build()
                .get()
                .uri(JsonPlaceHolderResources.USERS.getUri() // This will be https://jsonplaceholder.typicode.com/users/{userId}/posts
                        + ApplicationConstants.FORWARD_SLASH.getValue()
                        + userId
                        + JsonPlaceHolderResources.POSTS.getUri())
                .retrieve()
                .bodyToFlux(Post.class);

        return postFlux;
    }
}

UserController

@RequestMapping("/users")
public interface IUserController {

    /**
     * Fetches user detail for given Id
     * @param userId
     * @return
     */
    @GetMapping("/{userId}")
    Publisher<User> fetchById(@PathVariable("userId") Integer userId);
}

UserControllerImpl

@RestController
@Slf4j
@requiredArgsConstructor
public class UserController implements IUserController {

    private final IUserService userService;

    /**
     * Fetches user for given Id
     * @param userId
     * @return
     */
    @Override
    public Publisher<User> fetchById(Integer userId) {
        log.debug("Received fetchUser request for Id : {}",userId);
        return userService.fetchById(userId);
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)