提供一個(gè)OkHttp的工具類方法谎亩。
1. 引入依賴
<!-- 通信 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.8.1</version>
</dependency>
<!-- 序列化方式-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
2. 工具類代碼
工具類需要?jiǎng)?chuàng)建一個(gè)單例的OkHttp的客戶端。
import com.google.gson.Gson;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Base64;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
public class OkHttpUtil {
public final static Logger logger = LoggerFactory.getLogger(OkHttpUtil.class);
/**
* 最大連接時(shí)間
*/
public final static int CONNECTION_TIMEOUT = 5;
/**
* JSON格式
*/
public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
/**
* OkHTTP線程池最大空閑線程數(shù)
*/
public final static int MAX_IDLE_CONNECTIONS = 100;
/**
* OkHTTP線程池空閑線程存活時(shí)間
*/
public final static long KEEP_ALIVE_DURATION = 30L;
/**
* GSON格式
*/
public static final Gson GSON = new Gson();
public static String BASE64_PREFIX = "data:image/png;base64,";
/**
* client
* 配置重試
*/
private final static OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(MAX_IDLE_CONNECTIONS, KEEP_ALIVE_DURATION, TimeUnit.MINUTES))
.build();
/**
* get請(qǐng)求涧尿,無(wú)需轉(zhuǎn)換對(duì)象
*
* @param url 鏈接
* @param headers 請(qǐng)求頭
* @return 響應(yīng)信息
*/
public static String get(String url, Map<String, String> headers) {
try {
Request.Builder builder = new Request.Builder();
buildHeader(builder, headers);
Request request = builder.url(url).build();
Response response = HTTP_CLIENT.newCall(request).execute();
if (response.isSuccessful() && Objects.nonNull(response.body())) {
String result = response.body().string();
logger.info("執(zhí)行g(shù)et請(qǐng)求, url: {} 成功宽闲,返回?cái)?shù)據(jù): {}", url, result);
return result;
}
} catch (Exception e) {
logger.error("執(zhí)行g(shù)et請(qǐng)求肃廓,url: {} 失敗!", url, e);
}
return null;
}
/**
* Form表單提交
*
* @param url 地址
* @param params form參數(shù)
* @return
*/
public static String post(String url, Map<String, String> params) {
try {
FormBody.Builder builder = new FormBody.Builder();
if (!CollectionUtils.isEmpty(params)) {
params.forEach(builder::add);
}
FormBody body = builder.build();
Request request = new Request.Builder().url(url).post(body).build();
Response response = HTTP_CLIENT.newCall(request).execute();
//調(diào)用成功
if (response.isSuccessful() && response.body() != null) {
return response.body().string();
}
} catch (Exception e) {
logger.error("", e);
}
return null;
}
/**
* 簡(jiǎn)單post請(qǐng)求
*
* @param url 請(qǐng)求url
* @param headers 請(qǐng)求頭
* @param json 請(qǐng)求參數(shù)
* @return
*/
public static String post(String url, Map<String, String> headers, String json) {
try {
RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, json);
Request.Builder builder = new Request.Builder();
buildHeader(builder, headers);
Request request = builder.url(url).post(body).build();
Response response = HTTP_CLIENT.newCall(request).execute();
if (response.isSuccessful() && Objects.nonNull(response.body())) {
String result = response.body().string();
logger.info("執(zhí)行post請(qǐng)求,url: {}, header: {} ,參數(shù): {} 成功挎峦,返回結(jié)果: {}", url, headers, json, result);
return result;
}
} catch (Exception e) {
logger.error("執(zhí)行post請(qǐng)求,url: {},參數(shù): {} 失敗!", url, json, e);
}
return null;
}
/**
* 設(shè)置請(qǐng)求頭
*
* @param builder .
* @param headers 請(qǐng)求頭
*/
private static void buildHeader(Request.Builder builder, Map<String, String> headers) {
if (Objects.nonNull(headers) && headers.size() > 0) {
headers.forEach((k, v) -> {
if (Objects.nonNull(k) && Objects.nonNull(v)) {
builder.addHeader(k, v);
}
});
}
}
/**
* 支持嵌套泛型的post請(qǐng)求搜吧。
* <pre>
* Type type = new TypeToken<Results<User>>() {}.getType();
* <pre/>
*
* @param url 鏈接
* @param headers 請(qǐng)求頭
* @param json 請(qǐng)求json
* @param type 嵌套泛型
* @return 響應(yīng)對(duì)象, 可進(jìn)行強(qiáng)轉(zhuǎn)市俊。
*/
public static <T> T post(String url, Map<String, String> headers, String json, Type type) {
String result = post(url, headers, json);
if (Objects.nonNull(result) && Objects.nonNull(type)) {
return GSON.fromJson(result, type);
}
return null;
}
/**
* 讀取流,轉(zhuǎn)換為Base64
* 返回base64的照片
*/
public static String postImg(String url, Map<String, String> headers, String json) {
RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, json);
Request.Builder builder = new Request.Builder();
buildHeader(builder, headers);
Request request = builder.url(url).post(body).build();
try {
Response response = HTTP_CLIENT.newCall(request).execute();
String contentType = null;
if (response.body() != null && response.body().contentType() != null) {
contentType = response.body().contentType().toString();
}
if ("image/png".equals(contentType)) {
//讀取流
return BASE64_PREFIX + new String(Base64.getEncoder().encode(response.body().bytes()));
}
} catch (IOException e) {
logger.error("", e);
}
return null;
}
/**
* 異步獲取照片地址
*/
public static void downloadImg(String url, String json) {
RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, json);
Request request = new Request.Builder().url(url).post(body).build();
Call call = HTTP_CLIENT.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//打印異常
logger.error("", e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String s = BASE64_PREFIX + new String(Base64.getEncoder().encode(response.body().bytes()));
logger.info(s);
}
});
}
}
3. 注意
3.1 Response讀取響應(yīng)結(jié)果
可以通過(guò)Response的code來(lái)判斷請(qǐng)求是否成功滤奈,如果服務(wù)器返回的有數(shù)據(jù)摆昧,可以通過(guò)Response的body得到一個(gè)ResponseBody讀取。
-
response.body().string()
一次性將響應(yīng)體的信息全部讀取并轉(zhuǎn)換為String格式蜒程; -
response.body().bytes()
一次性讀取響應(yīng)體的信息到byte[]數(shù)組中绅你。
如果數(shù)據(jù)超過(guò)1MB可能會(huì)報(bào)內(nèi)存溢出,所以對(duì)于超過(guò)1MB的數(shù)據(jù)昭躺,建議采用流的方式去讀取忌锯,如ResponseBody的byteStream()方法。
附錄
- 被調(diào)用者代碼
import com.alibaba.fastjson.JSON;
import com.tellme.pojo.Results;
import com.tellme.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@Slf4j
@RestController
public class TestOkHttp {
/**
* get請(qǐng)求
*/
@GetMapping("/test/server")
public String getMsg() {
return "這是OkHttp的請(qǐng)求";
}
/**
* form表單
*/
@PostMapping("/test/form")
public String getFormMsg(User user) {
log.info(JSON.toJSONString(user));
return "這是Form的請(qǐng)求" + JSON.toJSONString(user);
}
/**
* post請(qǐng)求
*/
@PostMapping("/test/user")
public User getUser(@RequestBody User user) {
log.info(JSON.toJSONString(user));
return user;
}
/**
* post請(qǐng)求
*/
@PostMapping("/test/result")
public Results getResult(@RequestBody User user) {
Results<User> results = new Results<>();
results.setCode(200);
results.setStatus("OK");
results.setData(user);
return results;
}
/**
* 返回照片
*/
@PostMapping("/test/img")
public void getResult(HttpServletRequest request,
HttpServletResponse response) {
try {
File file = new File("/Users/yexuerui/Downloads/二維碼池改造.png");
FileInputStream inputStream = new FileInputStream(file);
byte[] data = new byte[(int) file.length()];
//信息從文件輸入到JVM的數(shù)組中
inputStream.read(data);
inputStream.close();
response.setContentType("image/png");
ServletOutputStream outputStream = response.getOutputStream();
//信息從JVM的數(shù)組輸出到
outputStream.write(data);
outputStream.close();
} catch (FileNotFoundException e) {
log.error("", e);
} catch (IOException e) {
log.error("", e);
}
}
}
- 調(diào)用者代碼
@Slf4j
@RestController
public class TestOkHttpController {
@GetMapping("/test/okHttp")
public String sendMsg() {
String url = "http://localhost:8010/test/server";
Map<String, String> header = new HashMap<>();
return OkHttpUtil.get(url, header);
}
@GetMapping("/test/form")
public String sendForm() {
String url = "http://localhost:8010/test/form";
Map<String, String> params = new HashMap<>();
params.put("name", "libai");
params.put("age", "1");
return OkHttpUtil.post(url, params);
}
@GetMapping("/test/user")
public String sendUser() {
String url = "http://localhost:8010/test/user";
User user=new User();
user.setName("平安");
user.setAge(12);
return OkHttpUtil.post(url, null, JSON.toJSONString(user));
}
//帶有嵌套泛型的對(duì)象
@GetMapping("/test/result")
public void sendResult() {
String url = "http://localhost:8010/test/result";
User user=new User();
user.setName("平安");
user.setAge(12);
Results<User> results = OkHttpUtil.post(url, null, JSON.toJSONString(user), new TypeToken<Results<User>>() {
}.getType());
log.info(JSON.toJSONString(results));
}
@GetMapping("/test/img")
public String sendImg() {
String url = "http://localhost:8010/test/img";
return OkHttpUtil.postImg(url, null, "{}");
}
//異步調(diào)用
@GetMapping("/test/sync/img")
public void sendSyncImg() {
String url = "http://localhost:8010/test/img";
OkHttpUtil.downloadImg(url, "{}");
log.info("請(qǐng)求結(jié)束");
}
}