基于httpclient依赖封装一个更适用自己业务场景的工具类

使用依赖

            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.5.13</version>
            </dependency>
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.8.0</version>
            </dependency>

工具类

public class HttpClientUtil {
    private static HttpClientUtil httpClient;
    private final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
    private final PoolingHttpClientConnectionManager cm;
    private final RequestConfig reqConfig;
    private final HttpClientBuilder clientBuilder;
    //设置同时访问的线程
    private final Semaphore semaphore = new Semaphore(300);

    {
        ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();

        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", plainsf)
                .register("https", sslsf)
                .build();

        cm = new PoolingHttpClientConnectionManager(registry);
        cm.setMaxTotal(1000);
        cm.setDefaultMaxPerRoute(1000);
        //连接配置信息
        reqConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(15000)
                .setConnectTimeout(15000)
                .setSocketTimeout(15000)
                .setExpectContinueEnabled(false)
                .build();
        clientBuilder = HttpClients.custom();

        clientBuilder.setDefaultRequestConfig(reqConfig);
        clientBuilder.setConnectionManager(cm);

    }


    /**
     * 执行一个get类型的HTTP请求
     *
     * @param url       需要访问的地址
     * @param headerMap headerMap可以为
     * @return 请求路径响应的内容
     */
    public String getHttpResponseBody(String url, Map<String, String> headerMap) {
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断
        }
        HttpGet request = new HttpGet(url);
        return requestExecute(request, headerMap);
    }

    /**
     * 执行一个get类型的HTTP请求,返回输入流
     *
     * @param url       需要访问的地址
     * @param headerMap headerMap可以为
     * @return 请求路径响应的内容
     */
    public ByteArrayOutputStream getHttpResponseIs(String url, Map<String, String> headerMap) {
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断
        }
        HttpGet request = new HttpGet(url);
        return requestExecuteByte(request, headerMap);
    }

    /**
     * 执行一个post类型的HTTP请求
     *
     * @param url       需要访问的地址
     * @param headerMap headerMap可以为
     * @param paramBody 请求参数体
     * @return 请求路径响应的内容
     */
    public String postHttpResponseBody(String url, Map<String, String> headerMap, Object paramBody) {
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断
        }
        HttpPost request = new HttpPost(url);
        if (paramBody != null) {
            String bodyStr = JSON.toJSONString(paramBody);
            request.setEntity(new StringEntity(bodyStr, ContentType.APPLICATION_JSON));
        }
        return requestExecute(request, headerMap);
    }

    /**
     * 执行一个post类型的HTTP请求
     *
     * @param url       需要访问的地址
     * @param headerMap headerMap可以为
     * @param paramBody 请求参数体
     * @return 请求路径响应的内容
     */
    public String postHttpResponseXmlBody(String url, Map<String, String> headerMap, String paramBody) {
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断
        }
        HttpPost request = new HttpPost(url);
        if (paramBody != null) {
            request.setEntity(new StringEntity(paramBody, ContentType.APPLICATION_XML));
        }
        return requestExecute(request, headerMap);
    }

    /**
     * 执行一个put类型的HTTP请求
     *
     * @param url       需要访问的地址
     * @param headerMap headerMap可以为
     * @param paramBody 请求参数体
     * @return 请求路径响应的内容
     */
    public String putHttpResponseBody(String url, Map<String, String> headerMap, Object paramBody) {
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断
        }
        String bodyStr = JSON.toJSONString(paramBody);
        HttpPut request = new HttpPut(url);
        request.setEntity(new StringEntity(bodyStr, ContentType.APPLICATION_JSON));
        return requestExecute(request, headerMap);
    }

    /**
     * 执行一个post类型的HTTP请求,用于上传文件
     *
     * @param url       请求路径
     * @param fileField 文件字段名字
     * @param bytes     文件
     * @param headerMap 请求头
     * @param paramBody 请求附带参数对象
     * @return 请求路径响应的内容
     */
    public String postFileHttpResponseBody(String url, String fileField, byte[] bytes,
                                           Map<String, String> headerMap, Object paramBody) {
        headerMap.put("Content-Type", null);
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断
        }
        MultipartEntityBuilder builder = MultipartEntityBuilder.create().setCharset(StandardCharsets.UTF_8);
        JSONObject jsonObject = (JSONObject) JSON.toJSON(paramBody);
        if (bytes != null) {
            String filename = jsonObject.getString("filename");
            filename = filename == null ? "" : filename;
            ContentType contentType = ContentType.create("application/octet-stream", "UTF-8");
            builder.addBinaryBody(fileField, bytes, contentType, filename);
        }
        final ContentType contentType = ContentType.create("text/plain", "UTF-8");
        jsonObject.forEach((k, v) -> {
            if (v == null) return;
            StringBody stringBody = new StringBody(v.toString(), contentType);
            builder.addPart(k, stringBody);
        });
        HttpPost request = new HttpPost(url);
        request.setEntity(builder.build());
        return requestExecute(request, headerMap);
    }


    /**
     * 执行一个post类型的HTTP请求格式是application/x-www-form-urlencoded
     *
     * @param url       需要访问的地址
     * @param headerMap headerMap可以为
     * @param params    请求参数
     * @return 请求路径响应的内容
     */
    public String postHttpFormResponseBody(String url, Map<String, String> headerMap, Object params) {
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断
        }
        ArrayList<BasicNameValuePair> basicNameValuePairs = new ArrayList<>();
        if (params instanceof Map) {
            Set<Map.Entry<String, String>> entries = ((Map) params).entrySet();
            for (Map.Entry<String, String> entry : entries) {
                basicNameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        } else {
            ReflectionUtils.doWithFields(params.getClass(), field -> {
                field.setAccessible(true);
                Object val = field.get(params);
                if (val != null) {
                    basicNameValuePairs.add(new BasicNameValuePair(field.getName(), val.toString()));
                }
            });
        }
        UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(basicNameValuePairs, StandardCharsets.UTF_8);
        HttpPost request = new HttpPost(url);
        request.setEntity(urlEncodedFormEntity);
        headerMap.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        return requestExecute(request, headerMap);
    }

    /**
     * 组装get请求的参数到API路径中
     *
     * @param reqParam API的请求参数对象,由{@link ApiBaseReq.BaseBuilder#build()}生成
     * @return 组装后的路径 https://ad.e.kuaishou.com/rest/openapi/v1/comment/list?nick=zym&age=25&pid=6666
     */
    public String createGetRequestUrl(ApiBaseReq reqParam, String platform) {
        String apiUrl = reqParam.getApiUrl();
        JSONObject json = (JSONObject) JSONObject.toJSON(reqParam);
        return this.createGetRequestUrl(json, apiUrl, platform);
    }

    /**
     * 组装get请求的参数到API路径中
     *
     * @param reqJson API的请求参数Json
     * @param apiUrl  暂未拼接的路径例如:https://ad.e.kuaishou.com/rest/openapi/v1/comment/list
     * @return 组装后的路径 https://ad.e.kuaishou.com/rest/openapi/v1/comment/list?nick=zym&age=25&pid=6666
     */
    public String createGetRequestUrl(JSONObject reqJson, String apiUrl, String platform) {
        String params = reqJson.entrySet().stream().filter(x -> x.getValue() != null && !"null".equals(x.getValue()))
                .map(x -> {
                    try {
                        return this.joinParam(x.getKey(), x.getValue(), platform);
                    } catch (UnsupportedEncodingException e) {
                        logger.error("createGetRequestUrl UnsupportedEncodingException:", e);
                        return null;
                    }
                }).collect(Collectors.joining("&"));
        //如果结尾不是?并且包含=,则说明url已经拼接过参数了
        if (!apiUrl.endsWith("?") && apiUrl.contains("=")) return apiUrl + "&" + params;
        return apiUrl.endsWith("?") ? apiUrl + params : apiUrl + "?" + params;
    }

    private String joinParam(Object key, Object val, String platform) throws UnsupportedEncodingException {
        if (val instanceof JSONArray) {
            if ("BL_BL".equalsIgnoreCase(platform)) {
                // 把 '[' 或 ']' 全部替换为空串
                return key + "=" + val.toString().replaceAll("\\[|\\]|\"", "");
            }
            return key + "=" + URLEncoder.encode(val.toString(), "utf-8");
        } else if (val instanceof JSONObject) {
            return key + "=" + URLEncoder.encode(val.toString(), "utf-8");
        } else {
            return key + "=" + val;
        }
    }

    /**
     * 真正开始执行HTTP请求
     *
     * @param request   请求内容
     * @param headerMap 请求头部
     * @return 请求响应的内容
     */
    private String requestExecute(HttpRequestBase request, Map<String, String> headerMap) {
        setHeaders(request, headerMap);//请求头部设置
        CloseableHttpClient httpClient = clientBuilder.build();
        HttpClientContext localContext = HttpClientContext.create();
        CloseableHttpResponse httpResp = null;//执行
        try {
            httpResp = httpClient.execute(request, localContext);
            if (httpResp == null) {
                logger.error("【requestExecute】请求失败 httpResp is null");
                return null;
            }
            int statusCode = httpResp.getStatusLine().getStatusCode();//请求状态码200位成功
            if (httpResp.getStatusLine().getStatusCode() != 200) {
                logger.error("【requestExecute】请求失败 statusCode:{}", statusCode);
                return null;
            }
            if (httpResp.getEntity() == null) return null;
            return getResponseStr(httpResp);
        } catch (Exception e) {
            logger.error("【httpClient】 requestExecute Exception:{}", e.getMessage());
            return null;
        } finally {
            StreamClose.close(httpResp);
            request.releaseConnection();
            clientClose();
        }
    }

    /**
     * 真正开始执行HTTP请求,返回输入流
     *
     * @param request   请求内容
     * @param headerMap 请求头部
     * @return 请求响应的内容
     */
    private ByteArrayOutputStream requestExecuteByte(HttpRequestBase request, Map<String, String> headerMap) {
        setHeaders(request, headerMap);//请求头部设置
        CloseableHttpClient httpClient = clientBuilder.build();
        HttpClientContext localContext = HttpClientContext.create();
        CloseableHttpResponse httpResp = null;//执行
        try {
            httpResp = httpClient.execute(request, localContext);
            if (httpResp == null) {
                logger.error("【requestExecuteByte】请求失败 httpResp is null");
                return null;
            }
            int statusCode = httpResp.getStatusLine().getStatusCode();//请求状态码200位成功
            if (httpResp.getStatusLine().getStatusCode() != 200) {
                logger.error("【requestExecuteByte】请求失败 statusCode:{}", statusCode);
                return null;
            }
            if (httpResp.getEntity() == null) return null;
            ByteArrayOutputStream aos = new ByteArrayOutputStream();
            IOUtils.copy(httpResp.getEntity().getContent(), aos);
            return aos;
        } catch (Exception e) {
            logger.error("【httpClient】 requestExecuteByte Exception:{}", e.getMessage());
            return null;
        } finally {
            StreamClose.close(httpResp);
            request.releaseConnection();
            clientClose();
        }
    }


    /**
     * 设置请求头
     *
     * @param httpReq   请求对象
     * @param headerMap 配置的请求头部
     */
    private void setHeaders(HttpRequestBase httpReq, Map<String, String> headerMap) {
        httpReq.setConfig(reqConfig);
        if (headerMap == null) return;
        if (!headerMap.containsKey("Content-Type")) {
            httpReq.setHeader("Content-Type", "application/json;charset=UTF-8");
        }
        headerMap.forEach((k, v) -> {
            if (v == null || k == null) return;
            httpReq.setHeader(k, v);
        });
    }

    private void clientClose() {
        cm.closeExpiredConnections();// 关闭过期的链接
        cm.closeIdleConnections(30, TimeUnit.SECONDS);  // 选择关闭 空闲30秒的链接
        semaphore.release();//释放令牌
    }

    /**
     * 获取响应的字符串
     *
     * @param httpResp 请求响应的对象
     * @return 请求URL响应的字符内容
     */
    private String getResponseStr(CloseableHttpResponse httpResp) {
        InputStream is = null;
        try {
            is = httpResp.getEntity().getContent();
            String charsetName = getCharsetName(httpResp);
            return IOUtils.toString(is, charsetName);
        } catch (IOException e) {
            logger.error("getResponseStr IOException:{}", e.getMessage());
        } finally {
            StreamClose.close(is);
        }
        return null;
    }

    /**
     * 获取响应中的字符格式
     *
     * @param httpResp 请求响应的对象
     * @return 字符编码
     */
    private String getCharsetName(CloseableHttpResponse httpResp) {
        String value = httpResp.getEntity().getContentType().getValue().trim();
        String[] contentTypes = value.split(";");
        String charsetName = StandardCharsets.UTF_8.displayName();//编码格式
        for (String type : contentTypes) {
            if (!type.trim().startsWith("charset")) continue;
            String[] split = type.split("=");
            return split[1];
        }
        return charsetName;
    }

    /**
     * 实例化方法
     */
    public static HttpClientUtil getInstance() {
        if (httpClient != null) return httpClient;
        synchronized (HttpClientUtil.class) {
            if (httpClient != null) return httpClient;
            httpClient = new HttpClientUtil();
        }
        return httpClient;
    }

    private HttpClientUtil() {
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Acmen-zym

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值