
com.github.hugh.http.builder.OkHttps Maven / Gradle / Ivy
package com.github.hugh.http.builder;
import com.github.hugh.constant.StrPool;
import com.github.hugh.http.UrlUtils;
import com.github.hugh.http.constant.MediaTypes;
import com.github.hugh.http.constant.OkHttpCode;
import com.github.hugh.http.exception.ToolboxHttpException;
import com.github.hugh.http.model.FileFrom;
import com.github.hugh.json.gson.GsonUtils;
import com.github.hugh.json.gson.Jsons;
import com.github.hugh.util.EmptyUtils;
import com.github.hugh.util.ListUtils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 封装OkHttp 工具类
*
* @author hugh
* @since 2.5.1
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class OkHttps {
/**
* 默认超时时间,单位:秒
*/
private static final int TIME_OUT = 10;
private String url;// 接口地址
/**
* HTTP 请求的请求体信息。
*/
private Object body;
private long time; // 请求响应时间
/**
* HTTP 请求的请求头信息。
*/
private Map header;
private int connectTimeout; // 连接超时时间,单位:秒
private int readTimeout; // 读取超时时间,单位:秒
private int writeTimeout; // 写入超时时间,单位:秒
private boolean isSendCookies = false; // 是否发送 Cookie 信息
/**
* 用于存储多个文件来源信息的列表,其中每个 FileFrom 对象包括文件的路径、大小、类型等属性。
*/
private List fileFrom;
/**
* 用于进行 HTTP/HTTPS 请求的客户端对象。该对象封装了连接池、超时设置、请求拦截器、响应拦截器等功能,可以根据实际情况进行配置。
*/
private OkHttpClient okHttpClient;
/**
* 用于管理 TCP 连接的连接池对象,用于复用并限制 TCP 连接数量。通过使用连接池,可以在多个请求之间共享连接,避免建立和关闭连接的开销。ConnectionPool 对象包括最大连接数、保持时间等属性,可以根据实际情况进行配置。
*/
private ConnectionPool connectionPool;
/**
* 默认的数据库连接池,最小连接数为 5 个,最大连接数为无限制。
* 在连接闲置时间达到 60 秒后,连接池会将该连接关闭以释放资源。
*/
private static final ConnectionPool defaultConnectionPool = new ConnectionPool(5, 60, TimeUnit.SECONDS);
/**
* 创建一个 OkHttpClient 实例,该实例支持 cookie 操作
*/
public static final OkHttpClient cookieClient = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
// 保存从响应中获取的 Cookie
@Override
public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List list) {
OkHttpCode.COOKIE_STORE.put(httpUrl.host(), list);
}
// 加载发送请求时需要包含的 Cookie
@NotNull
@Override
public List loadForRequest(@NotNull HttpUrl httpUrl) {
List cookies = OkHttpCode.COOKIE_STORE.get(httpUrl.host());
return cookies == null ? new ArrayList<>() : cookies;
}
})
// 设置连接超时时间
.connectTimeout(TIME_OUT, TimeUnit.SECONDS)
// 设置读取超时时间
.readTimeout(TIME_OUT, TimeUnit.SECONDS)
// 构建 OkHttpClient 实例
.build();
/**
* 设置请求的 URL,用于发起 HTTPS 请求。
*
* @param url 请求的目标 URL 地址。
* @return 返回 OkHttps 实例,以支持链式调用。
*/
public OkHttps setUrl(String url) {
this.url = url;
return this;
}
/**
* 设置 HTTP 请求的请求体信息。
*
* @param body HTTP 请求的请求体信息。
* @return 返回当前 OkHttps 实例,以便支持链式调用。
*/
public OkHttps setBody(Object body) {
this.body = body;
return this;
}
/**
* 设置 HTTP 请求的请求头信息。
*
* @param header HTTP 请求的请求头信息。
* @return 返回当前 OkHttps 实例,以便支持链式调用。
*/
public OkHttps setHeader(Map header) {
this.header = header;
return this;
}
/**
* 设置连接超时时间。
*
* @param connectTimeout 连接超时时间,单位为秒。
* @return 返回当前对象,用于链式调用。
*/
public OkHttps setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}
/**
* 设置读取超时时间。
*
* @param readTimeout 读取超时时间,单位为秒。
* @return 返回当前对象,用于链式调用。
*/
public OkHttps setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
return this;
}
/**
* 设置写入超时时间。
*
* @param writeTimeout 写入超时时间,单位为秒。
* @return 返回当前对象,用于链式调用。
*/
public OkHttps setWriteTimeout(int writeTimeout) {
this.writeTimeout = writeTimeout;
return this;
}
/**
* 设置是否发送 cookie 的方法。
*
* @param flag 是否发送 cookie 的标志,true 表示发送,false 表示不发送。
* @return 返回一个 OkHttps 实例以支持方法链接调用。
*/
public OkHttps isSendCookie(boolean flag) {
this.isSendCookies = flag;
return this;
}
/**
* 设置文件来源,使用单个 FileFrom 对象
*
* @param fileFrom 文件来源
* @return 当前 OkHttps 实例
*/
public OkHttps setFileFrom(FileFrom fileFrom) {
this.fileFrom = Collections.singletonList(fileFrom);
return this;
}
/**
* 设置文件来源,使用一个包含多个 FileFrom 对象的列表
*
* @param fileNameList 文件来源列表
* @return 当前 OkHttps 实例
*/
public OkHttps setFileFrom(List fileNameList) {
this.fileFrom = fileNameList;
return this;
}
/**
* 设置 OkHttpClient 对象。
*
* @param okHttpClient OkHttpClient 对象
* @return 返回当前对象,便于链式调用
*/
public OkHttps setOkHttpClient(OkHttpClient okHttpClient) {
this.okHttpClient = okHttpClient;
return this;
}
/**
* 设置连接池对象。
*
* @param connectionPool 连接池对象
* @return 当前 OkHttps 对象
*/
public OkHttps setConnectionPool(ConnectionPool connectionPool) {
this.connectionPool = connectionPool;
return this;
}
/**
* 创建并返回一个新的 OkHttps 对象,设置请求的 URL。
*
* @param url 请求的 URL
* @return 新的 OkHttps 对象,其 URL 属性被设置为指定的 URL
* @since 2.5.8
*/
public static OkHttps url(String url) {
return new OkHttps().setUrl(url);
}
/**
* 发送 GET 请求,并获取 HTTP 响应消息。
*
* @return 返回 OkHttps 实例,以支持链式调用其他方法。
* @throws IOException 如果发送请求失败,则抛出异常。
*/
public OkHttpsResponse doGet() throws IOException {
// 确保URL不为null或空
verifyUrlEmpty();
// 如果提供了查询参数,则将其添加到URL中
url = UrlUtils.urlParam(url, this.body);
// 构建请求对象
final Request.Builder request = new Request.Builder().url(url);
if (this.header != null) {
// 如果提供了请求头,将其添加到请求中
Headers headers = Headers.of(this.header);
request.headers(headers);
}
String result;
if (this.isSendCookies) {
result = send(request.build(), cookieClient);
} else {
initOkHttpClient();
result = send(request.build(), okHttpClient);
}
// 发送请求并返回响应
return new OkHttpsResponse(result);
}
/**
* 创建 OkHttpClient 对象,并在 okHttpClient 为 null 时使用默认的 OkHttpClient。
* 注意:该方法会直接覆盖属性 okHttpClient 的值。
*/
private void initOkHttpClient() {
if (okHttpClient == null) {
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
// 设置连接超时时间,若用户自定义了连接超时,则使用用户定义的,否则使用默认值
okHttpClientBuilder.connectTimeout(connectTimeout > 0 ? connectTimeout : TIME_OUT, TimeUnit.SECONDS);
// 设置读取超时时间,若用户自定义了读取超时,则使用用户定义的,否则使用默认值
okHttpClientBuilder.readTimeout(readTimeout > 0 ? readTimeout : TIME_OUT, TimeUnit.SECONDS);
// 设置写入超时时间,若用户自定义了写入超时,则使用用户定义的,否则使用默认值
okHttpClientBuilder.writeTimeout(writeTimeout > 0 ? writeTimeout : TIME_OUT, TimeUnit.SECONDS);
// 设置连接池,若用户自定义了连接池,则使用用户定义的,否则使用默认连接池
if (connectionPool == null) {
okHttpClientBuilder.connectionPool(defaultConnectionPool);
}
okHttpClient = okHttpClientBuilder.build();
}
}
/**
* 执行带有表单数据的 POST 请求。
*
* @return 服务器返回的响应结果
* @throws IOException 如果发生 I/O 错误
*/
public OkHttpsResponse doPostForm() throws IOException {
verifyUrlEmpty();
final String params = UrlUtils.jsonParse(this.body);
if (this.isSendCookies) {
return doPost(MediaTypes.APPLICATION_FORM_URLENCODED, params, cookieClient);
} else {
initOkHttpClient();
return doPost(MediaTypes.APPLICATION_FORM_URLENCODED, params, okHttpClient);
}
}
/**
* 执行带有 JSON 数据的 POST 请求。
*
* @return 服务器返回的响应结果
* @throws IOException 如果发生 I/O 错误
*/
public OkHttpsResponse doPostJson() throws IOException {
verifyUrlEmpty();
// 创建OkHttpClient实例并设置超时值
if (this.isSendCookies) {
okHttpClient = cookieClient;
} else {
initOkHttpClient();
}
if (this.body == null) {
return doPost(MediaTypes.APPLICATION_JSON_UTF8, StrPool.EMPTY, okHttpClient);
}
if (this.body instanceof String) {
return doPost(MediaTypes.APPLICATION_JSON_UTF8, String.valueOf(this.body), okHttpClient);
}
return doPost(MediaTypes.APPLICATION_JSON_UTF8, GsonUtils.toJson(this.body), okHttpClient);
}
/**
* 发送 HTTP POST 请求的方法。
*
* @param mediaType 发送请求主体内容的媒体类型。
* @param body 发送请求的主体内容。
* @param okHttpClient 用于发送请求的 OkHttpClient 实例。
* @return 返回一个 OkHttpsResponse 对象,包含服务器返回的响应信息。
* @throws IOException 如果请求发送失败,则抛出 IOException 异常。
*/
private OkHttpsResponse doPost(MediaType mediaType, String body, OkHttpClient okHttpClient) throws IOException {
RequestBody requestBody = RequestBody.create(mediaType, body);
final Request.Builder request = new Request.Builder().url(url).post(requestBody);
if (this.header != null) {
Headers headers = Headers.of(this.header);
request.headers(headers);
}
return new OkHttpsResponse(send(request.build(), okHttpClient));
}
/**
* 上传文件的方法
*
* @param 上传参数键类型
* @param 上传参数值类型
* @return OkHttpsResponse 响应结果对象
* @throws IOException 文件上传失败抛出该异常
*/
public OkHttpsResponse uploadFile() throws IOException {
MultipartBody.Builder requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
// 如果请求体不为空,则将其转换为 Map 对象,并遍历 Map 中的每一项,添加到请求体中
if (EmptyUtils.isNotEmpty(this.body)) {
final Map params = new Jsons(this.body).toMap();
for (Map.Entry entry : params.entrySet()) {
requestBody.addFormDataPart(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
}
}
if (ListUtils.isEmpty(this.fileFrom)) {
throw new ToolboxHttpException("file is null");
}
// 遍历文件列表,将每个文件添加到请求体中
for (FileFrom file : this.fileFrom) {
requestBody.addFormDataPart(file.getKey(), file.getName(), setFileParam(file));
}
Request request = new Request.Builder()
.url(url)
.post(requestBody.build())
.build();
if (this.isSendCookies) {
okHttpClient = cookieClient;
} else {
initOkHttpClient();
}
final String result = send(request, okHttpClient);
return new OkHttpsResponse(result);
}
/**
* 设置 HTTP 请求中需要上传的文件参数。
*
* @param file 包含要上传的文件信息的 FileFrom 对象。
* @return 表示要上传的文件的 RequestBody 对象。
* @throws ToolboxHttpException 如果文件键为空或文件路径为空。
*/
private RequestBody setFileParam(FileFrom file) {
if (EmptyUtils.isEmpty(file.getKey())) {
throw new ToolboxHttpException("upload file key is null");
}
File uploadFile;
if (file.getFile() == null) {
isFilePathEmpty(file.getPath());
uploadFile = new File(file.getPath());
} else {
uploadFile = file.getFile();
}
return RequestBody.create(file.getFileMediaType(), uploadFile);
}
/**
* 检查URL是否为空,如果为空,则抛出异常。
*
* @throws ToolboxHttpException 如果URL为空,则抛出ToolboxHttpException异常。
*/
private void verifyUrlEmpty() {
if (EmptyUtils.isEmpty(this.url)) {// 检查 URL 是否为空
throw new ToolboxHttpException("url is null");
}
}
/**
* 检查文件路径是否为空。
*
* @param path 文件路径。
* @throws ToolboxHttpException 如果文件路径为空。
*/
private void isFilePathEmpty(String path) {
if (EmptyUtils.isEmpty(path)) {// 检查 文件 是否为空
throw new ToolboxHttpException("file path is null");
}
}
/**
* 统一发送请求
*
* @param request 请求内容
* @param okHttpClient OkHttpClient
* @return String 返回结果
* @throws IOException IO异常
*/
private static String send(Request request, OkHttpClient okHttpClient) throws IOException {
try (Response response = okHttpClient.newCall(request).execute()) {
ResponseBody body1 = response.body();
if (body1 == null) {
throw new ToolboxHttpException("result params is null ");
}
return body1.string();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy