SpringCloud中使用webclient(get和post)请求微服务接口数据

 更新时间:2024年10月19日 14:06:27   作者:全栈工程师进阶  
在SpringCloud项目中使用WebClient调用微服务时,涉及配置WebClient、发起get和post请求等操作,如请求头设置、服务地址配置、数据转换处理、异常处理等,避免在循环中使用WebClient请求、路径设置细节以及数据返回处理技巧,本文旨在帮助理解和应用WebClient进行微服务调用

在SpringCloud项目中使用WebClient调用微服务时,涉及配置WebClient、发起get和post请求等操作,如请求头设置、服务地址配置、数据转换处理、异常处理等,避免在循环中使用WebClient请求、路径设置细节以及数据返回处理技巧,本文旨在帮助理解和应用WebClient进行微服务调用。

配置WebClient

首先我们在SpringCloud项目中配置WebClient,如下所示:

@Component
public class WebClientConfig {
    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

然后在方法中引用:

@Resource
private WebClient.Builder webClientBuilder;

调用微服务接口

主要围绕get和post请求来请求微服务接口数据,如下:

1、Get请求

 public Mono<FileShare> getSharedFriends(String fileId, LoginUser loginUser) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            String userJson = mapper.writeValueAsString(loginUser);
            WebClient webClient = webClientBuilder.baseUrl("http://space-service").build();

            return webClient.get()
                    .uri(uriBuilder -> uriBuilder
                            // 注意:path中不能添加http://space-service,应该在上面添加
                            .path("/crud/file/getSharedFriends")
                            .queryParam("fileId", fileId)
                            .build())
                    // 将用户信息传递给下游接口
                    .header(UserContext.USER, userJson)
                    .retrieve()
                    .bodyToMono(new ParameterizedTypeReference<ResultSuccess<Object>>() {})
                    .flatMap(resultSuccess -> {
                        log.info("resultSuccess={}", JSONArray.toJSONString(resultSuccess));
                        if (resultSuccess == null || resultSuccess.getData() == null) {
                            log.error("Received null data from server");
                            return Mono.empty();  // 避免 NullPointerException
                        }
                        log.info("resultSuccess.getData()={}", resultSuccess.getData());

                        ObjectMapper objectMapper = new ObjectMapper(); // Jackson ObjectMapper
                        FileShare fileShare = objectMapper.convertValue(resultSuccess.getData(), FileShare.class);

                        return Mono.just(fileShare);
                    })
                    .onErrorResume(e -> {
                        log.error("Error retrieving FileShare: {}", e.getMessage());
                        return Mono.empty();
                    });
        } catch (Exception ex) {
            log.info("getSharedFriends Exception ={}", ex.getMessage());
            return Mono.empty();
        }
    }

解释一下上面的代码:

  1. 我们在header中添加请求头包含用户信息数据传递给下游接口
  2. webClientBuilder.baseUrl中设置服务地址
  3. 使用bodyToMono转换返回来的数据,当然你可以写自己的类型或者String.class
  4. flatMap处理转换好的数据并返回
  5. 如果出现异常使用onErrorResume来处理
  6. queryParam添加?请求参数

然后我们可以处理接口返回来的数据

Mono<FileShare> fs = spaceWebClient.getSharedFriends(fileId, loginUser);
            return fs.switchIfEmpty(Mono.defer(() -> {
                        // 返回一个空的 FileShare 对象,以保持类型一致
                        FileShare emptyFileShare = new FileShare();  // 或者根据你的需求设置合适的默认值
                        return Mono.just(emptyFileShare);  // 返回类型为 Mono<FileShare>
                    })
            ).flatMap(fileShare -> {
                log.info("fileShare = {}", fileShare);
                List<String> uids = new ArrayList<>();
                List<User> user;
                uids.add(loginUser.getUid());
                if (fileShare == null || fileShare.getFriendIds() == null || fileShare.getFriendIds().isEmpty()) {
                    user = userService.getUserByName(uids, userName, 5);
                    return Mono.just(ResponseEntity.ok(new ResultSuccess<>(user)));
                } else {
                    uids.addAll(fileShare.getFriendIds());
                    user = userService.getUserByName(uids, userName, 5);
                }
                return Mono.just(ResponseEntity.ok(new ResultSuccess<>(user)));
            });

注意:如果webclient方法中返回Mono.empty(),则不会进入flatMap方法中,所以我们在switchIfEmpty方法中默认设置一个值

上面的flatMap处理你返回的接口数据,这样就完成了Get请求示例,下面看看Post请求。

2、Post请求

跟Get一样,代码如下:

