【Java】HttpClientUtils(Apache HttpClient 工具类)

HttpClientUtils

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.Data;
import lombok.SneakyThrows;
import org.apache.http.Header;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.apache.http.util.TextUtils;

import javax.net.ssl.SSLContext;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.StringReader;
import java.lang.reflect.ParameterizedType;
import java.nio.charset.Charset;
import java.util.*;

public class HttpClientUtils {

    private static final int CONNECT_TIMEOUT = 8000;
    private static final int SOCKET_TIMEOUT  = 8000;
    private static final int MAX_TOTAL       = 512;
    private static final int MAX_PER_ROUTE   = 32;

    private static final String CONTENT_TYPE = "Content-Type";
    private static final String USER_AGENT = "User-Agent";
    private static final String DEFAULT_CHARSET = "UTF-8";
    private static final String TEXT$ = "text";
    private static final String JSON$ = "json";
    private static final String XML$ = "xml";
    private static final String EMPTY = "";

    // region HttpRequest part
    private static HttpUriRequest createRequestBase(String url, String method) {
        HttpUriRequest request = null;
        switch (Objects.nonNull(method) ? method.toUpperCase() : EMPTY) {
            case HttpGet.METHOD_NAME:
                request = new HttpGet(url);
                break;
            case HttpPost.METHOD_NAME:
                request = new HttpPost(url);
                break;
            case HttpPut.METHOD_NAME:
                request = new HttpPut(url);
                break;
            case HttpPatch.METHOD_NAME:
                request = new HttpPatch(url);
                break;
            case HttpDelete.METHOD_NAME:
                request = new HttpDelete(url);
                break;
            case HttpHead.METHOD_NAME:
                request = new HttpHead(url);
                break;
            case HttpOptions.METHOD_NAME:
                request = new HttpOptions(url);
                break;
        }
        return request;
    }

