提供一个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. 工具类代码
工具类需要创建一个单例的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);
/**
* 最大连接时间
*/
public final static int CONNECTION_TIMEOUT = 5;
/**
* JSON格式
*/
public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
/**
* OkHTTP线程池最大空闲线程数
*/
public final static int MAX_IDLE_CONNECTIONS = 100;
/**
* OkHTTP线程池空闲线程存活时间
*/
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请求,无需转换对象
*
* @param url 链接
* @param headers 请求头
* @return 响应信息
*/
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("执行get请求, url: {} 成功,返回数据: {}", url, result);
return result;
}
} catch (Exception e) {
logger.error("执行get请求,url: {} 失败!", url, e);
}
return null;
}
/**
* Form表单提交
*
* @param url 地址
* @param params form参数
* @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();
//调用成功
if (response.isSuccessful() && response.body() != null) {
return response.body().string();
}
} catch (Exception e) {
logger.error("", e);
}
return null;
}
/**
* 简单post请求
*
* @param url 请求url
* @param headers 请求头
* @param json 请求参数
* @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("执行post请求,url: {}, header: {} ,参数: {} 成功,返回结果: {}", url, headers, json, result);
return result;
}
} catch (Exception e) {
logger.error("执行post请求,url: {},参数: {} 失败!", url, json, e);
}
return null;
}
/**
* 设置请求头
*
* @param builder .
* @param headers 请求头
*/
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请求。
* <pre>
* Type type = new TypeToken<Results<User>>() {}.getType();
* <pre/>
*
* @param url 链接
* @param headers 请求头
* @param json 请求json
* @param type 嵌套泛型
* @return 响应对象, 可进行强转。
*/
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;
}
/**
* 读取流,转换为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读取响应结果
可以通过Response的code来判断请求是否成功,如果服务器返回的有数据,可以通过Response的body得到一个ResponseBody读取。
-
response.body().string()
一次性将响应体的信息全部读取并转换为String格式; -
response.body().bytes()
一次性读取响应体的信息到byte[]数组中。
如果数据超过1MB可能会报内存溢出,所以对于超过1MB的数据,建议采用流的方式去读取,如ResponseBody的byteStream()方法。
附录
- 被调用者代码
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请求
*/
@GetMapping("/test/server")
public String getMsg() {
return "这是OkHttp的请求";
}
/**
* form表单
*/
@PostMapping("/test/form")
public String getFormMsg(User user) {
log.info(JSON.toJSONString(user));
return "这是Form的请求" + JSON.toJSONString(user);
}
/**
* post请求
*/
@PostMapping("/test/user")
public User getUser(@RequestBody User user) {
log.info(JSON.toJSONString(user));
return user;
}
/**
* post请求
*/
@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的数组中
inputStream.read(data);
inputStream.close();
response.setContentType("image/png");
ServletOutputStream outputStream = response.getOutputStream();
//信息从JVM的数组输出到
outputStream.write(data);
outputStream.close();
} catch (FileNotFoundException e) {
log.error("", e);
} catch (IOException e) {
log.error("", e);
}
}
}
- 调用者代码
@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));
}
//带有嵌套泛型的对象
@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, "{}");
}
//异步调用
@GetMapping("/test/sync/img")
public void sendSyncImg() {
String url = "http://localhost:8010/test/img";
OkHttpUtil.downloadImg(url, "{}");
log.info("请求结束");
}
}