public Mono<List<NotifyRemind>> queryNotifyBy(LoginUser loginUser, String senderId, String objId, List<String> recipientIds) {
        try {
            ObjectMapper mapper = new ObjectMapper();

            NotifyRemindRequest  notifyRemindRequest = new NotifyRemindRequest();
            notifyRemindRequest.setSenderId(senderId);
            notifyRemindRequest.setObjectId(objId);
            notifyRemindRequest.setRecipientIds(recipientIds);

            String userJson = mapper.writeValueAsString(loginUser);
            WebClient webClient = webClientBuilder.baseUrl("http://notify-service").build();

            return webClient.post()
                    .uri(uriBuilder -> uriBuilder
                            // 注意:path中不能添加http://space-service,应该在上面添加
                            .path("/crud/remind/queryBy")
                            .build())
                    .bodyValue(notifyRemindRequest)
                    // 将用户信息传递给下游接口
                    .header(UserContext.USER, userJson)
                    .retrieve()
                    .bodyToMono(new ParameterizedTypeReference<ResultInfo<Object>>() {})
                    .flatMap(resultInfo -> {
                        log.info("resultSuccess={}", JSONArray.toJSONString(resultInfo));
                        if (resultInfo == null || resultInfo.getData() == null) {
                            List<NotifyRemind> empty = new ArrayList<>();
                            log.error("Received null data from server");
                            return Mono.just(empty);  // 避免 NullPointerException
                        }
                        ObjectMapper objectMapper = new ObjectMapper(); // Jackson ObjectMapper
                        // 使用 TypeReference 来指定目标类型
                        List<NotifyRemind> notifyReminds = objectMapper.convertValue(
                                //注意:不要使用List.class,因为返回的是List<LinkedHashMap>,改成:new TypeReference<>() {}
                                resultInfo.getData(), new TypeReference<>() {});
                        return Mono.just(notifyReminds);
                    })
                    .onErrorResume(e -> {
                        log.error("Error retrieving FileShare: {}", e.getMessage());
                        return Mono.empty();
                    });
        } catch (Exception ex) {
            log.info("getSharedFriends Exception ={}", ex.getMessage());
            return Mono.empty();
        }
    }

除了bodyValue添加请求参数类,其它的跟Get请求类似,不过有个注意点:

objectMapper.convertValue转换成自己想要的List<NotifyRemind>类型时

请使用:

objectMapper.convertValue(resultInfo.getData(), new TypeReference<>() {})

不要使用:

objectMapper.convertValue(resultInfo.getData(), List.class)

接着我们在Controller层来接收下返回的接口数据:

Mono<List<NotifyRemind>> listMono = notifyWebClient.queryNotifyBy(loginUser, loginUser.getUid(), fileId, fids);

listMono.subscribe(res -> {
    log.info("result:{}", res);
    if (res.isEmpty()) {
        for (String fid : fids) {
            sendNotify(loginUser, file, fid);
        }
    } else {
        // 找出 fids 中不存在于 notifyRemind.id 的值
        List<String> missingIds = fids.stream()
                .filter(fid -> res.stream().noneMatch(recipient -> recipient.getRecipientId().equals(fid)))
                .collect(Collectors.toList());
        for (String fid : missingIds) {
            sendNotify(loginUser, file, fid);
        }
    }
});

注意

1、Mono如果你没使用的话则它不会请求接口,如:

Mono<FileShare> fs = spaceWebClient.getSharedFriends(fileId, loginUser);

这段代码它不会请求接口,只有加上上面的.flatMap才会正常请求
2、不要把WebClient的请求放到循环中,如while和for
3、path是设置路径,服务名需要在webClientBuilder.baseUrl中设置
4、因为我不想返回数据,所以使用.subscribe方法来接收

总结

到此这篇关于SpringCloud中使用webclient(get和post)请求微服务接口数据的文章就介绍到这了,更多相关SpringCloud中用webclient调用微服务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java的NIO管道用法代码分享

    java的NIO管道用法代码分享

    这篇文章主要介绍了java的NIO管道用法代码分享,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • Java中的 VO,BO,DO 对象命名问题小结

    Java中的 VO,BO,DO 对象命名问题小结

    本文讲解VO,BO,DO 的作用以及如何使用,分析了如何消除三者之间重复的代码,同样结合现实生活中领导配秘书来类比讲解,对Java  VO  对象命名相关知识感兴趣的朋友一起看看吧
    2024-01-01
  • java环境变量path和classpath的配置

    java环境变量path和classpath的配置

    这篇文章主要为大家详细介绍了java系统环境变量path和classpath的配置过程,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • java常用工具类之数据库连接类(可以连接多种数据库)

    java常用工具类之数据库连接类(可以连接多种数据库)

    这篇文章主要介绍了java常用工具类之数据库连接类,可以连接多种数据库,代码中包含详细注释,需要的朋友可以参考下
    2014-07-07
  • mybatis如何封装List<String>类型属性

    mybatis如何封装List<String>类型属性

    这篇文章主要介绍了mybatis如何封装List<String>类型属性问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • 关于Java中代码块的执行顺序

    关于Java中代码块的执行顺序

    这篇文章主要介绍了关于Java中代码块的执行顺序,构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化,因为构造函数是可以多个的,运行哪个构造函数就会建立什么样的对象,但无论建立哪个对象,都会先执行相同的构造代码块,需要的朋友可以参考下
    2023-08-08
  • springboot+idea+maven 多模块项目搭建的详细过程(连接数据库进行测试)

    springboot+idea+maven 多模块项目搭建的详细过程(连接数据库进行测试)

    这篇文章主要介绍了springboot+idea+maven 多模块项目搭建的详细过程(连接数据库进行测试),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • Mybatis-plus新版本分页失效PaginationInterceptor过时的问题

    Mybatis-plus新版本分页失效PaginationInterceptor过时的问题

    这篇文章主要介绍了Mybatis-plus新版本分页失效,PaginationInterceptor过时问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • Resty极简restful框架快速接入Spring

    Resty极简restful框架快速接入Spring

    这篇文章主要为大家介绍了Resty极简的restful框架快速接入Spring详细说明,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • 使用opencsv文件读写CSV文件

    使用opencsv文件读写CSV文件

    这篇文章主要为大家详细介绍了用opencsv文件读写CSV文件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05

最新评论