REQUEST_HEADER_PARAM = new ThreadLocal<>();
/**
* 设置超时时间,注意该超时时间仅仅对下一条请求有效
*
* 设置新连接的默认连接超时。值0表示没有超时,否则在转换为毫秒时,值必须介于1和Integer.MAX_VALUE之间。
* 将TCP套接字连接到目标主机时应用connectTimeout。默认值为10秒。
*
* @param connect 连接超时时间
* @param read 读取超时时间
*/
public static void setTimeout(Integer connect, Integer read) {
if (connect != null) CONNECT_TIMEOUT.set(connect);
if (read != null) READ_TIMEOUT.set(read);
}
/**
* 获取响应流
*
* @param url 请求路径
*/
public static BufferedSource getResponseSource(final String url) throws RequestException {
Request request = new Builder().url(url).build();
try {
Response response = sendRequest(request);
ResponseBody body = response.body();
return body.source();
} catch (IOException e) {
throw new RequestException("请求路径:" + url + "异常!:", e);
}
}
/**
* 下载小文件
*
* @param url 网络路径
* @param filePath 文件保存路径
* @return 下载成功则为true 反之false
*/
public static boolean downloadSmallFile(final String url, final String filePath) throws RequestException {
return downloadSmallFile(url, new File(filePath));
}
/**
* 下载小文件
*
* @param url 网络路径
* @param file 文件对象
* @return 下载成功则为true 反之false
*/
public static boolean downloadSmallFile(final String url, final File file) throws RequestException {
BufferedSink sink = null;
BufferedSource source = null;
try {
source = getResponseSource(url);
sink = Okio.buffer(Okio.sink(FileKit.createFile(file)));
sink.writeAll(source);
sink.flush();
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (sink != null)
try {
sink.close();
} catch (IOException e) {
e.printStackTrace();
}
if (source != null)
try {
source.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
/**
* 请求日志
*
* @param request 请求体
*/
private static void requestLog(Request request) {
if (log.isDebugEnabled()) {
log.debug("请求地址:{}", request.url());
log.debug("请求类型:{}", request.method());
Object requestHeaderParam = REQUEST_HEADER_PARAM.get();
log.debug("请求头部参数:{}", requestHeaderParam == null ? "" : JSON.toJSONString(requestHeaderParam));
Object requestParam = REQUEST_PARAM.get();
if (requestParam != null)
log.debug("请求主体参数:{}", requestParam instanceof String ? requestParam : JSON.toJSONString(requestParam));
}
}
/**
* 发送http请求
*/
private static Response sendRequest(Request request) throws RequestException, IOException {
try {
// 打印日志
requestLog(request);
// 构建请求
Integer connectTimeout = CONNECT_TIMEOUT.get();
Integer readTimeout = READ_TIMEOUT.get();
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(connectTimeout == null ? 10 : connectTimeout, TimeUnit.SECONDS)
.readTimeout(readTimeout == null ? 10 : readTimeout, TimeUnit.SECONDS)
.build();
// 响应
long startTime = System.nanoTime();
Response response = client.newCall(request).execute();
if (log.isDebugEnabled())
log.debug("请求耗时:" + (System.nanoTime() - startTime) / 1000 + " /μs");
// 请求成功
if (response.isSuccessful()) {
return response;
}
throw new RequestException(response.code(), response.message(), response.body().string());
} finally {
CONNECT_TIMEOUT.remove();
READ_TIMEOUT.remove();
REQUEST_PARAM.remove();
REQUEST_HEADER_PARAM.remove();
}
}
/**
* 返回结果封装
*/
private static T packagingResult(Request request, Class resultClazz) throws RequestException {
try {
Response response = sendRequest(request);
String result = response.body().string();
if (log.isDebugEnabled())
log.debug("请求结果:\n {} ", result);
return JSON.parseObject(result, resultClazz);
} catch (IOException e) {
throw new RequestException("发送地址为" + request.url() + "的请求错误", e);
}
}
/**
* 设置多部分post请求参数
*/
private static void setPostParam(Map params, MultipartBody.Builder multipartBodyBuilder) {
if (params != null && params.size() > 0) {
for (String key : params.keySet()) {
multipartBodyBuilder.addFormDataPart(key, params.get(key));
}
}
}
/**
* 设置POST请求表单参数
*/
private static void setPostParam(Map params, FormBody.Builder builder) {
if (params != null && params.size() > 0) {
for (String key : params.keySet()) {
builder.add(key, params.get(key));
}
}
}
/**
* 设置请求头部信息
*/
private static Builder setHeadParam(Builder requestBuilder, Map headParam) {
REQUEST_HEADER_PARAM.set(headParam);
if (headParam != null && headParam.size() > 0) {
for (String key : headParam.keySet()) {
requestBuilder.addHeader(key, headParam.get(key));
}
}
return requestBuilder;
}
/**
* POST请求 自定义表单方式提交
*
* @param url 请求路径
* @param headParam 头部参数
* @param params 请求参数
* @param resultClazz 返回封装对象
* @return 封装结果
* @throws RequestException
*/
public static T sendPOSTNoEncode(String url, Map headParam, Map params, Class resultClazz) throws RequestException {
REQUEST_PARAM.set(params);
Request request = setHeadParam(new Builder().url(url).post(getNoEncodeFormBody(params).build()), headParam).build();
return packagingResult(request, resultClazz);
}
/**
* 获取表单格式请求主体
*/
private static NoEncodeFormBody.Builder getNoEncodeFormBody(Map params) {
NoEncodeFormBody.Builder builder = new NoEncodeFormBody.Builder();
params.forEach(builder::add);
return builder;
}
/**
* 获取表单格式请求主体
*/
private static FormBody.Builder getFormBody(Map params) {
FormBody.Builder builder = new FormBody.Builder();
setPostParam(params, builder);
return builder;
}
/**
* POST请求 表单方式提交
*
* @param url 请求路径
* @param headParam 头部参数
* @param params 请求参数
* @param resultClazz 返回封装对象
* @return 封装结果
* @throws RequestException
*/
public static T sendPOST(String url, Map headParam, Map params, Class resultClazz)
throws RequestException {
REQUEST_PARAM.set(params);
FormBody body = getFormBody(params).build();
return sendPOST(url, headParam, body, resultClazz);
}
/**
* POST请求 表单方式提交
*
* @param url 请求路径
* @param headParam 头部参数
* @param body 自定义请求主体
* @param resultClazz 返回封装对象
* @return 封装结果
* @throws RequestException
*/
private static T sendPOST(String url, Map headParam, RequestBody body, Class resultClazz)
throws RequestException {
Request request = setHeadParam(new Builder().url(url).post(body), headParam).build();
return packagingResult(request, resultClazz);
}
/**
* POST请求 Payload{Json}方式提交,适合复杂数据
*
* @param url 请求路径
* @param headParam 头部参数
* @param params 请求参数
* @param resultClazz 返回封装对象
* @return 封装对象
* @throws RequestException
*/
public static T sendPOSTJson(String url, Map headParam, Map params, Class resultClazz)
throws RequestException {
REQUEST_PARAM.set(params);
return sendPOSTJson(url, headParam, JSON.toJSONString(params), resultClazz);
}
public static T sendPOSTJson(String url, Map headParam, String params, Class resultClazz)
throws RequestException {
REQUEST_PARAM.set(params);
// 构建请求主体参数
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), params);
return sendPOST(url, headParam, body, resultClazz);
}
/**
* 设置get参数
*
* @param url 请求地址
* @param param 请求参数
* @return 参数拼接结果
*/
private static String setGetParam(String url, Map param) {
if (param != null && param.size() > 0) {
StringBuilder builder = new StringBuilder();
for (String key : param.keySet()) {
builder.append(key).append("=").append(param.get(key)).append("&");
}
url = url + "?" + builder.toString().substring(0, builder.length() - 1);
}
return url;
}
/**
* get请求
*
* @param url 请求路径
* @param headParam 头部参数
* @param param 请求参数
* @return 请求结果
* @throws RequestException 请求时出现例外
*/
public static T sendGET(String url, Map headParam, Map param, Class resultClazz)
throws RequestException {
Request request = setHeadParam(new Builder().url(setGetParam(url, param)).get(), headParam).build();
return packagingResult(request, resultClazz);
}
/**
* 上传多张图片及参数
*
* @param reqUrl URL地址
* @param headParam 头部参数
* @param params 额外参数
* @param picKey 上传图片的关键字
* @param files 图片路径
*/
public static T sendPostMultipart(String reqUrl, Map headParam,
Map params, String picKey, List files, Class resultClazz) throws RequestException {
MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
multipartBodyBuilder.setType(MultipartBody.FORM);
setPostParam(params, multipartBodyBuilder);
// 遍历files中所有图片绝对路径到builder,并约定key如“upload”作为后台接受多张图片的key
if (files != null) {
for (File file : files) {
String sux = getMimeType(file.getName());
MediaType mediaType = MediaType.parse(MIME.getMimeType(sux));
multipartBodyBuilder.addFormDataPart(picKey, file.getName(), RequestBody.create(mediaType, file));
}
}
Request request = setHeadParam(new Builder().url(reqUrl).post(multipartBodyBuilder.build()), headParam).build();
return packagingResult(request, resultClazz);
}
/**
* 获取文件类型
*
* @param fileName 文件名称
* @return 文件后缀
*/
private static String getMimeType(String fileName) {
return fileName.substring(fileName.lastIndexOf(".") + 1);
}
}