    private static void createRequestHeaders(HttpUriRequest request, HttpHeaders requestHead) {
        if (Objects.nonNull(request)) {
            if (Objects.nonNull(requestHead) && !requestHead.isEmpty()) {
                requestHead.forEach((k, v) -> request.setHeader(k, requestHead.getFirst(k)));
            } else {
                request.setHeader(CONTENT_TYPE, "application/json");
            }
            request.setHeader(USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0");
        }
    }

    private static void createRequestBody(HttpUriRequest request, HttpEntity requestBody) {
        if (Objects.nonNull(request) && (request instanceof HttpEntityEnclosingRequestBase)) {
            ((HttpEntityEnclosingRequestBase) request).setEntity(requestBody);
        }
    }
    // endregion HttpRequest

    // region HttpResponse part
    @Data
    public static class HttpStatus {
        int value;
        String reasonPhrase;
    }

    public static class HttpHeaders extends HashMap<String, List<String>> {
        public String getFirst(String headerName) {
            List<String> headerValues = super.get(headerName);
            return headerValues != null ? headerValues.get(0) : null;
        }
        public void add(String headerName, String headerValue) {
            super.computeIfAbsent(headerName, (k) -> new LinkedList<>()).add(headerValue);
        }
        public void addAll(String headerName, List<? extends String> headerValues) {
            super.computeIfAbsent(headerName, (k) -> new LinkedList<>()).addAll(headerValues);
        }
        public void addAll(Map<String, List<String>> values) {
            values.forEach(this::addAll);
        }
        public void set(String headerName, String headerValue) {
            List<String> headerValues = new LinkedList<>();
            headerValues.add(headerValue);
            super.put(headerName, headerValues);
        }
        public void setAll(Map<String, String> values) {
            values.forEach(this::set);
        }
        public Map<String, String> toSingleValueMap() {
            LinkedHashMap<String, String> singleValueMap = new LinkedHashMap<>(super.size());
            super.forEach((key, valueList) -> singleValueMap.put(key, valueList.get(0)));
            return singleValueMap;
        }
        public ContentType getContentType() {
            String value = this.getFirst(CONTENT_TYPE);
            return TextUtils.isBlank(value) ? null : ContentType.parse(value);
        }
    }

    @Data
    public static class ResponseEntity {
        HttpStatus status;
        HttpHeaders headers;
        Object body;

        public boolean hasBody() {
            return null != this.body;
        }
        String getMimeType() {
            if (Objects.nonNull(headers)) {
                ContentType contentType = headers.getContentType();
                if (Objects.nonNull(contentType)) {
                    String mimeType = contentType.getMimeType();
                    if (Objects.nonNull(mimeType)) {
                        return mimeType;
                    }
                }
            }
            return EMPTY;
        }
        Charset getCharset() {
            if (Objects.nonNull(headers)) {
                ContentType contentType = headers.getContentType();
                if (Objects.nonNull(contentType)) {
                    Charset charset = contentType.getCharset();
                    if (Objects.nonNull(charset)) {
                        return charset;
                    }
                }
            }
            return Charset.forName(DEFAULT_CHARSET);
        }
    }

    private static void createResponseHeaders(ResponseEntity response, HeaderIterator iterator) {
        if (Objects.nonNull(response) && Objects.nonNull(iterator)) {
            HttpHeaders headers = new HttpHeaders();
            while (iterator.hasNext()) {
                final Header header = iterator.nextHeader();
                headers.add(header.getName(), header.getValue());
            }
            response.setHeaders(headers);
        }
    }

    private static void createResponseStatus(ResponseEntity response, StatusLine statusLine) {
        if (Objects.nonNull(response) && Objects.nonNull(statusLine)) {
            HttpStatus status = new HttpStatus();
            status.setValue(statusLine.getStatusCode());
            status.setReasonPhrase(statusLine.getReasonPhrase());
            response.setStatus(status);
        }
    }
    // endregion HttpResponse

    // region MessageConverter part
    @SuppressWarnings("unchecked")
    @SneakyThrows
    private static <T> T parseObjectFromXMLString(String xml, ParameterizedType type) {
        if (!TextUtils.isBlank(xml) && Objects.nonNull(type)) {
            Class<?>[] classes = ParameterizedTypeUtils.getClasses(type);
            if (classes.length == 0 || (classes.length == 1 && String.class == classes[0])) {
                return (T) xml;
            }
            JAXBContext context = JAXBContext.newInstance(classes);
            Unmarshaller um = context.createUnmarshaller();
            return (T) um.unmarshal(new StringReader(xml));
        }
        return null;
    }

    private static <T> T parseObjectFromJSONString(String json, ParameterizedType type) {
        if (ParameterizedTypeUtils.hasActualTypeArguments(type)) {
            return JSON.parseObject(json, type);
        } else {
            Class<T> clazz = ParameterizedTypeUtils.getClass(type);
            return JSON.parseObject(json, clazz);
        }
    }

    private static String toJSONString(Object obj) {
        return JSON.toJSONString(obj);
    }
    // endregion MessageConverter

    @SneakyThrows
    private static CloseableHttpClient getCustomHttpClient() {
        RequestConfig reqCfg = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT)
                .setConnectTimeout(CONNECT_TIMEOUT)
                .build();
        SocketConfig sockCfg = SocketConfig.custom()
                .setTcpNoDelay(true)
                .setSoTimeout(SOCKET_TIMEOUT)
                .build();
        SSLContext sslCtx = SSLContexts.custom()
                .loadTrustMaterial(TrustAllStrategy.INSTANCE)
                .build();
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", new SSLConnectionSocketFactory(sslCtx, NoopHostnameVerifier.INSTANCE))
                .build();
        PoolingHttpClientConnectionManager manager
                = new PoolingHttpClientConnectionManager(registry);
        manager.setMaxTotal(MAX_TOTAL);
        manager.setDefaultMaxPerRoute(MAX_PER_ROUTE);
        HttpClientBuilder builder = HttpClients.custom();
        builder.setDefaultRequestConfig(reqCfg);
        builder.setDefaultSocketConfig(sockCfg);
        builder.setConnectionManager(manager);
        builder.setRetryHandler(new DefaultHttpRequestRetryHandler(1, true));
        return builder.build();
    }

    private static ResponseEntity exchange(String url,
                                           String method,
                                           HttpEntity requestBody,
                                           HttpHeaders requestHead) {
        ResponseEntity ret = new ResponseEntity();
        HttpUriRequest request = createRequestBase(url, method);
        if (Objects.nonNull(request)) {
            createRequestHeaders(request, requestHead);
            createRequestBody(request, requestBody);
            try (CloseableHttpClient httpClient = getCustomHttpClient();
                 CloseableHttpResponse response = httpClient.execute(request)) {
                final StatusLine statusLine = response.getStatusLine();
                createResponseStatus(ret, statusLine);
                final HeaderIterator headerIterator = response.headerIterator();
                createResponseHeaders(ret, headerIterator);
                final HttpEntity responseEntity = response.getEntity();
                if (Objects.nonNull(responseEntity)) {
                    ret.setBody(EntityUtils.toByteArray(responseEntity));
                }
            } catch (Throwable ex) {
                throw new RuntimeException(ex);
            }
        }
        return ret;
    }

