--- title: 'Spring Boot Webclient and gson' disqus: hackmd --- ###### tags: `SpringBoot` Spring Boot Webclient === [TOC] ## 筆記目的 了解如何使用webclient 套件去打API,簡單來說,你使用postman可以透過get request或是 post request去取得某些資源,而這些資源常常是所謂的**json**格式的資料,我們要如何不使用postman,而使用後端程式去取得url上的**json**資料後,我們要把它存成**javabean** * [stackoverflow](https://stackoverflow.com/questions/48828603/how-to-create-request-with-parameters-with-webflux-webclient/52013826) ## 思路方向 其實分成兩個部份來思考,第一個部分是給定URL後,怎麼把資源給get回來?第二部分則是取回來的資源,型態是甚麼,又需要怎麼把他給變成Javabean? 變成JAVAbean最大的好處就是可以直接`get`還有`set`去把它做取值還有變更值的動作,而且也可以省掉一些使用其他非gson套件的錯誤 非常簡單的說我們做的事情可以歸納如下:某個url上面有json資料,我們用webclient套件拿到,並且把她轉換成String,最後在透過gson套件,把String轉換成JAVAbean。 **pom.xml** ```xml= <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20210307</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.2.2</version> </dependency> ``` ## 設計BEAN 先把JAVABEAN給設計出來,設計的方式要取決於,你的資源的樣子 舉例而言,我的資源長這樣 ```json { "access_token": "ya29.a0ARrdaM8zl28w8Cfke6aYXcp2CjO5NDboDITXSHC8YQukR8_c946QXVgAHukIJV-MUPeZkhRFl_kpF4RaUWp9FZZyG9XkjSTBEUQ4SSETRewRlYKg9zdwd5zYVzH8z2O-rXU4k532TDy-H9im5-zCsUTqzFTxRA", "expires_in": 3599, "scope": "https://www.googleapis.com/auth/drive", "token_type": "Bearer" } ``` 那JAVABean就要長這樣 ```java= package com.example.value.bean; public class GoogleAccessTokenBean { private String access_token; private String expires_in; private String scope; private String token_type; public GoogleAccessTokenBean() { // super(); // TODO Auto-generated constructor stub } public GoogleAccessTokenBean(String access_token, String expires_in, String scope, String token_type) { super(); this.access_token = access_token; this.expires_in = expires_in; this.scope = scope; this.token_type = token_type; } public String getAccess_token() { return access_token; } public void setAccess_token(String access_token) { this.access_token = access_token; } public String getExpires_in() { return expires_in; } public void setExpires_in(String expires_in) { this.expires_in = expires_in; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } public String getToken_type() { return token_type; } public void setToken_type(String token_type) { this.token_type = token_type; } } ``` ## 取得資源 ### Tool Class ```java= package com.example.value; import org.springframework.web.reactive.function.client.WebClient; public class WebclientTool { public static String getJsonFromUrl(String url) { WebClient client = WebClient.create(); String responseSpec = client.post() .uri(url) .retrieve().bodyToMono(String.class).block(); return responseSpec; } } ``` > 要注意的地方在於我使用client.post代表是post request,如果想要換成 ### Main Class ```java= package com.example.value; import org.json.JSONObject; import org.springframework.web.reactive.function.client.WebClient; import com.example.value.bean.GoogleAccessTokenBean; import com.google.gson.Gson; public class GetToken { public static void main(String[] args) { String Accesstokenurl="XXXXXXXXXXXXXXX"; String Accesstoken=WebclientTool.getJsonFromUrl(Accesstokenurl); Gson gson = new Gson(); GoogleAccessTokenBean data = gson.fromJson(Accesstoken, GoogleAccessTokenBean.class); String token=data.getAccess_token(); System.out.println("mytoken from gson"+":"+token); JSONObject object = new JSONObject(Accesstoken); // System.out.println(object.toString()); // System.out.println(object.get("token_type")); String tokenJson = String.valueOf(object.get("access_token")) ; System.out.println("mytoken from JSONObject"+":"+tokenJson); // System.out.println(joke); } } ``` ## 簡單的範例,根本文關係不大 > 但這個範例可以直接run ### Main Class ```java= package com.example.value; import org.springframework.web.reactive.function.client.WebClient; public class GetJoke { public static void main(String[] args) { WebClient client = WebClient.create(); WebClient.ResponseSpec responseSpec = client.get() .uri("https://v2.jokeapi.dev/joke/Any") .retrieve(); String responseBody = responseSpec.bodyToMono(String.class).block(); System.out.println(responseBody); } } ``` ### result ```json= { "error": false, "category": "Dark", "type": "twopart", "setup": "I told my psychiatrist I got suicidal tendencies.", "delivery": "He said from now on I have to pay in advance.", "flags": { "nsfw": false, "religious": false, "political": false, "racist": false, "sexist": false, "explicit": false }, "id": 93, "safe": false, "lang": "en" } ``` ## 複雜的範例 ![](https://i.imgur.com/nqicCEa.png) ![](https://i.imgur.com/BffEZvd.png) ## 遇到的問題 1. 資料被切斷 ![](https://i.imgur.com/XDvskeS.png) 2. [passing URI Parameters (path parameters, and query parameters) in a WebClient Requests.](https://www.amitph.com/spring-webclient-request-parameters/) 3. 接回來之後怎麼轉成物件? 5. set header? 6. logic string to json,json to object? ## 資料太長怎辦 ```java= ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder() .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(16 *1024 * 1024)).build(); WebClient webClient = WebClient.builder().exchangeStrategies(exchangeStrategies).build(); String listCampaignFromAllieUrl="http://ai-ext.allproducts.com/Allie/api/optimizationList?platform=Google&status=ACTIVE"; String responseSpec = webClient.post().uri(listCampaignFromAllieUrl).retrieve().bodyToMono(String.class).block(); System.out.println(responseSpec.length()); System.out.println(responseSpec); ```