在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 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>() {}) .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(); } }
解释一下上面的代码:
- 我们在header中添加请求头包含用户信息数据传递给下游接口
- webClientBuilder.baseUrl中设置服务地址
- 使用bodyToMono转换返回来的数据,当然你可以写自己的类型或者
String.class
- flatMap处理转换好的数据并返回
- 如果出现异常使用onErrorResume来处理
- queryParam添加?请求参数
然后我们可以处理接口返回来的数据
Mono fs = spaceWebClient.getSharedFriends(fileId, loginUser); return fs.switchIfEmpty(Mono.defer(() -> { // 返回一个空的 FileShare 对象,以保持类型一致 FileShare emptyFileShare = new FileShare(); // 或者根据你的需求设置合适的默认值 return Mono.just(emptyFileShare); // 返回类型为 Mono }) ).flatMap(fileShare -> { log.info("fileShare = {}", fileShare); List uids = new ArrayList(); List 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> queryNotifyBy(LoginUser loginUser, String senderId, String objId, List 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>() {}) .flatMap(resultInfo -> { log.info("resultSuccess={}", JSONArray.toJSONString(resultInfo)); if (resultInfo == null || resultInfo.getData() == null) { List empty = new ArrayList(); log.error("Received null data from server"); return Mono.just(empty); // 避免 NullPointerException } ObjectMapper objectMapper = new ObjectMapper(); // Jackson ObjectMapper // 使用 TypeReference 来指定目标类型 List notifyReminds = objectMapper.convertValue( //注意:不要使用List.class,因为返回的是List,改成: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类型时
请使用:
objectMapper.convertValue(resultInfo.getData(), new TypeReference() {})
不要使用:
objectMapper.convertValue(resultInfo.getData(), List.class)
接着我们在Controller层来接收下返回的接口数据:
Mono> 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 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 fs = spaceWebClient.getSharedFriends(fileId, loginUser);
这段代码它不会请求接口,只有加上上面的.flatMap才会正常请求
2、不要把WebClient的请求放到循环中,如while和for
3、path是设置路径,服务名需要在webClientBuilder.baseUrl
中设置
4、因为我不想返回数据,所以使用.subscribe
方法来接收
总结
到此这篇关于SpringCloud中使用webclient(get和post)请求微服务接口数据的文章就介绍到这了,更多相关SpringCloud中用webclient调用微服务内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!