    @SuppressWarnings("unchecked")
    public static <T> T fetch(String url,
                              String method,
                              HttpEntity body,
                              HttpHeaders headers,
                              ParameterizedType parameterizedType) {
        ResponseEntity responseEntity = exchange(url, method, body, headers);
        if (!responseEntity.hasBody()) {
            return null;
        }
        Class<T> clazz = ParameterizedTypeUtils.getClass(parameterizedType);
        final Object responseEntityBody = responseEntity.getBody();
        if (Objects.equals(clazz, responseEntityBody.getClass())) {
            return (T) responseEntityBody;
        }
        final String mime = responseEntity.getMimeType().toLowerCase();
        boolean isJson = mime.contains(JSON$), isXml = mime.contains(XML$), isText = mime.contains(TEXT$);
        String data;
        if (isJson || isXml || isText) {
            data = new String((byte[]) responseEntityBody, responseEntity.getCharset());
            if (isXml && Objects.nonNull(clazz.getDeclaredAnnotation(XmlRootElement.class))) {
                return parseObjectFromXMLString(data, parameterizedType);
            }
            return parseObjectFromJSONString(data, parameterizedType);
        }
        data = toJSONString(responseEntityBody);
        return parseObjectFromJSONString(data, parameterizedType);
    }

    public static <T> T fetch(String url,
                              String method,
                              HttpEntity body,
                              HttpHeaders headers,
                              TypeReference<T> responseType) {
        ParameterizedType parameterizedType = ParameterizedTypeUtils.make(responseType);
        return fetch(url, method, body, headers, parameterizedType);
    }

    public static <T> T fetch(String url,
                              String method,
                              HttpEntity body,
                              HttpHeaders headers,
                              Class<T> clazz) {
        ParameterizedType parameterizedType = ParameterizedTypeUtils.make(clazz);
        return fetch(url, method, body, headers, parameterizedType);
    }



    /*
    public static void main(String[] args) throws Exception {
        // List<Header> headers = new ArrayList<>();
        // headers.add(new BasicHeader("Content-Type", "multipart/form-data"));
        // MultipartEntityBuilder form = MultipartEntityBuilder.create();
        // form.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        // form.addTextBody("data", "");
        // form.addBinaryBody("file", new File(""));
        // form.addBinaryBody("byte", new ByteArrayInputStream(new byte[0]));
        // HttpEntity body = form.build();
        // fetch("url", "POST", body, headers, JSONObject.class);
//    */

}

ParameterizedTypeUtils

import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.util.ParameterizedTypeImpl;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;

public class ParameterizedTypeUtils {

    public static ParameterizedType make(TypeReference<?> typeReference) {
        return (ParameterizedType) typeReference.getType();
    }

    public static ParameterizedType make(Type rawType) {
        return make(rawType, null, null);
    }

    public static ParameterizedType make(Type rawType, Type[] actualTypeArguments) {
        return make(rawType, actualTypeArguments, null);
    }

    public static ParameterizedType make(Type rawType, Type[] actualTypeArguments, Type ownerType) {
        // sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.make(Class<?>, Type[], Type);
        return new ParameterizedTypeImpl(actualTypeArguments, ownerType, rawType);
    }

    public static Type getRawType(ParameterizedType parameterizedType) {
        return parameterizedType.getRawType();
    }

    public static Type getOwnerType(ParameterizedType parameterizedType) {
        return parameterizedType.getOwnerType();
    }

    public static Type[] getActualTypeArguments(ParameterizedType parameterizedType) {
        Type[] argTypes = parameterizedType.getActualTypeArguments();
        if (Objects.isNull(argTypes)) {
            argTypes = new Type[0];
        }
        return argTypes;
    }

    public static boolean hasRawType(ParameterizedType parameterizedType) {
        return Objects.nonNull(getRawType(parameterizedType));
    }

    public static boolean hasOwnerType(ParameterizedType parameterizedType) {
        return Objects.nonNull(getOwnerType(parameterizedType));
    }

    public static boolean hasActualTypeArguments(ParameterizedType parameterizedType) {
        return getActualTypeArguments(parameterizedType).length > 0;
    }

    @SuppressWarnings("unchecked")
    public static <T> Class<T> getClass(ParameterizedType parameterizedType) {
        return (Class<T>) parameterizedType.getRawType();
    }

    public static Class<?>[] getClasses(ParameterizedType parameterizedType) {
        Type[] typeArgs = getActualTypeArguments(parameterizedType);
        Class<?>[] classes = new Class[typeArgs.length + 1];
        classes[0] = getClass(parameterizedType);
        Type item;
        for (int i = 0, cnt = typeArgs.length; i < cnt; i++) {
            item = typeArgs[i];
            classes[i + 1] = (item instanceof ParameterizedType
                    ? getClass((ParameterizedType) item)
                    : (Class<?>) item);
        }
        return classes;
    }

}
posted @ 2022-01-22 17:02  XKIND  阅读(355)  评论(0编辑  收藏  举报