|
|
@@ -0,0 +1,405 @@
|
|
|
+package com.sckw.core.utils;
|
|
|
+
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import okhttp3.*;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.jetbrains.annotations.NotNull;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+
|
|
|
+import javax.net.ssl.SSLContext;
|
|
|
+import javax.net.ssl.SSLSocketFactory;
|
|
|
+import javax.net.ssl.TrustManager;
|
|
|
+import javax.net.ssl.X509TrustManager;
|
|
|
+import java.io.IOException;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.SecureRandom;
|
|
|
+import java.security.cert.X509Certificate;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.concurrent.Semaphore;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author xcq
|
|
|
+ * @date 2023-02-21 10:42:20
|
|
|
+ **/
|
|
|
+@Slf4j
|
|
|
+public class OkHttpUtils {
|
|
|
+ private static volatile OkHttpClient okHttpClient = null;
|
|
|
+ private static volatile Semaphore semaphore = null;
|
|
|
+ private Map<String, String> headerMap;
|
|
|
+ private Map<String, String> paraMap;
|
|
|
+ private Map<String, String> bodyParaMap;
|
|
|
+ //json字符串
|
|
|
+ private String bodyParaString;
|
|
|
+ private String url;
|
|
|
+ private Request.Builder request;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化okHttpClient,并且允许https访问
|
|
|
+ */
|
|
|
+ private OkHttpUtils() {
|
|
|
+ if (okHttpClient == null) {
|
|
|
+ synchronized (OkHttpUtils.class) {
|
|
|
+ if (okHttpClient == null) {
|
|
|
+ TrustManager[] trustManagers = buildTrustManagers();
|
|
|
+ okHttpClient = new OkHttpClient.Builder()
|
|
|
+ .connectTimeout(15, TimeUnit.SECONDS)
|
|
|
+ .writeTimeout(20, TimeUnit.SECONDS)
|
|
|
+ .readTimeout(20, TimeUnit.SECONDS)
|
|
|
+ .sslSocketFactory(createSSLSocketFactory(trustManagers), (X509TrustManager) trustManagers[0])
|
|
|
+ .hostnameVerifier((hostName, session) -> true)
|
|
|
+ .retryOnConnectionFailure(true)
|
|
|
+ .build();
|
|
|
+ addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 用于异步请求时,控制访问线程数,返回结果
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static Semaphore getSemaphoreInstance() {
|
|
|
+ //只能1个线程同时访问
|
|
|
+ synchronized (OkHttpUtils.class) {
|
|
|
+ if (semaphore == null) {
|
|
|
+ semaphore = new Semaphore(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return semaphore;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建OkHttpUtils
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static OkHttpUtils builder() {
|
|
|
+ return new OkHttpUtils();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加url
|
|
|
+ *
|
|
|
+ * @param url
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public OkHttpUtils url(String url) {
|
|
|
+ this.url = url;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加参数
|
|
|
+ *
|
|
|
+ * @param key 参数名
|
|
|
+ * @param value 参数值
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public OkHttpUtils addPara(String key, String value) {
|
|
|
+ if (paraMap == null) {
|
|
|
+ paraMap = new LinkedHashMap<>(16);
|
|
|
+ }
|
|
|
+ paraMap.put(key, value);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加参数
|
|
|
+ *
|
|
|
+ * @param key 参数名
|
|
|
+ * @param value 参数值
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public OkHttpUtils addBodyPara(String key, String value) {
|
|
|
+ if (bodyParaMap == null) {
|
|
|
+ bodyParaMap = new LinkedHashMap<>(16);
|
|
|
+ }
|
|
|
+ bodyParaMap.put(key, value);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public OkHttpUtils addBodyJsonStr(String string) {
|
|
|
+ bodyParaString = string;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加请求头
|
|
|
+ *
|
|
|
+ * @param key 参数名
|
|
|
+ * @param value 参数值
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public OkHttpUtils addHeader(String key, String value) {
|
|
|
+ if (headerMap == null) {
|
|
|
+ headerMap = new LinkedHashMap<>(16);
|
|
|
+ }
|
|
|
+ headerMap.put(key, value);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化get方法
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public OkHttpUtils get() {
|
|
|
+ request = new Request.Builder().get();
|
|
|
+ request.url(buildUrl());
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化post方法
|
|
|
+ */
|
|
|
+ public OkHttpUtils postForm(JSONObject object, byte[] file) {
|
|
|
+ MultipartBody.Builder formBody = new MultipartBody.Builder();
|
|
|
+ formBody.setType(MultipartBody.FORM);
|
|
|
+
|
|
|
+ for (String s : object.keySet()) {
|
|
|
+ formBody.addFormDataPart(s, StringUtils.isBlank(object.getString(s)) ? "" : object.getString(s));
|
|
|
+ }
|
|
|
+ String fileName = UUIDUtils.get32UUID() + ".zip";
|
|
|
+ log.info("文件名:{}", fileName);
|
|
|
+ formBody.addFormDataPart("file", fileName, RequestBody.create(file));
|
|
|
+
|
|
|
+ RequestBody requestBody = formBody.build();
|
|
|
+ // params参数
|
|
|
+ request = new Request.Builder().post(requestBody).url(buildUrl());
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化post方法
|
|
|
+ *
|
|
|
+ * @param isJsonPost true等于json的方式提交数据,类似postman里post方法的raw
|
|
|
+ * false等于普通的表单提交
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public OkHttpUtils post(boolean isJsonPost) {
|
|
|
+ RequestBody requestBody;
|
|
|
+ if (isJsonPost) {
|
|
|
+ String json;
|
|
|
+ if (StringUtils.isNotBlank(bodyParaString)) {
|
|
|
+ json = bodyParaString;
|
|
|
+ } else if (!CollectionUtils.isEmpty(bodyParaMap)) {
|
|
|
+ json = JSONObject.toJSONString(bodyParaMap);
|
|
|
+ } else {
|
|
|
+ json = "{}";
|
|
|
+ }
|
|
|
+ requestBody = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));
|
|
|
+ } else {
|
|
|
+ FormBody.Builder formBody = new FormBody.Builder();
|
|
|
+ if (bodyParaMap != null) {
|
|
|
+ bodyParaMap.forEach(formBody::add);
|
|
|
+ }
|
|
|
+ requestBody = formBody.build();
|
|
|
+ }
|
|
|
+ // params参数
|
|
|
+ request = new Request.Builder().post(requestBody).url(buildUrl());
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String buildUrl() {
|
|
|
+ StringBuilder urlBuilder = new StringBuilder(url);
|
|
|
+ if (paraMap != null) {
|
|
|
+ urlBuilder.append("?");
|
|
|
+ try {
|
|
|
+ for (Map.Entry<String, String> entry : paraMap.entrySet()) {
|
|
|
+ urlBuilder.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8)).
|
|
|
+ append("=").
|
|
|
+ append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8)).
|
|
|
+ append("&");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ urlBuilder.deleteCharAt(urlBuilder.length() - 1);
|
|
|
+ }
|
|
|
+ return urlBuilder.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 文件下载同步请求
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public byte[] fileSync() {
|
|
|
+ setHeader(request);
|
|
|
+ try {
|
|
|
+ Response response = okHttpClient.newCall(request.build()).execute();
|
|
|
+ if (response.isSuccessful()) {
|
|
|
+ assert response.body() != null;
|
|
|
+ return response.body().bytes();
|
|
|
+ }
|
|
|
+ return new byte[0];
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ return new byte[0];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 同步请求
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String sync() {
|
|
|
+ setHeader(request);
|
|
|
+ try {
|
|
|
+ Response response = okHttpClient.newCall(request.build()).execute();
|
|
|
+ assert response.body() != null;
|
|
|
+ return response.body().string();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ return "请求失败:" + e.getMessage();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 异步请求,有返回值
|
|
|
+ */
|
|
|
+ public String async() {
|
|
|
+ StringBuilder buffer = new StringBuilder("");
|
|
|
+ setHeader(request);
|
|
|
+ okHttpClient.newCall(request.build()).enqueue(new Callback() {
|
|
|
+ @Override
|
|
|
+ public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
|
|
|
+ assert response.body() != null;
|
|
|
+ buffer.append(response.body().string());
|
|
|
+ getSemaphoreInstance().release();
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void onFailure(@NotNull Call call, @NotNull IOException e) {
|
|
|
+ buffer.append("请求出错:").append(e.getMessage());
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ try {
|
|
|
+ getSemaphoreInstance().acquire();
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return buffer.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 异步请求,带有接口回调
|
|
|
+ *
|
|
|
+ * @param callBack
|
|
|
+ */
|
|
|
+ public void async(ICallBack callBack) {
|
|
|
+ setHeader(request);
|
|
|
+ okHttpClient.newCall(request.build()).enqueue(new Callback() {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onFailure(@NotNull Call call,@NotNull IOException e) {
|
|
|
+ callBack.onFailure(call, e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onResponse(Call call, Response response) throws IOException {
|
|
|
+ assert response.body() != null;
|
|
|
+ callBack.onSuccessful(call, response.body().string());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 为request添加请求头
|
|
|
+ *
|
|
|
+ * @param request
|
|
|
+ */
|
|
|
+ private void setHeader(Request.Builder request) {
|
|
|
+ if (headerMap != null) {
|
|
|
+ try {
|
|
|
+ for (Map.Entry<String, String> entry : headerMap.entrySet()) {
|
|
|
+ request.addHeader(entry.getKey(), entry.getValue());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成安全套接字工厂,用于https请求的证书跳过
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustAllCerts) {
|
|
|
+ SSLSocketFactory ssfFactory = null;
|
|
|
+ try {
|
|
|
+ SSLContext sc = SSLContext.getInstance("SSL");
|
|
|
+ sc.init(null, trustAllCerts, new SecureRandom());
|
|
|
+ ssfFactory = sc.getSocketFactory();
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return ssfFactory;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static TrustManager[] buildTrustManagers() {
|
|
|
+ return new TrustManager[]{
|
|
|
+ new X509TrustManager() {
|
|
|
+ @Override
|
|
|
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public X509Certificate[] getAcceptedIssuers() {
|
|
|
+ return new X509Certificate[]{};
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 自定义一个接口回调
|
|
|
+ */
|
|
|
+ public interface ICallBack {
|
|
|
+
|
|
|
+ void onSuccessful(Call call, String data);
|
|
|
+
|
|
|
+ void onFailure(Call call, String errorMsg);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 使用示例
|
|
|
+ *
|
|
|
+ * @param args
|
|
|
+ * @author xcq
|
|
|
+ * @date 2023-02-21 10:47:28
|
|
|
+ **/
|
|
|
+ public static void main(String[] args) {
|
|
|
+ String address = "https://file.cloudpnr.com/app-86820a0f-8b13-479b-a466-b261af7290d5%2Fsaturnfile%2F48cf909816b142e5beec68988c1982b1%2F39189ab6-fac3-11ed-9690-0242ac110002.zip?Expires=1685254390&OSSAccessKeyId=LTAI6Yzq9tIYS57h&Signature=oNyqey777CjDk0IH5ZaniwTAdfg%3D";
|
|
|
+ byte[] file = OkHttpUtils.builder().url(address)
|
|
|
+ .get()
|
|
|
+ .fileSync();
|
|
|
+ /*通知中台*/
|
|
|
+ JSONObject tmp = new JSONObject();
|
|
|
+ tmp.put("status", StringUtils.equals("00000000", "00000000") ? "true" : "false");
|
|
|
+ tmp.put("msg", "");
|
|
|
+ log.info("交易确认异步通知中台入参:{}", tmp.toJSONString());
|
|
|
+
|
|
|
+ String sync = OkHttpUtils.builder().url("http://10.10.10.241:9505/notice/huifu/signal_agent_pay/S520267896211968001/00dd5d5dd4682ea3fad88a37ab48223a")
|
|
|
+ .postForm(tmp, file)
|
|
|
+ .sync();
|
|
|
+ log.info("交易确认异步通知中台返回->{}", sync);
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+}
|