SpringCloud中使用webclient(get和post)請(qǐng)求微服務(wù)接口數(shù)據(jù)
在SpringCloud項(xiàng)目中使用WebClient調(diào)用微服務(wù)時(shí),涉及配置WebClient、發(fā)起get和post請(qǐng)求等操作,如請(qǐng)求頭設(shè)置、服務(wù)地址配置、數(shù)據(jù)轉(zhuǎn)換處理、異常處理等,避免在循環(huán)中使用WebClient請(qǐng)求、路徑設(shè)置細(xì)節(jié)以及數(shù)據(jù)返回處理技巧,本文旨在幫助理解和應(yīng)用WebClient進(jìn)行微服務(wù)調(diào)用。
配置WebClient
首先我們?cè)赟pringCloud項(xiàng)目中配置WebClient,如下所示:
@Component public class WebClientConfig { @Bean @LoadBalanced public WebClient.Builder webClientBuilder() { return WebClient.builder(); } }
然后在方法中引用:
@Resource private WebClient.Builder webClientBuilder;
調(diào)用微服務(wù)接口
主要圍繞get和post請(qǐng)求來請(qǐng)求微服務(wù)接口數(shù)據(jù),如下:
1、Get請(qǐng)求
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,應(yīng)該在上面添加 .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(); } }
解釋一下上面的代碼:
- 我們?cè)趆eader中添加請(qǐng)求頭包含用戶信息數(shù)據(jù)傳遞給下游接口
- webClientBuilder.baseUrl中設(shè)置服務(wù)地址
- 使用bodyToMono轉(zhuǎn)換返回來的數(shù)據(jù),當(dāng)然你可以寫自己的類型或者
String.class
- flatMap處理轉(zhuǎn)換好的數(shù)據(jù)并返回
- 如果出現(xiàn)異常使用onErrorResume來處理
- queryParam添加?請(qǐng)求參數(shù)
然后我們可以處理接口返回來的數(shù)據(jù)
Mono<FileShare> fs = spaceWebClient.getSharedFriends(fileId, loginUser); return fs.switchIfEmpty(Mono.defer(() -> { // 返回一個(gè)空的 FileShare 對(duì)象,以保持類型一致 FileShare emptyFileShare = new FileShare(); // 或者根據(jù)你的需求設(shè)置合適的默認(rèn)值 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(),則不會(huì)進(jìn)入flatMap方法中,所以我們?cè)趕witchIfEmpty方法中默認(rèn)設(shè)置一個(gè)值
上面的flatMap處理你返回的接口數(shù)據(jù),這樣就完成了Get請(qǐng)求示例,下面看看Post請(qǐng)求。
2、Post請(qǐng)求
跟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,應(yīng)該在上面添加 .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 來指定目標(biāo)類型 List<NotifyRemind> notifyReminds = objectMapper.convertValue( //注意:不要使用List.class,因?yàn)榉祷氐氖荓ist<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添加請(qǐng)求參數(shù)類,其它的跟Get請(qǐng)求類似,不過有個(gè)注意點(diǎn):
objectMapper.convertValue轉(zhuǎn)換成自己想要的List<NotifyRemind>類型時(shí)
請(qǐng)使用:
objectMapper.convertValue(resultInfo.getData(), new TypeReference<>() {})
不要使用:
objectMapper.convertValue(resultInfo.getData(), List.class)
接著我們?cè)贑ontroller層來接收下返回的接口數(shù)據(jù):
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如果你沒使用的話則它不會(huì)請(qǐng)求接口,如:
Mono<FileShare> fs = spaceWebClient.getSharedFriends(fileId, loginUser);
這段代碼它不會(huì)請(qǐng)求接口,只有加上上面的.flatMap才會(huì)正常請(qǐng)求
2、不要把WebClient的請(qǐng)求放到循環(huán)中,如while和for
3、path是設(shè)置路徑,服務(wù)名需要在webClientBuilder.baseUrl
中設(shè)置
4、因?yàn)槲也幌敕祷財(cái)?shù)據(jù),所以使用.subscribe
方法來接收
總結(jié)
到此這篇關(guān)于SpringCloud中使用webclient(get和post)請(qǐng)求微服務(wù)接口數(shù)據(jù)的文章就介紹到這了,更多相關(guān)SpringCloud中用webclient調(diào)用微服務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis新增數(shù)據(jù)并返回主鍵id的兩種方法實(shí)現(xiàn)
本文主要介紹了Mybatis新增數(shù)據(jù)并返回主鍵id的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-02-02Java實(shí)現(xiàn)有限狀態(tài)機(jī)的推薦方案分享
有限狀態(tài)機(jī)又稱有限狀態(tài)自動(dòng)機(jī),簡稱狀態(tài)機(jī),是表示有限個(gè)狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動(dòng)作等行為的數(shù)學(xué)模型,這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)有限狀態(tài)機(jī)的推薦方案,需要的朋友可以參考下2021-11-11java volatile關(guān)鍵字使用方法及注意事項(xiàng)
這篇文章主要介紹了java volatile關(guān)鍵字使用方法及注意事項(xiàng)的相關(guān)資料,當(dāng)一個(gè)變量被聲明為 volatile 后,java 內(nèi)存模型確保所有使用該變量的線程能看到相同的、一致的值。,需要的朋友可以參考下2017-07-07使用Idea或Datagrip導(dǎo)入excel數(shù)據(jù)的方法
這篇文章主要介紹了使用Idea或Datagrip導(dǎo)入excel數(shù)據(jù)的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11解決SecureRandom.getInstanceStrong()引發(fā)的線程阻塞問題
這篇文章主要介紹了解決SecureRandom.getInstanceStrong()引發(fā)的線程阻塞問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12