---
# System prepended metadata

title: Spring Boot Webclient and gson
tags: [SpringBoot]

---

---
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);
```








