前言
网上的类似工具类已经很多了,自己优化了一些,希望大家多多给到意见
实现
OkHttp3Utils(主类)
说明一下几个特殊类,可以在实际使用过程中按需替换
- SkynetUtils:封装了公司内部日志系统日志记录功能的实现类(记录日志)
- EnumSkynetCategoryPublicUtils(记录日志用)
- EnumSkynetLogModule(记录日志用)
package demo.common.utls;
import com.google.gson.Gson;
import demo.common.enumlibrary.skynet.category.EnumSkynetCategoryPublicUtils;
import demo.common.enumlibrary.skynet.EnumSkynetLogModule;
import demo.model.proxy.ProxyDO;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* OkHttp3Utils
* 通过OKHttp3构建的Http请求方法
*
* @author John Chen
* @since 2018/10/11
*/
public class OkHttp3Utils {
private final static String MODULE = EnumSkynetLogModule.PUBLIC_UTILS.getName();
private final static String CATEGORY = EnumSkynetCategoryPublicUtils.OKHTTP3.getName();
private OkHttpClient client = new OkHttpClient();
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
public static final MediaType URL_ENCODED = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
public static final MediaType FORM_DATA = MediaType.parse("multipart/form-data; charset=utf-8");
public static final MediaType XML = MediaType.parse("text/xml; charset=utf-8");
private Gson gson = new Gson();
private int connectTimeout = 3;
private int requestTimeout = 6;
private int readTimeout = 6;
//region 构造方法
/**
* 构建方法,默认超时时间
*/
public OkHttp3Utils() {
this(0, 0, 0);
}
/**
* 构建方法,自定义读取超时(推荐)
*
* @param readTimeout 读取超时时间
*/
public OkHttp3Utils(int readTimeout) {
this(readTimeout, 0, 0);
}
/**
* 默认方法,自定义写入超时\读取超时(不推荐)
*
* @param readTimeout 读取超时时间
* @param requestTimeout 写入超时时间
*/
public OkHttp3Utils(int readTimeout, int requestTimeout) {
this(readTimeout, requestTimeout, 0);
}
/**
* 默认方法,自定义写入超时\读取超时\连接超时(不推荐)
*
* @param readTimeout 读取超时时间
* @param requestTimeout 写入超时时间
* @param connectTimeout 连接超时时间
*/
public OkHttp3Utils(int readTimeout, int requestTimeout, int connectTimeout) {
this(readTimeout, requestTimeout, connectTimeout, null);
}
/**
* 默认方法,自定义写入超时\读取超时\连接超时(不推荐)
*
* @param readTimeout 读取超时时间
* @param requestTimeout 写入超时时间
* @param connectTimeout 连接超时时间
* @param proxyDO 代理实体
*/
public OkHttp3Utils(int readTimeout, int requestTimeout, int connectTimeout, ProxyDO proxyDO) {
this.requestTimeout = requestTimeout > 0 ? requestTimeout : this.requestTimeout;
this.readTimeout = readTimeout > 0 ? readTimeout : this.readTimeout;
this.connectTimeout = connectTimeout > 0 ? connectTimeout : this.connectTimeout;
OkHttpClient.Builder builder = client.newBuilder().connectTimeout(this.connectTimeout, TimeUnit.SECONDS)
.writeTimeout(this.requestTimeout, TimeUnit.SECONDS).readTimeout(this.readTimeout, TimeUnit.SECONDS);
if (proxyDO != null) {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyDO.getServiceAddress(), Integer.parseInt(proxyDO.getPort())));
builder.proxy(proxy);
if (!StringUtils.isEmpty(proxyDO.getUserName())) {
String userName = proxyDO.getUserName();
String password = proxyDO.getPassword();
Authenticator proxyAuthenticator = (route, response) -> {
String credential = Credentials.basic(userName, password == null ? "" : password);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
};
builder.proxyAuthenticator(proxyAuthenticator);
}
}
client = builder.build();
}
//endregion
//region Post方法集合
/**
* post请求方法.默认使用Json方式通信
*
* @param url url
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String post(@NotNull String url) throws IOException {
return post(url, "", null, null, null);
}
/**
* post请求方法.默认使用Json方式通信
*
* @param url url
* @param requestParam 请求参数,会放在url中
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String post(@NotNull String url, Map<String, Object> requestParam) throws IOException {
return post(url, "", null, requestParam, null);
}
/**
* post请求方法.默认使用Json方式通信
*
* @param url url
* @param jsonBody 请求体
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String post(@NotNull String url, @NotNull String jsonBody) throws IOException {
return post(url, jsonBody, null, null, null);
}
/**
* post请求方法.默认使用Json方式通信
*
* @param url url
* @param jsonBody 请求体
* @param requestParam 请求参数,会放入url中
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String post(@NotNull String url, @NotNull String jsonBody, Map<String, Object> requestParam) throws IOException {
return post(url, jsonBody, null, requestParam, null);
}
/**
* post请求方法
*
* @param url url
* @param body 请求体
* @param mediaType post请求类型。传Null则默认application/json; charset=utf-8
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String post(@NotNull String url, @NotNull String body, MediaType mediaType) throws IOException {
return post(url, body, mediaType, null, null);
}
/**
* post请求方法
*
* @param url url
* @param body 请求体
* @param mediaType post请求类型。传Null则默认application/json; charset=utf-8
* @param requestParam 请求地址参数,可以为null
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String post(@NotNull String url, @NotNull String body, MediaType mediaType, Map<String, Object> requestParam) throws IOException {
return post(url, body, mediaType, requestParam, null);
}
/**
* post请求的底层方法
*
* @param url 请求地址
* @param body 请求体
* @param mediaType post请求类型。传Null则默认application/json; charset=utf-8
* @param requestParam 请求地址参数,可以为null
* @param requestHeader 请求头,可以为null
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String post(@NotNull String url, @NotNull String body, MediaType mediaType, Map<String, Object> requestParam, Map<String, String> requestHeader) throws IOException {
HttpUrl httpUrl = new HttpUrl(url, requestParam);
Response response = execute(httpUrl, requestHeader, body, mediaType);
return responseToString(response, url, requestParam);
}
//endregion
/**
* 用于处理response
*
* @param response 返回实体
* @param url 地址
* @param requestParam 地址参数
* @return 返回Body中的String
*/
private String responseToString(Response response, String url, Map<String, Object> requestParam) throws IOException {
if (!response.isSuccessful()) {
String errorString = "请求失败,响应码:" + response.code()
+ ";uri:" + url
+ ";requestParam:" + (requestParam == null ? "null" : gson.toJson(requestParam))
+ ";错误信息:" + (response.body() != null ? response.body().string() : "null");
SkynetUtils.printWarn(errorString, MODULE, CATEGORY, "post", "", "");
throw new IllegalStateException(errorString);
}
return response.body() == null ? "" : response.body().string();
}
//region get请求方法集
/**
* get请求的底层方法
*
* @param url 请求地址
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String get(@NotNull String url) throws IOException {
return get(url, null, null);
}
/**
* get请求的底层方法
*
* @param url 请求地址
* @param requestParam 请求地址参数,可以为null
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String get(@NotNull String url, Map<String, Object> requestParam) throws IOException {
return get(url, requestParam, null);
}
/**
* get请求的底层方法
*
* @param url 请求地址
* @param requestParam 请求地址参数,可以为null
* @param requestHeader 请求头,可以为null
* @return 返回请求体
* @throws IOException 除了一般异常抛出外,如果返回Code不为200,也会抛出异常
*/
public String get(@NotNull String url, Map<String, Object> requestParam, Map<String, String> requestHeader) throws IOException {
HttpUrl httpUrl = new HttpUrl(url, requestParam);
Response response = execute(httpUrl, requestHeader, null, null);
return responseToString(response, url, requestParam);
}
//endregion
//region 底层请求方法
/**
* 请求底层方法
*
* @param httpUrl URL实体
* @param requestHeader Header信息。无Header信息时传null
* @param body 请求体。当body=null时使用get方法,否则使用post方法
* @param mediaType Post方法的请求方法
* @return 返回实体
* @throws IOException 请求时可能抛出的异常
*/
public Response execute(@NotNull HttpUrl httpUrl, Map<String, String> requestHeader, String body, MediaType mediaType) throws IOException {
URL url;
url = httpUrl.build();
//region 构建RequestBody
Request request;
if (body == null) {
request = new Request.Builder().url(url).build();
} else {
MediaType media = mediaType != null ? mediaType : JSON;
RequestBody requestBody = RequestBody.create(media, body);
request = new Request.Builder().url(url).post(requestBody).build();
}
//endregion
//region 添加Header
if (requestHeader != null && requestHeader.size() > 0) {
for (Map.Entry<String, String> s : requestHeader.entrySet()) {
request = request.newBuilder().addHeader(s.getKey(), s.getValue()).build();
}
}
//endregion
return execute(request);
}
/**
* request
* 底层请求方法
* 过滤了空的返回实体
*
* @param request 请求体
* @return 返回Response
* @throws IOException HTTP请求可能抛出异常
*/
public Response execute(Request request) throws IOException {
Response response = client.newCall(request).execute();
Objects.requireNonNull(response, "response为空, request is :" + request);
return response;
}
/**
* 异步Request方法
*
* @param request 请求体
* @param responseCallback callBack方法
*/
public void enqueue(Request request, Callback responseCallback) {
client.newCall(request).enqueue(responseCallback);
}
//endregion
}
ProxyDO(代理实体)
如果要使用代理,则先构建这个代理实体
package demo.model.proxy;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import javax.validation.constraints.NotBlank;
/**
* ProxyDO
*
* @author 陈伟伟 John Chen [email protected]
* @since 2019/11/15
*/
@Data
@AllArgsConstructor
public class ProxyDO {
/**
* 服务地址(用于代理服务的地址)(必填)
*/
@NotBlank
private String serviceAddress;
/**
* 端口(必填)
*/
@NotBlank
private String port;
/**
* 内网IP(选填,通常用于IP切换等Job中)
*/
private String innerIp;
/**
* 用户名(选填,如有)
*/
private String userName;
/**
* 密码(选填,如有)
*/
private String password;
/**
* 获取连接字符串
* 格式:[serviceAddress]:[port]{:[userName]:[password]}
*
* @return 返回用于代理连接的字符串
*/
public String getProxyContentStr() {
StringBuilder stringBuilder = new StringBuilder(serviceAddress + ":" + port);
if (!StringUtils.isEmpty(userName)) {
stringBuilder.append(":").append(userName);
if (!StringUtils.isEmpty(password)) {
stringBuilder.append(":").append(password);
}
}
return stringBuilder.toString();
}
}