一个http请求工具类的接口化(多种实现)

针对上一篇文章的接口设计,提供了三种实现URLConnection、ApacheHttpClient、OkHttp3。

现给出三种实现的继承树。

HTTPURLConnection

ApacheHttp

OkHttp3

首先每种实现都需要实现模板方法HttpTemplate。

URLConnection

package cn.zytx.common.http.base;

import cn.zytx.common.http.Header;
import cn.zytx.common.http.HttpConstants;
import cn.zytx.common.http.HttpStatus;
import cn.zytx.common.http.Method;
import cn.zytx.common.http.base.ssl.DefaultTrustManager;
import cn.zytx.common.http.base.ssl.SSLSocketFactoryBuilder;
import cn.zytx.common.http.base.ssl.TrustAnyHostnameVerifier;
import cn.zytx.common.http.smart.Request;
import cn.zytx.common.http.smart.SSLRequest;
import cn.zytx.common.utils.ArrayListMultimap;
import cn.zytx.common.utils.IoUtil;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.util.HashMap;
import java.util.Set;

/**
 * 使用URLConnection实现的Http公共父类
 * @author 熊诗言2018/6/6
 */
public abstract class AbstractNativeHttp implements HttpTemplate<HttpURLConnection> {
    @Override
    public <R> R template(Request request, Method method, ContentCallback<HttpURLConnection> contentCallback , ResultCallback<R> resultCallback) throws IOException {
        HttpURLConnection connect = null;
        InputStream inputStream = null;
        try {
            //1.获取连接
            connect = (HttpURLConnection)new java.net.URL(request.getUrl()).openConnection();

            //2.处理header
            setConnectProperty(connect, method, request.getContentType(), request.getHeaders(),request.getConnectionTimeout(),request.getReadTimeout());


            ssl处理///
            if(connect instanceof HttpsURLConnection){
                //默认设置这些
                HttpsURLConnection con = (HttpsURLConnection)connect;
                initSSL(con , getDefaultHostnameVerifier() , getDefaultSSLSocketFactory());
                if(request instanceof SSLRequest){
                    //客户给了就用给客户的
                    SSLRequest sslRequest = (SSLRequest) request;
                    initSSL(con , sslRequest.getHostnameVerifier(), sslRequest.getSslSocketFactory());
                }
            }
            ssl处理///

            //3.留给子类复写的机会:给connection设置更多参数
            doWithConnection(connect);

            //5.写入内容,只对post有效
            if(contentCallback != null){
                contentCallback.doWriteWith(connect);
            }

            //4.连接
            connect.connect();

            //6.获取返回值
            int statusCode = connect.getResponseCode();

            inputStream = getStreamFrom(connect , statusCode);

            return resultCallback.convert(statusCode , inputStream, request.getResultCharset(), request.isIncludeHeaders() ? connect.getHeaderFields() : new HashMap<>(0));
            ///返回Response
            //return Response.with(statusCode , inputStream , request.getResultCharset() , request.isIncludeHeaders() ? connect.getHeaderFields() : new HashMap<>(0));
        } catch (IOException e) {
            throw e;
        } catch (Exception e){
            throw new RuntimeException(e);
        } finally {
            //关闭顺序不能改变,否则服务端可能出现这个异常  严重: java.io.IOException: 远程主机强迫关闭了一个现有的连接
            //1 . 关闭连接
            disconnectQuietly(connect);
            //2 . 关闭流
            IoUtil.close(inputStream);
        }
    }


    @Override
    public <R> R template(String url, Method method, String contentType, ContentCallback<HttpURLConnection> contentCallback, ArrayListMultimap<String, String> headers, int connectTimeout, int readTimeout, String resultCharset , boolean includeHeaders , ResultCallback<R> resultCallback) throws IOException {
        //默认的https校验
        // 后面会处理的,这里就不需要了 initDefaultSSL(sslVer);

        HttpURLConnection connect = null;
        InputStream inputStream = null;
        try {
            //1.获取连接
            connect = (HttpURLConnection)new java.net.URL(url).openConnection();

            //2.处理header
            setConnectProperty(connect, method, contentType, headers,connectTimeout,readTimeout);

            ssl处理///
            if(connect instanceof HttpsURLConnection){
                //默认设置这些
                HttpsURLConnection con = (HttpsURLConnection)connect;
                initSSL(con , getDefaultHostnameVerifier() , getDefaultSSLSocketFactory());
            }
            ssl处理///

            //3.留给子类复写的机会:给connection设置更多参数
            doWithConnection(connect);

            //5.写入内容,只对post有效
            if(contentCallback != null){
                contentCallback.doWriteWith(connect);
            }

            //4.连接
            connect.connect();

            //6.获取返回值
            int statusCode = connect.getResponseCode();
            ///保留起非200抛异常的方式
//            if( HttpStatus.HTTP_OK == statusCode){
//                //6.1获取body
//                /*InputStream is = connect.getInputStream();
//                byte[] result = IoUtil.stream2Bytes(is);
//                is.close();
//
//                String s = new String(result, resultCharset);*/
//
//                //6.2获取header
//
//                inputStream = connect.getInputStream();
//
//                return resultCallback.convert(inputStream, resultCharset, includeHeaders ? connect.getHeaderFields() : new HashMap<>(0));
//
//            } else{
//                String err = errMessage(connect);
//                throw new HttpException(statusCode,err,connect.getHeaderFields());
//            }

            inputStream = getStreamFrom(connect , statusCode);

            return resultCallback.convert(statusCode , inputStream, resultCharset, includeHeaders ? connect.getHeaderFields() : new HashMap<>(0));
        } catch (IOException e) {
            throw e;
        } catch (Exception e){
            throw new RuntimeException(e);
        } finally {
            //关闭顺序不能改变,否则服务端可能出现这个异常  严重: java.io.IOException: 远程主机强迫关闭了一个现有的连接
            //1 . 关闭连接
            disconnectQuietly(connect);
            //2 . 关闭流
            IoUtil.close(inputStream);
        }
    }

    private InputStream getStreamFrom(HttpURLConnection connect , int statusCode) throws IOException{
        InputStream inputStream;
        if(HttpStatus.HTTP_OK == statusCode){
            inputStream = connect.getInputStream();
        }else {
            inputStream = connect.getErrorStream();
        }
        if(null == inputStream){
            inputStream = new ByteArrayInputStream(new byte[]{});
        }
        return inputStream;
    }
    protected HostnameVerifier getDefaultHostnameVerifier(){
        return new TrustAnyHostnameVerifier();
    }
    protected SSLSocketFactory getDefaultSSLSocketFactory(){
        return SSLSocketFactoryBuilder.create().build();
    }

    /**子类复写需要首先调用此方法,保证http的功能*/
    protected void doWithConnection(HttpURLConnection connect) throws Exception{
    }

    /**
     * @see SSLSocketFactoryBuilder#build()
     * @see SSLSocketFactoryBuilder#build(String, String)
     */
    protected void initSSL(HttpsURLConnection con , HostnameVerifier hostnameVerifier , SSLSocketFactory sslSocketFactory) {
        // 验证域
        if(null != hostnameVerifier){
            con.setHostnameVerifier(hostnameVerifier);
        }
        if(null != sslSocketFactory){
            con.setSSLSocketFactory(sslSocketFactory);
        }
    }

    protected void setConnectProperty(HttpURLConnection connect, Method method, String contentType, ArrayListMultimap<String,String> headers, int connectTimeout, int readTimeout) throws ProtocolException {
        connect.setRequestMethod(method.name());
        connect.setDoOutput(true);
        connect.setUseCaches(false);
        if(null != headers) {
            Set<String> keySet = headers.keySet();
            keySet.forEach((k)->headers.get(k).forEach((v)->connect.addRequestProperty(k,v)));
        }
        if(null != contentType){
            connect.setRequestProperty(Header.CONTENT_TYPE.toString(), contentType);
        }
        connect.setConnectTimeout(connectTimeout);
        connect.setReadTimeout(readTimeout);
    }
    protected void writeContent(HttpURLConnection connect, String data, String bodyCharset) throws IOException {
        if (null == data || null == bodyCharset) {
            return;
        }
        OutputStream outputStream = connect.getOutputStream();
        outputStream.write(data.getBytes(bodyCharset));
        outputStream.close();
        /* PrintWriter out = new PrintWriter(connect.getOutputStream());
        if (null != data) {
            out.print(data);
            out.flush();
        }
        out.close();*/
    }

    /**
     * 获取输出流中的错误信息,针对HttpURLConnection
     * @param connect HttpURLConnection
     * @return 错误信息
     * @see HttpURLConnection
     * @throws IOException IO异常
     */
    protected String errMessage(HttpURLConnection connect) throws IOException {
        //如果服务器返回的HTTP状态不是HTTP_OK,则表示发生了错误,此时可以通过如下方法了解错误原因。
        // 通过getErrorStream了解错误的详情
        InputStream is = connect.getErrorStream();
        if(null==is){return "";}
        InputStreamReader isr = new InputStreamReader(is, HttpConstants.DEFAULT_CHARSET);
        BufferedReader in = new BufferedReader(isr);
        String inputLine;
        StringWriter bw = new StringWriter();
        while ((inputLine = in.readLine()) != null)
        {
            bw.write(inputLine);
            bw.write("\n");
        }
        bw.close();
        in.close();

        //disconnectQuietly(connect);

        return bw.getBuffer().toString();
    }

    public static void disconnectQuietly(HttpURLConnection connect) {
        if(null != connect){
            try {
                connect.disconnect();
            } catch (Exception e) {}
        }
    }

    protected void initDefaultSSL(String sslVer) {
        try {
            TrustManager[] tmCerts = new TrustManager[1];
            tmCerts[0] = new DefaultTrustManager();
            SSLContext sslContext = SSLContext.getInstance(sslVer);
            sslContext.init(null, tmCerts, null);
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

            HostnameVerifier hostnameVerifier = new TrustAnyHostnameVerifier();
            HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
        } catch (Exception e) {
        }
    }
}

ApcheHttpClient:

 

package cn.zytx.common.http.base;

import cn.zytx.common.http.Method;
import cn.zytx.common.http.ParamUtil;
import cn.zytx.common.http.base.ssl.SSLSocketFactoryBuilder;
import cn.zytx.common.http.base.ssl.TrustAnyHostnameVerifier;
import cn.zytx.common.http.smart.Request;
import cn.zytx.common.http.smart.SSLRequest;
import cn.zytx.common.utils.ArrayListMultimap;
import cn.zytx.common.utils.IoUtil;
import org.apache.http.*;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
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.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.ConnectException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 使用Apache SmartHttpClient 实现的Http请求类
 * @author 熊诗言2018/6/6
 */
public abstract class AbstractApacheHttp implements HttpTemplate<HttpEntityEnclosingRequest> {
    protected int _maxRetryTimes = 3;

    @Override
    public <R> R template(Request request, Method method , ContentCallback<HttpEntityEnclosingRequest> contentCallback , ResultCallback<R> resultCallback) throws IOException {
        HttpUriRequest httpUriRequest = (Method.POST == method) ? new HttpPost(request.getUrl()) : new HttpGet(request.getUrl());

        //2.设置请求头
        setRequestHeaders(httpUriRequest, request.getContentType(), request.getHeaders());

        //3.设置请求参数
        setRequestProperty((HttpRequestBase) httpUriRequest, request.getConnectionTimeout(), request.getReadTimeout());

        //4.创建请求内容,如果有的话
        if(httpUriRequest instanceof HttpEntityEnclosingRequest){
            if(contentCallback != null){
                contentCallback.doWriteWith((HttpEntityEnclosingRequest)httpUriRequest);
            }
        }

        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        HttpEntity entity = null;
        try {
            ssl处理///
            HostnameVerifier hostnameVerifier = null;
            SSLContext sslContext = null;
            //https默认设置这些
            if(ParamUtil.isHttps(request.getUrl())){
                hostnameVerifier = getDefaultHostnameVerifier();
                sslContext = getDefaultSSLContext();
                //客户传过来就用客户的
                if(request instanceof SSLRequest){
                    SSLRequest sslRequest = (SSLRequest)request;
                    hostnameVerifier = sslRequest.getHostnameVerifier();
                    sslContext = sslRequest.getSslContext();
                }
            }
            ssl处理///

            httpClient = getCloseableHttpClient(request.getUrl() , hostnameVerifier , sslContext);
            //6.发送请求
            response = httpClient.execute(httpUriRequest  , HttpClientContext.create());
            int statusCode = response.getStatusLine().getStatusCode();
            entity = response.getEntity();
            InputStream inputStream = entity.getContent();
            if(null == inputStream){
                inputStream = new ByteArrayInputStream(new byte[]{});
            }
            R convert = resultCallback.convert(statusCode , inputStream, request.getResultCharset(), request.isIncludeHeaders() ? parseHeaders(response) : new HashMap<>(0));
            IoUtil.close(inputStream);
            return convert;

            ///
            /*Response convert = Response.with(statusCode , inputStream , request.getResultCharset() , request.isIncludeHeaders() ? parseHeaders(response) : new HashMap<>(0));
            IoUtil.close(inputStream);
            return convert;*/
        } catch (IOException e) {
            throw e;
        } catch (Exception e){
            throw new RuntimeException(e);
        }finally {
            EntityUtils.consumeQuietly(entity);
            IoUtil.close(response);
            IoUtil.close(httpClient);
        }
    }

    @Override
    public  <R> R template(String url, Method method , String contentType, ContentCallback<HttpEntityEnclosingRequest> contentCallback, ArrayListMultimap<String, String> headers, int connectTimeout, int readTimeout, String resultCharset , boolean includeHeader , ResultCallback<R> resultCallback) throws IOException {
        //1.创建请求
        ///*URIBuilder builder = new URIBuilder(url);
        //URI uri = builder.build();*/
        HttpUriRequest httpUriRequest = (Method.POST == method) ? new HttpPost(url) : new HttpGet(url);

        //2.设置请求头
        setRequestHeaders(httpUriRequest, contentType, headers);

        //3.设置请求参数
        setRequestProperty((HttpRequestBase) httpUriRequest, connectTimeout, readTimeout);

        //4.创建请求内容,如果有的话
        if(httpUriRequest instanceof HttpEntityEnclosingRequest){
            if(contentCallback != null){
                contentCallback.doWriteWith((HttpEntityEnclosingRequest)httpUriRequest);
            }
        }

        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        HttpEntity entity = null;
        try {

            //5.创建http客户端
            //CloseableHttpClient httpClient = HttpClients.createDefault();
            httpClient = getCloseableHttpClient(url ,getDefaultHostnameVerifier() , getDefaultSSLContext());

            //6.发送请求
            response = httpClient.execute(httpUriRequest  , HttpClientContext.create());
            int statusCode = response.getStatusLine().getStatusCode();
            /*String resultString = EntityUtils.toString(response.getEntity(), resultCharset);*/

            entity = response.getEntity();

//            if (HttpStatus.HTTP_OK == statusCode) {
//                //7.封装返回参数
//                InputStream inputStream = entity.getContent();
//                R convert = resultCallback.convert(inputStream, resultCharset, includeHeader ? parseHeaders(response) : new HashMap<>(0));
//                IoUtil.close(inputStream);
//                return convert;
//            }else {
//                String errorMsg = EntityUtils.toString(entity, resultCharset);
//                throw new HttpException(statusCode,errorMsg,parseHeaders(response));
//            }
            InputStream inputStream = entity.getContent();
//            R convert;
//            if (HttpStatus.HTTP_OK == statusCode) {
//                //7.封装返回参数
//                convert = resultCallback.convert(HttpStatus.HTTP_OK , inputStream, resultCharset, includeHeader ? parseHeaders(response) : new HashMap<>(0));
//            }else {
//                convert = resultCallback.convert(statusCode , inputStream , resultCharset , parseHeaders(response));
//            }
            if(null == inputStream){
                inputStream = new ByteArrayInputStream(new byte[]{});
            }
            R convert = resultCallback.convert(statusCode , inputStream, resultCharset, includeHeader ? parseHeaders(response) : new HashMap<>(0));
            IoUtil.close(inputStream);
            return convert;
        } catch (IOException e) {
            throw e;
        } catch (Exception e){
            throw new RuntimeException(e);
        }finally {
            EntityUtils.consumeQuietly(entity);
            IoUtil.close(response);
            IoUtil.close(httpClient);
        }
    }
    protected HostnameVerifier getDefaultHostnameVerifier(){
        return new TrustAnyHostnameVerifier();
    }
    protected SSLContext getDefaultSSLContext(){
        return SSLSocketFactoryBuilder.create().getSSLContext();
    }
    /**
     * https://ss.xx.xx.ss:8080/dsda
     */
    private CloseableHttpClient getCloseableHttpClient(String url, HostnameVerifier hostnameVerifier , SSLContext sslContext) throws Exception{
        return createHttpClient(200, 40, 100, url , hostnameVerifier , sslContext);
    }

    private boolean retryIf(IOException exception, int executionCount, HttpContext context) {
        if (executionCount >= _maxRetryTimes) {
            return false;
        }
        // 如果服务器丢掉了连接,那么就重试
        if (exception instanceof NoHttpResponseException) {
            return true;
        }
        // 不要重试SSL握手异常
        if (exception instanceof SSLHandshakeException) {
            return false;
        }
        // 超时
        if (exception instanceof InterruptedIOException) {
            return false;
        }
        // 目标服务器不可达
        if (exception instanceof UnknownHostException) {
            return false;
        }
        // 连接被拒绝
        if (exception instanceof ConnectException) {
            return false;
        }
        // SSL握手异常
        if (exception instanceof SSLException) {
            return false;
        }

        HttpClientContext clientContext = HttpClientContext
                .adapt(context);
        HttpRequest request = clientContext.getRequest();
        // 如果请求是幂等的,就再次尝试
        if (!(request instanceof HttpEntityEnclosingRequest)) {
            return true;
        }
        return false;
    }

    protected CloseableHttpClient createHttpClient(int maxTotal, int maxPerRoute, int maxRoute, String url , HostnameVerifier hostnameVerifier , SSLContext sslContext) throws Exception{
        String hostname = url.split("/")[2];
        boolean isHttps = ParamUtil.isHttps(url);
        int port = isHttps ? 443 : 80;
        if (hostname.contains(":")) {
            String[] arr = hostname.split(":");
            hostname = arr[0];
            port = Integer.parseInt(arr[1]);
        }

        ConnectionSocketFactory csf = PlainConnectionSocketFactory
                .getSocketFactory();
        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory
                .getSocketFactory();
        Registry<ConnectionSocketFactory> registry = RegistryBuilder
                .<ConnectionSocketFactory> create().register("http", csf)
                .register("https", sslsf).build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
        // 将最大连接数增加
        cm.setMaxTotal(maxTotal);
        // 将每个路由基础的连接增加
        cm.setDefaultMaxPerRoute(maxPerRoute);
        // 设置不活动的连接1000ms之后Validate
        cm.setValidateAfterInactivity(1000);

        HttpHost httpHost = new HttpHost(hostname, port);
        // 将目标主机的最大连接数增加
        cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);

        // 请求重试处理
        HttpRequestRetryHandler httpRequestRetryHandler = this::retryIf ;

        HttpClientBuilder httpClientBuilder = HttpClients.custom()
                .setConnectionManager(cm)
                .setRetryHandler(httpRequestRetryHandler);

        if(isHttps){
            initSSL(httpClientBuilder , hostnameVerifier , sslContext);
        }

        //给子类复写的机会
        doWithClient(httpClientBuilder , isHttps);

        return httpClientBuilder.build();
    }

    protected void doWithClient(HttpClientBuilder httpClientBuilder , boolean isHttps) throws Exception{
    }

    /**
     * @see SSLSocketFactoryBuilder#getSSLContext()
     * @see SSLSocketFactoryBuilder#getSSLContext(String, String)
     */
    protected void initSSL(HttpClientBuilder httpClientBuilder , HostnameVerifier hostnameVerifier , SSLContext sslContext) {
        // 验证域
        if(null != hostnameVerifier){
            httpClientBuilder.setSSLHostnameVerifier(hostnameVerifier);
        }
        if(null != sslContext){
            httpClientBuilder.setSSLContext(sslContext);
        }
    }

    protected void setRequestBody(HttpEntityEnclosingRequest request, String body, String bodyCharset) {
        if(body == null || bodyCharset == null){return;}

        StringEntity entity = new StringEntity(body, bodyCharset);
        entity.setContentEncoding(bodyCharset);
        request.setEntity(entity);
    }

    protected void setRequestProperty(HttpRequestBase request, int connectTimeout, int readTimeout) {
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(connectTimeout)
                .setConnectionRequestTimeout(readTimeout)
                .setSocketTimeout(readTimeout)
                //.setStaleConnectionCheckEnabled(true)
                .build();
        request.setConfig(config);
    }

    protected void setRequestHeaders(HttpUriRequest request, String contentType, ArrayListMultimap<String, String> headers) {
        if(null != headers) {
            Set<String> keySet = headers.keySet();
            keySet.forEach((k)->headers.get(k).forEach((v)->request.addHeader(k,v)));
        }
        if(null != contentType){
            request.setHeader(cn.zytx.common.http.Header.CONTENT_TYPE.toString(), contentType);
        }
    }

    private Map<String , List<String>> parseHeaders(CloseableHttpResponse response) {
        Header[] allHeaders = response.getAllHeaders();
        ArrayListMultimap<String,String> arrayListMultimap = new ArrayListMultimap<>(allHeaders.length);
        for (Header header : allHeaders) {
            arrayListMultimap.put(header.getName() , header.getValue());
        }
        return arrayListMultimap.getMap();
    }
}

OkHttp3:

package cn.zytx.common.http.base;

import cn.zytx.common.http.Header;
import cn.zytx.common.http.HttpStatus;
import cn.zytx.common.http.Method;
import cn.zytx.common.http.ParamUtil;
import cn.zytx.common.http.base.ssl.DefaultTrustManager2;
import cn.zytx.common.http.base.ssl.SSLSocketFactoryBuilder;
import cn.zytx.common.http.base.ssl.TrustAnyHostnameVerifier;
import cn.zytx.common.http.smart.SSLRequest;
import cn.zytx.common.utils.ArrayListMultimap;
import cn.zytx.common.utils.IoUtil;
import okhttp3.*;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author xiongshiyan at 2018/6/6
 */
public abstract class AbstractOkHttp3 implements HttpTemplate<Request.Builder> {

    @Override
    public <R> R template(cn.zytx.common.http.smart.Request request, Method method ,ContentCallback<Request.Builder> contentCallback , ResultCallback<R> resultCallback) throws IOException {
        Response response = null;
        InputStream inputStream = null;
        try {
            //1.构造OkHttpClient
            OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder()
                    .connectTimeout(request.getConnectionTimeout(), TimeUnit.MILLISECONDS)
                    .readTimeout(request.getReadTimeout(), TimeUnit.MILLISECONDS);

            ssl处理///
            if(ParamUtil.isHttps(request.getUrl())){
                //默认设置这些
                initSSL(clientBuilder , getDefaultHostnameVerifier() , getDefaultSSLSocketFactory() , getDefaultX509TrustManager());
                if(request instanceof SSLRequest){
                    //客户给了就用给客户的
                    SSLRequest sslRequest = (SSLRequest) request;
                    initSSL(clientBuilder , sslRequest.getHostnameVerifier(), sslRequest.getSslSocketFactory() , sslRequest.getX509TrustManager());
                }
            }
            ssl处理///

            //给子类复写的机会
            doWithBuilder(clientBuilder , ParamUtil.isHttps(request.getUrl()));

            OkHttpClient client = clientBuilder.build();

            //2.1设置URL
            Request.Builder builder = new Request.Builder().url(request.getUrl());

            ArrayListMultimap<String, String> headers = request.getHeaders();
            //2.2设置headers
            if(null != headers) {
                Set<String> keySet = headers.keySet();
                keySet.forEach((k)->headers.get(k).forEach((v)->builder.addHeader(k,v)));
            }
            if(null != request.getContentType()){
                builder.addHeader(Header.CONTENT_TYPE.toString() , request.getContentType());
            }

            //2.3处理请求体
            if(null != contentCallback && Method.POST == method){
                contentCallback.doWriteWith(builder);
            }

            //3.构造请求
            Request okRequest = builder.build();

            //4.执行请求
            response = client.newCall(okRequest).execute();

            //5.获取响应
            inputStream = getStreamFrom(response);

            int statusCode = response.code();
            return resultCallback.convert(statusCode , inputStream, request.getResultCharset(), request.isIncludeHeaders() ? parseHeaders(response) : new HashMap<>(0));
            /*return cn.zytx.common.http.smart.Response.with(statusCode , inputStream , request.getResultCharset() ,
                    request.isIncludeHeaders() ? parseHeaders(response) : new HashMap<>(0));*/
        } catch (IOException e) {
            throw e;
        } catch (Exception e){
            throw new RuntimeException(e);
        } finally {
            IoUtil.close(inputStream);
            if(null != response){
                try {
                    response.close();
                } catch (Exception e) {}
            }
        }
    }

    private InputStream getStreamFrom(Response response) {
        ResponseBody body = response.body();
        InputStream inputStream = (body != null) ? body.byteStream() : emptyInputStream();
        if(null == inputStream){
            inputStream = emptyInputStream();
        }
        return inputStream;
    }

    /**
     * 获取一个空的,防止空指针
     */
    private ByteArrayInputStream emptyInputStream() {
        return new ByteArrayInputStream(new byte[]{});
    }

    @Override
    public  <R> R template(String url, Method method , String contentType , ContentCallback<Request.Builder> contentCallback , ArrayListMultimap<String, String> headers, int connectTimeout, int readTimeout, String resultCharset , boolean includeHeaders , ResultCallback<R> resultCallback) throws IOException{
        Objects.requireNonNull(url);
        Response response = null;
        InputStream inputStream = null;
        try {
            //1.构造OkHttpClient
            OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder()
                    .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
                    .readTimeout(readTimeout, TimeUnit.MILLISECONDS);

            ssl处理///
            if(ParamUtil.isHttps(url)){
                //默认设置这些
                initSSL(clientBuilder , getDefaultHostnameVerifier() , getDefaultSSLSocketFactory() , getDefaultX509TrustManager());
            }
            ssl处理///

            //给子类复写的机会
            doWithBuilder(clientBuilder , ParamUtil.isHttps(url));

            OkHttpClient client = clientBuilder.build();

            //2.1设置URL
            Request.Builder builder = new Request.Builder().url(url);

            //2.2设置headers
            if(null != headers) {
                Set<String> keySet = headers.keySet();
                keySet.forEach((k)->headers.get(k).forEach((v)->builder.addHeader(k,v)));
            }
            if(null != contentType){
                builder.addHeader(Header.CONTENT_TYPE.toString() , contentType);
            }

            //2.3处理请求体
            if(null != contentCallback && Method.POST == method){
                contentCallback.doWriteWith(builder);
            }

            //3.构造请求
            Request request = builder.build();

            //4.执行请求
            response = client.newCall(request).execute();

            //5.获取响应
//            return getReturnMsg(response , resultCharset , includeHeaders , resultCallback);
            inputStream = getStreamFrom(response);

            int statusCode = response.code();
            return resultCallback.convert(statusCode , inputStream, resultCharset, includeHeaders ? parseHeaders(response) : new HashMap<>(0));
            ///保留起
            /*if (HttpStatus.HTTP_OK == statusCode) {
                convert = resultCallback.convert(HttpStatus.HTTP_OK , inputStream, resultCharset, includeHeaders ? parseHeaders(response) : new HashMap<>(0));
            }else {
                convert = resultCallback.convert(statusCode , inputStream , resultCharset , parseHeaders(response));
            }
            return convert;*/
        } catch (IOException e) {
            throw e;
        } catch (Exception e){
            throw new RuntimeException(e);
        } finally {
            IoUtil.close(inputStream);
            if(null != response){
                try {
                    response.close();
                } catch (Exception e) {}
            }
        }
    }
    protected HostnameVerifier getDefaultHostnameVerifier(){
        return new TrustAnyHostnameVerifier();
    }
    protected SSLSocketFactory getDefaultSSLSocketFactory(){
        return SSLSocketFactoryBuilder.create().build();
    }
    protected X509TrustManager getDefaultX509TrustManager(){
        return new DefaultTrustManager2();
    }
    protected void doWithBuilder(OkHttpClient.Builder builder , boolean isHttps) throws Exception{
    }

    /**
     * @see SSLSocketFactoryBuilder#build()
     * @see SSLSocketFactoryBuilder#build(String, String)
     */
    protected void initSSL(OkHttpClient.Builder builder , HostnameVerifier hostnameVerifier , SSLSocketFactory sslSocketFactory , X509TrustManager trustManager) {
        // 验证域
        if(null != hostnameVerifier){
            builder.hostnameVerifier(hostnameVerifier);
        }
        if(null != sslSocketFactory) {
            builder.sslSocketFactory(sslSocketFactory , trustManager);
        }
    }

    protected void setRequestBody(Request.Builder builder , Method method , RequestBody requestBody){
        builder.method(method.name() , requestBody);
    }

    protected RequestBody stringBody(String body , String contentType){
        return RequestBody.create(MediaType.parse(contentType),body);
    }

    protected RequestBody inputStreamBody(String contentType , InputStream inputStream , long length){
        return new InputStreamRequestBody(contentType , inputStream , length);
    }

    protected <R> R getReturnMsg(Response response , String resultCharset , boolean includeHeaders , ResultCallback<R> resultParser) throws IOException {
        int statusCode = response.code();
        /*String body = new String(response.body().bytes() , resultCharset);*/
//        if (HttpStatus.HTTP_OK == statusCode) {
//            InputStream inputStream = response.body().byteStream();
//            R convert = resultParser.convert(inputStream, resultCharset, includeHeaders ? parseHeaders(response) : new HashMap<>(0));
//            IoUtil.close(inputStream);
//            return convert;
//
//        }else {
//            //获取错误body,而不是仅仅状态行信息的message response.message()
//            String errorMsg = new String(response.body().bytes() , resultCharset);
//            throw new HttpException(statusCode,errorMsg,parseHeaders(response));
//        }
        InputStream inputStream = getStreamFrom(response);
        R convert;
        if (HttpStatus.HTTP_OK == statusCode) {
            convert = resultParser.convert(HttpStatus.HTTP_OK , inputStream, resultCharset, includeHeaders ? parseHeaders(response) : new HashMap<>(0));
        }else {
            convert = resultParser.convert(statusCode , inputStream , resultCharset , parseHeaders(response));
        }
        IoUtil.close(inputStream);
        return convert;
    }

    /**
     * 获取响应中的headers
     */
    private Map<String, List<String>> parseHeaders(Response response) {
        Headers resHeaders = response.headers();
        ArrayListMultimap<String , String> headers = new ArrayListMultimap<>(resHeaders.size());
        resHeaders.names().forEach((key)-> headers.put(key,resHeaders.get(key)) );
        return headers.getMap();
    }

    /**
     * 根据inputStream生成requestBody的工具类
     * @see RequestBody#create(MediaType, File)
     */
    private static class InputStreamRequestBody extends RequestBody {
        private String contentType;
        private long len;
        private InputStream stream;

        public InputStreamRequestBody(String contentType, InputStream stream, long len) {
            this.contentType = contentType;
            this.stream = stream;
            this.len = len;
        }

        @Override
        public MediaType contentType() {
            return MediaType.parse(contentType);
        }

        @Override
        public long contentLength() throws IOException {
            return len;
        }

        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            Source source = Okio.source(stream);
            sink.writeAll(source);

            IoUtil.close(stream);
            IoUtil.close(source);
        }
    }
}

 

具体的实现就是调用相应的模板方法,传入不同的参数即可:

URLConnection:

package cn.zytx.common.http.basic;

import cn.zytx.common.http.*;

import cn.zytx.common.http.base.AbstractNativeHttp;
import cn.zytx.common.utils.ArrayListMultimap;
import cn.zytx.common.utils.IoUtil;

import java.io.*;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 使用URLConnection实现的Http请求类
 * @author 熊诗言2017/11/24
 */
public class NativeHttpClient extends AbstractNativeHttp implements HttpClient {
    private static final String END = "\r\n";
    private static final String TWO_HYPHENS = "--";
    private static final String BOUNDARY = "*****xsyloveyou******";
    /**
     * 数据开始标志
     */
    private static final String PART_BEGIN_LINE = TWO_HYPHENS + BOUNDARY + END;
    /**
     * 数据结束标志
     */
    private static final String END_LINE = TWO_HYPHENS + BOUNDARY + TWO_HYPHENS + END;
    @Override
    public String get(String actionName, Map<String, String> params, Map<String, String> headers, int connectTimeout, int readTimeout, String resultCharset) throws IOException {
        return template(HttpUtil.contactUrlParams(actionName , params), Method.GET, null, null, ArrayListMultimap.fromMap(headers),  connectTimeout, readTimeout,
                resultCharset, false , (b,r,h)-> IoUtil.read(b , r));
    }

    @Override
    public String post(String url, String body, String contentType, Map<String, String> headers, int connectTimeout, int readTimeout, String bodyCharset, String resultCharset) throws IOException {
        return template(url, Method.POST, contentType, connect -> writeContent(connect , body , bodyCharset),
                ArrayListMultimap.fromMap(headers), connectTimeout, readTimeout, resultCharset, false, (b, r, h) -> IoUtil.read(b, r));
    }

    @Override
    public byte[] getAsBytes(String url, ArrayListMultimap<String, String> headers,int connectTimeout,int readTimeout) throws IOException {
        return template(url, Method.GET, null, null, headers,
                connectTimeout, readTimeout, null, false ,
                (b,r,h)-> IoUtil.stream2Bytes(b));
    }

    @Override
    public File getAsFile(String url, ArrayListMultimap<String, String> headers, File file, int connectTimeout, int readTimeout) throws IOException {
        return template(url, Method.GET, null, null, headers,
                connectTimeout, readTimeout, null, false ,
                (b,r,h)-> IoUtil.copy2File(b, file));
    }

    /**
     * 上传文件
     */
    @Override
    public String upload(String url , ArrayListMultimap<String,String> headers , int connectTimeout , int readTimeout , String resultCharset ,FormFile... files) throws IOException{
        ArrayListMultimap<String, String> multimap = mergeHeaders(headers);
        return template(url, Method.POST, null, connect -> this.upload0(connect , files), multimap ,
                connectTimeout, readTimeout, resultCharset, false,
                (b, r, h) -> IoUtil.read(b, r));
    }

    /**
     * 上传文件和params参数传递,form-data类型的完全支持
     */
    @Override
    public String upload(String url, ArrayListMultimap<String, String> params, ArrayListMultimap<String, String> headers, int connectTimeout, int readTimeout, String resultCharset , FormFile... files) throws IOException {
        ArrayListMultimap<String, String> multimap = mergeHeaders(headers);
        return template(url, Method.POST, null, connect -> this.upload0(connect , params , files), multimap ,
                connectTimeout, readTimeout, resultCharset, false,
                (b, r, h) -> IoUtil.read(b, r));
    }

    protected void upload0(HttpURLConnection connection , FormFile... files) throws IOException{
        connection.addRequestProperty("Content-Length" , String.valueOf(getFormFilesLen(files) + END_LINE.length()));

        // 设置DataOutputStream
        DataOutputStream ds = new DataOutputStream(connection.getOutputStream());
        for (int i = 0; i < files.length; i++) {
            writeOneFile(ds, files[i]);
        }
        ds.writeBytes(END_LINE);
        /* close streams */
        ds.flush();
        //ds.close();
    }

    protected void upload0(HttpURLConnection connection , ArrayListMultimap<String, String> params, FormFile... files) throws IOException{
        int fileDataLength = getFormFilesLen(files);

        String textEntity = getTextEntity(params);
        // 计算传输给服务器的实体数据总长度
        int dataLength = textEntity.getBytes().length + fileDataLength + END_LINE.length();

        connection.addRequestProperty("Content-Length" , String.valueOf(dataLength));

        DataOutputStream ds = new DataOutputStream(connection.getOutputStream());

        //写params数据
        ds.writeBytes(textEntity);
        //写文件
        for (int i = 0; i < files.length; i++) {
            writeOneFile(ds, files[i]);
        }
        //写末尾行
        ds.writeBytes(END_LINE);
        /* close streams */
        ds.flush();
        ds.close();
    }

    /**
     * 写一个文件 , 必须保证和getFormFilesLen的内容一致
     * @see NativeHttpClient#getFormFilesLen(FormFile...)
     */
    private void writeOneFile(DataOutputStream ds, FormFile formFile) throws IOException {
        ds.writeBytes(PART_BEGIN_LINE);
        ds.writeBytes("Content-Disposition: form-data; name=\"" + formFile.getParameterName() + "\"; filename=\"" + formFile.getFilName() + "\"" + END);
        ds.writeBytes("Content-Type: " + formFile.getContentType() + END + END);

        InputStream inStream = formFile.getInStream();
        IoUtil.copy(inStream, ds);
        ds.writeBytes(END);

        IoUtil.close(inStream);
    }

    /**
     * 计算需要传输的字节数
     * @see NativeHttpClient#writeOneFile(DataOutputStream, FormFile)
     * @param files FormFile
     * @return 总的字节数
     */
    protected int getFormFilesLen(FormFile... files){
        int fileDataLength = 0;
        for (FormFile formFile : files) {
            StringBuilder fileExplain = new StringBuilder();
            fileExplain.append(PART_BEGIN_LINE);
            fileExplain.append("Content-Disposition: form-data; name=\"" + formFile.getParameterName() + "\";filename=\"" + formFile.getFilName() + "\"" + END);
            fileExplain.append("Content-Type: " + formFile.getContentType() + END + END);
            fileDataLength += fileExplain.length();
            fileDataLength += formFile.getFileLen();
            fileDataLength += END.length();
        }
        return fileDataLength;
    }

    private String getTextEntity(ArrayListMultimap<String, String> params) {
        StringBuilder textEntity = new StringBuilder();
        // 构造文本类型参数的实体数据
        if(null != params){
            Set<String> keySet = params.keySet();
            for(String key : keySet){
                List<String> list = params.get(key);
                for(String value : list){
                    textEntity.append(PART_BEGIN_LINE);
                    textEntity.append("Content-Disposition: form-data; name=\"" + key + "\"" + END + END);
                    textEntity.append(value).append(END);
                }
            }
        }
        return textEntity.toString();
    }

    protected ArrayListMultimap<String, String> mergeHeaders(ArrayListMultimap<String, String> headers) {
        if(null == headers){
            headers = new ArrayListMultimap<>();
        }
        //headers.put("Connection" , "Keep-Alive");
        headers.put("Charset" , "UTF-8");
        headers.put("Content-Type" , "multipart/form-data; boundary=" + BOUNDARY);
        return headers;
    }


    /**
     * form-data的格式为:
     */
/*
    --*****xsyloveyou******
    Content-Disposition: form-data; name="k1"

    v1
    --*****xsyloveyou******
    Content-Disposition: form-data; name="k2"

    v2
    --*****xsyloveyou******
    Content-Disposition: form-data; name="filedata2"; filename="BugReport.png"
    Content-Type: application/octet-stream

            我是文本类容文件
    --*****xsyloveyou******
    Content-Disposition: form-data; name="filedata"; filename="838586397836550106.jpg"
    Content-Type: application/octet-stream

            我是文件内容2
    --*****xsyloveyou******--

*/

}

ApacheHttpClient:

package cn.zytx.common.http.basic;

import cn.zytx.common.http.*;
import cn.zytx.common.http.base.AbstractApacheHttp;
import cn.zytx.common.utils.ArrayListMultimap;
import cn.zytx.common.utils.IoUtil;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.util.CharsetUtils;

import java.io.*;
import java.util.Map;

/**
 * 使用Apache SmartHttpClient 实现的Http请求类
 * @author 熊诗言2017/12/01
 */
public class ApacheHttpClient extends AbstractApacheHttp implements HttpClient {
    @Override
    public String get(String url, Map<String, String> params, Map<String, String> headers, int connectTimeout, int readTimeout, String resultCharset) throws IOException{
        return template(HttpUtil.contactUrlParams(url , params), Method.GET,null,null,
                ArrayListMultimap.fromMap(headers),
                connectTimeout,readTimeout , resultCharset,false,(b,r,h)-> IoUtil.read(b ,r));
    }

    @Override
    public String post(String url, String body, String contentType, Map<String, String> headers, int connectTimeout, int readTimeout, String bodyCharset, String resultCharset) throws IOException {
        return template(url,Method.POST, contentType, (request -> setRequestBody(request , body ,bodyCharset)),
                ArrayListMultimap.fromMap(headers),
                connectTimeout, readTimeout , resultCharset,false, (b,r,h)-> IoUtil.read(b ,r));
    }

    @Override
    public byte[] getAsBytes(String url, ArrayListMultimap<String, String> headers, int connectTimeout, int readTimeout) throws IOException {
        return template(url, Method.GET,null,null, headers,
                connectTimeout,readTimeout , null,false,
                (b,r,h)-> IoUtil.stream2Bytes(b));
    }

    @Override
    public File getAsFile(String url, ArrayListMultimap<String, String> headers, File file, int connectTimeout, int readTimeout) throws IOException {
        return template(url, Method.GET,null,null, headers ,
                connectTimeout,readTimeout , null,false,
                (b,r,h)-> IoUtil.copy2File(b, file));
    }


    @Override
    public String upload(String url, ArrayListMultimap<String,String> headers, int connectTimeout, int readTimeout, String resultCharset, FormFile... files) throws IOException{
        return template(url,Method.POST, null, (request -> addFormFiles(request, files)),
                headers, connectTimeout, readTimeout , resultCharset,false, (b,r,h)-> IoUtil.read(b ,r));
    }

    protected void addFormFiles(HttpEntityEnclosingRequest request, FormFile[] files) throws UnsupportedEncodingException {
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
                .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                .setCharset(CharsetUtils.get(DEFAULT_CHARSET));

        for (FormFile formFile : files) {
            multipartEntityBuilder.addBinaryBody(formFile.getParameterName(), formFile.getInStream() , ContentType.parse(formFile.getContentType()) , formFile.getFilName());
        }
        HttpEntity reqEntity = multipartEntityBuilder.build();
        request.setEntity(reqEntity);
    }


    @Override
    public String upload(String url, ArrayListMultimap<String, String> params, ArrayListMultimap<String, String> headers, int connectTimeout, int readTimeout, String resultCharset, FormFile... files) throws IOException {
        return template(url,Method.POST, null, (request -> addFormFiles(request, params ,files)),
                headers, connectTimeout, readTimeout , resultCharset,false, (b,r,h)-> IoUtil.read(b ,r));
    }

    protected void addFormFiles(HttpEntityEnclosingRequest request, ArrayListMultimap<String, String> params ,FormFile[] files) throws UnsupportedEncodingException {
        final MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
                .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                .setCharset(CharsetUtils.get(DEFAULT_CHARSET));

        if(null != params){
            params.keySet().forEach(key->params.get(key).forEach(value->multipartEntityBuilder.addTextBody(key , value)));
        }

        for (FormFile formFile : files) {
            multipartEntityBuilder.addBinaryBody(formFile.getParameterName(), formFile.getInStream() , ContentType.parse(formFile.getContentType()) , formFile.getFilName());
        }
        HttpEntity reqEntity = multipartEntityBuilder.build();
        request.setEntity(reqEntity);
    }
}

OkHttp3:

package cn.zytx.common.http.basic;

import cn.zytx.common.http.base.AbstractOkHttp3;
import cn.zytx.common.http.HttpUtil;
import cn.zytx.common.http.Method;
import cn.zytx.common.utils.ArrayListMultimap;
import cn.zytx.common.utils.IoUtil;
import okhttp3.Headers;
import okhttp3.MultipartBody;

import java.io.File;
import java.io.IOException;
import java.util.Map;

/**
 * @author xiongshiyan at 2018/1/11
 */
public class OkHttp3Client extends AbstractOkHttp3 implements HttpClient {
    @Override
    public String get(String url, Map<String, String> params, Map<String, String> headers, int connectTimeout, int readTimeout, String resultCharset) throws IOException {
        return template(HttpUtil.contactUrlParams(url , params),Method.GET,null,null,
                ArrayListMultimap.fromMap(headers),
                connectTimeout,readTimeout,resultCharset,false,(b,r,h)-> IoUtil.read(b ,r));
    }

    /**
     * @param bodyCharset 请求体的编码,不支持,需要在contentType中指定
     */
    @Override
    public String post(String url, String body, String contentType, Map<String, String> headers, int connectTimeout, int readTimeout, String bodyCharset, String resultCharset) throws IOException {
        return template(url, Method.POST, contentType, d->setRequestBody(d , Method.POST , stringBody(body , contentType)) ,
                ArrayListMultimap.fromMap(headers),
                connectTimeout,readTimeout,resultCharset,false,
                (b,r,h)-> IoUtil.read(b ,r));
    }

    @Override
    public byte[] getAsBytes(String url, ArrayListMultimap<String, String> headers, int connectTimeout, int readTimeout) throws IOException {
        return template(url,Method.GET,null,null, headers ,
                connectTimeout,readTimeout,null,false,
                (b,r,h)-> IoUtil.stream2Bytes(b));
    }

    @Override
    public File getAsFile(String url, ArrayListMultimap<String, String> headers, File file, int connectTimeout, int readTimeout) throws IOException {
        return template(url,Method.GET,null,null, headers ,
                connectTimeout,readTimeout,null,false,
                (b,r,h)-> IoUtil.copy2File(b, file));
    }

    @Override
    public String upload(String url, ArrayListMultimap<String, String> headers, int connectTimeout, int readTimeout, String resultCharset, FormFile... files) throws IOException {
        MultipartBody requestBody = getFilesBody(files);

        return template(url, Method.POST, null , d->setRequestBody(d, Method.POST , requestBody), headers,
                connectTimeout,readTimeout,resultCharset,false,
                (b,r,h)-> IoUtil.read(b ,r));
    }

    protected MultipartBody getFilesBody(FormFile... files) {
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        for (FormFile formFile : files) {
            builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + formFile.getParameterName() + "\"; filename=\"" + formFile.getFilName() + "\"") ,
                    inputStreamBody(formFile.getContentType() , formFile.getInStream() , formFile.getFileLen()));
        }
        return builder.build();
    }

    @Override
    public String upload(String url, ArrayListMultimap<String, String> params, ArrayListMultimap<String, String> headers, int connectTimeout, int readTimeout, String resultCharset , FormFile... files) throws IOException {
        MultipartBody requestBody = getFilesBody(params , files);

        return template(url, Method.POST, null , d->setRequestBody(d, Method.POST , requestBody), headers,
                connectTimeout,readTimeout,resultCharset,false,
                (b,r,h)-> IoUtil.read(b ,r));
    }

    protected MultipartBody getFilesBody(ArrayListMultimap<String, String> params , FormFile... files) {
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        if(null != params){
            params.keySet().forEach(key->params.get(key).forEach(value->builder.addFormDataPart(key , value)));
        }

        for (FormFile formFile : files) {
            builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + formFile.getParameterName() + "\"; filename=\"" + formFile.getFilName() + "\"") ,
                    inputStreamBody(formFile.getContentType() , formFile.getInStream() , formFile.getFileLen()));
        }
        return builder.build();
    }
}

其中关于SSL处理的一些工具类【感谢looly等】

package cn.zytx.common.http.base.ssl;

import cn.zytx.common.utils.ArrayUtil;
import cn.zytx.common.utils.StrUtil;

import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Objects;

/**
 * SSLSocketFactory构建器
 * @author Looly
 * @author xiongshiyan 增加证书相关方法
 */
public class SSLSocketFactoryBuilder {

    /** Supports some version of SSL; may support other versions */
	public static final String SSL    = "SSL";
	/** Supports SSL version 2 or later; may support other versions */
	public static final String SSLv2  = "SSLv2";
	/** Supports SSL version 3; may support other versions */
	public static final String SSLv3  = "SSLv3";
	
	/** Supports some version of TLS; may support other versions */
	public static final String TLS    = "TLS";
	/** Supports RFC 2246: TLS version 1.0 ; may support other versions */
	public static final String TLSv1  = "TLSv1";
	/** Supports RFC 4346: TLS version 1.1 ; may support other versions */
	public static final String TLSv11 = "TLSv1.1";
	/** Supports RFC 5246: TLS version 1.2 ; may support other versions */
	public static final String TLSv12 = "TLSv1.2";


    /**
     * 证书类型
	 */
	public static final String JKS = "JKS";
	public static final String PKCS12 = "PKCS12";

	private String protocol = TLS;
	private String certType = PKCS12;
	private KeyManager[] keyManagers;
	private TrustManager[] trustManagers = {new DefaultTrustManager()};
	private SecureRandom secureRandom  = new SecureRandom();
	
	
	/**
	 * 创建 SSLSocketFactoryBuilder
	 * @return SSLSocketFactoryBuilder
	 */
	public static SSLSocketFactoryBuilder create(){
		return new SSLSocketFactoryBuilder();
	}
	
	/**
	 * 设置协议
	 * @param protocol 协议
	 * @return 自身
	 */
	public SSLSocketFactoryBuilder setProtocol(String protocol){
		if(StrUtil.isNotBlank(protocol)){
			this.protocol = protocol;
		}
		return this;
	}

	/**
     * 设置证书类型
	 * @param certType 证书类型
     */
	public SSLSocketFactoryBuilder setCertType(String certType) {
		if(StrUtil.isNotBlank(certType)){
			this.certType = certType;
		}
		return this;
	}

	/**
	 * 设置信任信息
	 * @param trustManagers TrustManager列表
	 * @return 自身
	 */
	public SSLSocketFactoryBuilder setTrustManagers(TrustManager... trustManagers) {
		if (ArrayUtil.isNotEmpty(trustManagers)) {
			this.trustManagers = trustManagers;
		}
		return this;
	}

	public TrustManager[] getTrustManagers() {
		return trustManagers;
	}

	/**
	 * 设置 JSSE key managers
	 * @param keyManagers JSSE key managers
	 * @return 自身
	 */
	public SSLSocketFactoryBuilder setKeyManagers(KeyManager... keyManagers) {
		if (ArrayUtil.isNotEmpty(keyManagers)) {
			this.keyManagers = keyManagers;
		}
		return this;
	}
	
	/**
	 * 设置 SecureRandom
	 * @param secureRandom SecureRandom
	 * @return 自己
	 */
	public SSLSocketFactoryBuilder setSecureRandom(SecureRandom secureRandom){
		if(null != secureRandom){
			this.secureRandom = secureRandom;
		}
		return this;
	}
	
	/**
	 * 构建SSLSocketFactory
	 * @return SSLSocketFactory
	 */
	public SSLSocketFactory build() {
		return getSSLContext().getSocketFactory();
	}

	/**
	 * 用于ssl双向认证,例如微信退款应用中
	 * 用证书和密码构建SSLSocketFactory
	 * @param certPath 证书路径
	 * @param certPass 证书密码
	 */
	public SSLSocketFactory build(String certPath, String certPass){
		return getSSLContext(certPath , certPass).getSocketFactory();
	}
	public SSLSocketFactory buildWithClassPathCert(Class<?> clazz , String certPath, String certPass){
		return getClassPathSSLContext(clazz , certPath , certPass).getSocketFactory();
	}
	public SSLSocketFactory build(InputStream inputStream, String certPass){
		return getSSLContext(inputStream , certPass).getSocketFactory();
	}


	public SSLContext getSSLContext(){
		try {
			SSLContext sslContext = SSLContext.getInstance(protocol);
			sslContext.init(this.keyManagers, this.trustManagers, this.secureRandom);
			return sslContext;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
     * 使用FileInputStream来加载资源
	 * @param certPath 证书路径
	 * @param certPass 证书密码
	 */
	public SSLContext getSSLContext(String certPath, String certPass){
		try {
			InputStream inputStream = new FileInputStream(certPath);
			return getSSLContext(inputStream , certPass);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	/**
     * 使用class来加载资源
	 * @param clazz 用于加载资源 /开头的话就从classpath目录下,否则从class包下
	 *              @see Class#getResourceAsStream(String)
	 * @param certPath classpath 证书路径
	 * @param certPass 证书密码
	 */
	public SSLContext getClassPathSSLContext(Class<?> clazz , String certPath, String certPass){
		try {
			InputStream inputStream = clazz.getResourceAsStream(certPath);
			return getSSLContext(inputStream , certPass);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @param certStream 证书流,本方法会自动关闭
	 * @param certPass 密码
	 */
	public SSLContext getSSLContext(InputStream certStream, String certPass){
		InputStream inputStream = Objects.requireNonNull(certStream);

		try {
			KeyStore clientStore = KeyStore.getInstance(certType);
			char[] passArray = certPass.toCharArray();
			clientStore.load(inputStream, passArray);

			KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
			kmf.init(clientStore, passArray);
			KeyManager[] kms = kmf.getKeyManagers();
			//"TLSv1"
			SSLContext sslContext = SSLContext.getInstance(protocol);

			sslContext.init(kms, this.trustManagers, this.secureRandom);

			inputStream.close();

			return sslContext;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
package cn.zytx.common.http.base.ssl;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

/**
 * https 域名校验
 * @author Looly
 */
public class TrustAnyHostnameVerifier implements HostnameVerifier {
	
	@Override
	public boolean verify(String hostname, SSLSession session) {
		// 直接返回true
		return true;
	}
}
package cn.zytx.common.http.base.ssl;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**
 * 证书管理
 * @author Looly
 *
 */
public class DefaultTrustManager implements X509TrustManager {

	@Override
	public X509Certificate[] getAcceptedIssuers() {
		return null;
	}

	@Override
	public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	}

	@Override
	public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	}
}
package cn.zytx.common.http.base.ssl;

import java.security.cert.X509Certificate;

/**
 * 防止OKHttp3的空指针
 * @author xiongshiyan
 */
public class DefaultTrustManager2 extends DefaultTrustManager {

	@Override
	public X509Certificate[] getAcceptedIssuers() {
		X509Certificate[] certificates = {};
		return certificates;
	}
}

 

操作更简便的SmartHttpClient的实现类

HttpURLConnection

package cn.zytx.common.http.smart;

import cn.zytx.common.http.*;
import cn.zytx.common.http.basic.NativeHttpClient;
import cn.zytx.common.utils.ArrayListMultimap;
import cn.zytx.common.utils.IoUtil;

import java.io.*;

/**
 * 使用URLConnection实现的Http请求类
 * @author 熊诗言2017/11/24
 */
public class NativeSmartHttpClient extends NativeHttpClient implements SmartHttpClient {
    @Override
    public Response get(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*Response response = template(ParamUtil.contactUrlParams(request.getUrl(), request.getParams() , request.getBodyCharset()), Method.GET,
                request.getContentType(), null, request.getHeaders(), request.getConnectionTimeout(), request.getReadTimeout(),
                request.getResultCharset(), request.isIncludeHeaders(), Response::with);*/
        Response response = template(request.setUrl(ParamUtil.contactUrlParams(request.getUrl(), request.getParams(), request.getBodyCharset())) ,
                Method.GET , null , Response::with);
        return afterTemplate(request , response);
    }

    @Override
    public Response post(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*Response response = template(request.getUrl(), Method.POST, request.getContentType(),
                connection -> writeContent(connection, request.getBody(), request.getBodyCharset()),
                request.getHeaders(), request.getConnectionTimeout(), request.getReadTimeout(),
                request.getResultCharset(), request.isIncludeHeaders(), Response::with);*/
        Response response = template(request, Method.POST , connection -> writeContent(connection, request.getBody(), request.getBodyCharset()) , Response::with);
        return afterTemplate(request , response);
    }

    @Override
    public byte[] getAsBytes(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*return template(request.getUrl(), Method.GET, request.getContentType(), null,request.getHeaders(),
                request.getConnectionTimeout(), request.getReadTimeout(), request.getResultCharset(), request.isIncludeHeaders() ,
                (s,b,r,h)-> IoUtil.stream2Bytes(b));*/
        return template(request , Method.GET , null , (s, b, r, h)-> IoUtil.stream2Bytes(b));
    }

    @Override
    public File getAsFile(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*return template(request.getUrl(), Method.GET, request.getContentType(), null,request.getHeaders(),
                request.getConnectionTimeout(), request.getReadTimeout(), request.getResultCharset(), request.isIncludeHeaders() ,
                (s,b,r,h)-> IoUtil.copy2File(b, request.getFile()));*/
        return template(request , Method.GET , null , (s, b, r, h)-> IoUtil.copy2File(b, request.getFile()));
    }

    @Override
    public Response upload(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*ArrayListMultimap<String, String> headers = mergeHeaders(request.getHeaders(), request.getFormFiles());
        Response response = template(request.getUrl(), Method.POST, null, connect -> this.upload0(connect, request.getFormFiles()),
                headers, request.getConnectionTimeout(), request.getReadTimeout(), request.getResultCharset(), request.isIncludeHeaders(),
                Response::with);*/
        /*使用更全的 ,支持文件和参数一起上传 */

        ArrayListMultimap<String, String> headers = mergeHeaders(request.getHeaders());
        /*Response response = template(request.getUrl(), Method.POST, null, connect -> this.upload0(connect, request.getParams() ,request.getFormFiles()),
                headers, request.getConnectionTimeout(), request.getReadTimeout(), request.getResultCharset(), request.isIncludeHeaders(),
                Response::with);*/
        Response response = template(request.setHeaders(headers), Method.POST ,
                connect -> this.upload0(connect, request.getParams(), request.getFormFiles()) , Response::with);
        return afterTemplate(request , response);
    }

    @Override
    public Response afterTemplate(Request request, Response response) throws IOException{
        if(request.isRedirectable() && response.needRredirect()){
            return get(Request.of(response.getRedirectUrl()));
        }
        return response;
    }
}

ApacheHttpClient

package cn.zytx.common.http.smart;

import cn.zytx.common.http.*;
import cn.zytx.common.http.basic.ApacheHttpClient;
import cn.zytx.common.utils.IoUtil;

import java.io.File;
import java.io.IOException;

/**
 * 使用Apache SmartHttpClient 实现的Http请求类
 * @author 熊诗言2017/12/01
 */
public class ApacheSmartHttpClient extends ApacheHttpClient implements SmartHttpClient {
    @Override
    public Response get(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*Response response = template(ParamUtil.contactUrlParams(request.getUrl(), request.getParams() , request.getBodyCharset()), Method.GET,
                request.getContentType(), null, request.getHeaders(),
                request.getConnectionTimeout(), request.getReadTimeout(),
                request.getResultCharset(), request.isIncludeHeaders(),
                Response::with);*/
        Response response = template(request.setUrl(ParamUtil.contactUrlParams(request.getUrl(), request.getParams(), request.getBodyCharset())) ,
                Method.GET , null , Response::with);
        return afterTemplate(request , response);
    }

    @Override
    public Response post(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*Response response = template(request.getUrl(), Method.POST, request.getContentType(),
                r -> setRequestBody(r, request.getBody(), request.getBodyCharset()), request.getHeaders(),
                request.getConnectionTimeout(), request.getReadTimeout(), request.getResultCharset(), request.isIncludeHeaders(),
                Response::with);*/
        Response response = template(request, Method.POST ,
                r -> setRequestBody(r, request.getBody(), request.getBodyCharset()) , Response::with);
        return afterTemplate(request , response);
    }

    @Override
    public byte[] getAsBytes(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*return template(request.getUrl(), Method.GET, request.getContentType(),null, request.getHeaders(),
                request.getConnectionTimeout(),request.getReadTimeout() , request.getResultCharset(),request.isIncludeHeaders(),
                (s,b,r,h)-> IoUtil.stream2Bytes(b));*/
        return template(request , Method.GET , null , (s, b, r, h)-> IoUtil.stream2Bytes(b));
    }

    @Override
    public File getAsFile(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*return template(request.getUrl(), Method.GET, request.getContentType(),null, request.getHeaders() ,
                request.getConnectionTimeout(),request.getReadTimeout() , request.getResultCharset(),request.isIncludeHeaders(),
                (s,b,r,h)-> IoUtil.copy2File(b, request.getFile()));*/
        return template(request , Method.GET, null , (s, b, r, h)-> IoUtil.copy2File(b, request.getFile()));
    }

    @Override
    public Response upload(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*Response response = template(request.getUrl(), Method.POST, request.getContentType(), r -> addFormFiles(r, request.getFormFiles()),
                request.getHeaders(), request.getConnectionTimeout(), request.getReadTimeout(), request.getResultCharset(), request.isIncludeHeaders(),
                Response::with);*/
        /*使用更全的 ,支持文件和参数一起上传 */

        /*Response response = template(request.getUrl(), Method.POST, request.getContentType(), r -> addFormFiles(r, request.getParams() , request.getFormFiles()),
                request.getHeaders(), request.getConnectionTimeout(), request.getReadTimeout(), request.getResultCharset(), request.isIncludeHeaders(),
                Response::with);*/
        Response response = template(request , Method.POST ,
                r -> addFormFiles(r, request.getParams(), request.getFormFiles()) , Response::with);
        return afterTemplate(request , response);
    }

    @Override
    public Response afterTemplate(Request request, Response response) throws IOException{
        if(request.isRedirectable() && response.needRredirect()){
            return get(Request.of(response.getRedirectUrl()));
        }
        return response;
    }
}

OkHttp3

package cn.zytx.common.http.smart;

import cn.zytx.common.http.ParamUtil;
import cn.zytx.common.http.Method;
import cn.zytx.common.http.basic.OkHttp3Client;
import cn.zytx.common.utils.IoUtil;
import okhttp3.MultipartBody;

import java.io.File;
import java.io.IOException;

/**
 * @author xiongshiyan at 2018/1/11
 */
public class OkHttp3SmartHttpClient extends OkHttp3Client implements SmartHttpClient {
    @Override
    public Response get(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*Response response = template(ParamUtil.contactUrlParams(request.getUrl(), request.getParams() , request.getBodyCharset()), Method.GET, request.getContentType(), null, request.getHeaders(),
                request.getConnectionTimeout(), request.getReadTimeout(), request.getResultCharset(), request.isIncludeHeaders(),
                Response::with);
        return afterTemplate(request , response);*/
        Response response = template(request.setUrl(ParamUtil.contactUrlParams(request.getUrl(), request.getParams(), request.getBodyCharset())) , Method.GET , null , Response::with);
        return afterTemplate(request , response);
    }
    /**
     * @param req 请求体的编码,不支持,需要在contentType中指定
     */
    @Override
    public Response post(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*Response response = template(request.getUrl(), Method.POST, request.getContentType(), d -> setRequestBody(d, Method.POST, stringBody(request.getBody(), request.getContentType())),
                request.getHeaders(), request.getConnectionTimeout(), request.getReadTimeout(), request.getResultCharset(), request.isIncludeHeaders(),
                Response::with);*/
        Response response = template(request, Method.POST , d -> setRequestBody(d, Method.POST, stringBody(request.getBody(), request.getContentType())) , Response::with);
        return afterTemplate(request , response);
    }

    @Override
    public byte[] getAsBytes(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*return template(request.getUrl(),Method.GET,request.getContentType() ,null, request.getHeaders() ,
                request.getConnectionTimeout(),request.getReadTimeout(),request.getResultCharset(),request.isIncludeHeaders(),
                (s,b,r,h)-> IoUtil.stream2Bytes(b));*/
        return template(request , Method.GET , null , (s, b, r, h)-> IoUtil.stream2Bytes(b));
    }

    @Override
    public File getAsFile(Request req) throws IOException {
        Request request = beforeTemplate(req);
        /*return template(request.getUrl(),Method.GET,request.getContentType(),null, request.getHeaders() ,
                request.getConnectionTimeout(),request.getConnectionTimeout(),request.getResultCharset(),request.isIncludeHeaders(),
                (s,b,r,h)-> IoUtil.copy2File(b, request.getFile()));*/
        return template(request , Method.GET , null , (s, b, r, h)-> IoUtil.copy2File(b, request.getFile()));
    }

    @Override
    public Response upload(Request req) throws IOException {
        Request request = beforeTemplate(req);

        //MultipartBody requestBody = getFilesBody(request.getFormFiles());
        /*使用更全的 ,支持文件和参数一起上传 */

        MultipartBody requestBody = getFilesBody(request.getParams() , request.getFormFiles());

        /*Response response = template(request.getUrl(), Method.POST, request.getContentType(), d -> setRequestBody(d, Method.POST, requestBody), request.getHeaders(),
                request.getConnectionTimeout(), request.getConnectionTimeout(), request.getResultCharset(), request.isIncludeHeaders(),
                Response::with);*/
        Response response = template(request, Method.POST , d -> setRequestBody(d, Method.POST, requestBody) , Response::with);
        return afterTemplate(request , response);
    }

    @Override
    public Response afterTemplate(Request request, Response response) throws IOException{
        if(request.isRedirectable() && response.needRredirect()){
            return get(Request.of(response.getRedirectUrl()));
        }
        return response;
    }
}

直接将结果封装为Bean的实现,使用的时候需要给这些类设置一个Converter的实现类(String->Bean)。

HTTPURLConnection

package cn.zytx.common.http.withconverter;

import cn.zytx.common.http.smart.NativeSmartHttpClient;

import java.util.Objects;

/**
 * 返回结果String转换为<R>
 * @author 熊诗言2017/11/24
 */
public class ConverterNativeSmartHttpClient extends NativeSmartHttpClient implements ConverterSmartHttpClient {

    private Converter converter;
    public ConverterNativeSmartHttpClient(Converter converter){
        this.converter = Objects.requireNonNull(converter);
    }
    public ConverterNativeSmartHttpClient(){}

    @Override
    public ConverterSmartHttpClient setConverter(Converter converter) {
        this.converter = Objects.requireNonNull(converter);
        return this;
    }

    @Override
    public <R> R convert(String src, Class<R> clazz) {
        if(converter == null){
            throw new IllegalStateException("converter is null,please use setConverter() to setting a converter");
        }
        return converter.convert(src , clazz);
    }
}

ApacheHttp

package cn.zytx.common.http.withconverter;

import cn.zytx.common.http.smart.ApacheSmartHttpClient;

import java.util.Objects;

/**
 * 返回结果String转换为<R>
 * @author 熊诗言2017/12/01
 */
public class ConverterApacheSmartHttpClient extends ApacheSmartHttpClient implements ConverterSmartHttpClient {

    private Converter converter;
    public ConverterApacheSmartHttpClient(Converter converter){
        this.converter = Objects.requireNonNull(converter);
    }
    public ConverterApacheSmartHttpClient(){}

    @Override
    public ConverterSmartHttpClient setConverter(Converter converter) {
        this.converter = Objects.requireNonNull(converter);
        return this;
    }

    @Override
    public <R> R convert(String src, Class<R> clazz) {
        if(converter == null){
            throw new IllegalStateException("converter is null,please use setConverter() to setting a converter");
        }
        return converter.convert(src , clazz);
    }
}

OkHttp3

package cn.zytx.common.http.withconverter;

import cn.zytx.common.http.smart.OkHttp3SmartHttpClient;

import java.util.Objects;

/**
 * 返回结果String转换为<R>
 * @author xiongshiyan at 2018/1/11
 */
public class ConverterOkHttp3SmartHttpClient extends OkHttp3SmartHttpClient implements ConverterSmartHttpClient {

    private Converter converter;
    public ConverterOkHttp3SmartHttpClient(Converter converter){
        this.converter = Objects.requireNonNull(converter);
    }
    public ConverterOkHttp3SmartHttpClient(){}

    @Override
    public ConverterSmartHttpClient setConverter(Converter converter) {
        this.converter = Objects.requireNonNull(converter);
        return this;
    }

    @Override
    public <R> R convert(String src, Class<R> clazz) {
        if(converter == null){
            throw new IllegalStateException("converter is null,please use setConverter() to setting a converter");
        }
        return converter.convert(src , clazz);
    }
}

其中的一个实现Json2BeanConverter

package cn.zytx.common.http.withconverter;

import cn.zytx.common.json.JsonObject;
import cn.zytx.common.json.impl.JSONObject;

/**
 * Json String -> JavaBean
 * 此类也示范了统一json的好处
 * cn.zytx.common.json.JsonObject
 * cn.zytx.common.json.impl.JSONObject
 * <!包名不变!>,只需要在build.gradle中修改引用就能改变json的实现
 * @author xiongshiyan at 2018/7/16
 */
public class Json2BeanConverter implements Converter{
    @Override
    public <R> R convert(String src, Class<R> clazz){
        JsonObject json = new JSONObject();
        return json.deserialize(src, clazz);
    }
}

json的实现参见我的另外两篇博文(完美统一Json的使用):

https://blog.csdn.net/xxssyyyyssxx/article/details/80696560

https://blog.csdn.net/xxssyyyyssxx/article/details/80696822

使用的时候可以使用HttpUtil工具里的getSmartHttpClient获取实现类,可以通过setSmartHttpClient修改默认的实现(默认是基于HTTPURLConnection)。

还可以通过 delegate()方法获取自动的实现,默认加载顺序是OkHttp3、ApacheHttpClient、HTTPURLConnection,即根据jar包自动加载。

package cn.zytx.common.http;

import cn.zytx.common.http.basic.HttpClient;
import cn.zytx.common.http.basic.NativeHttpClient;
import cn.zytx.common.http.converter.json.ConverterSmartHttpClient;
import cn.zytx.common.http.smart.NativeSmartHttpClient;
import cn.zytx.common.http.smart.SmartHttpClient;
import cn.zytx.common.utils.ClassUtil;

/**
 * @author xiongshiyan at 2017/12/11
 */
public class HttpUtil {
    private HttpUtil(){}

    /**
     * 静态绑定
     */
    private static HttpClient BASIC_HTTP_CLIENT = new NativeHttpClient();
    private static SmartHttpClient SMART_HTTP_CLIENT = new NativeSmartHttpClient();

    public static HttpClient getBasicHttpClient() {
        return BASIC_HTTP_CLIENT;
    }
    public static void setBasicHttpClient(HttpClient httpClient){BASIC_HTTP_CLIENT = httpClient;}
    public static SmartHttpClient getSmartHttpClient() {
        return SMART_HTTP_CLIENT;
    }
    public static void setSmartHttpClient(SmartHttpClient smartHttpClient){SMART_HTTP_CLIENT = smartHttpClient;}


    // http请求工具代理对象
    private static final ConverterSmartHttpClient delegate;
    public static ConverterSmartHttpClient delegate() {
        return delegate;
    }

    static {

        //根据类路径的jar加载默认顺序是 OKHttp3、ApacheHttpClient、URLConnection
        ConverterSmartHttpClient delegateToUse = null;
        // okhttp3.OkHttpClient ?
        if (ClassUtil.isPresent(HttpUtil.class.getClassLoader() ,"okhttp3.OkHttpClient" , "okio.Okio")) {
            delegateToUse = new cn.zytx.common.http.converter.json.ConverterOkHttp3SmartHttpClient();
        }
        // org.apache.http.impl.client.CloseableHttpClient ?
        else if (ClassUtil.isPresent(HttpUtil.class.getClassLoader() ,
                "org.apache.http.impl.client.CloseableHttpClient","org.apache.http.impl.client.HttpClientBuilder")) {
            delegateToUse = new cn.zytx.common.http.converter.json.ConverterApacheSmartHttpClient();
        }
        // java.net.URLConnection
        else if (ClassUtil.isPresent(HttpUtil.class.getClassLoader() ,"java.net.URLConnection")) {
            delegateToUse = new cn.zytx.common.http.converter.json.ConverterNativeSmartHttpClient();
        }
        delegate = delegateToUse;
    }
}

在springboot环境中,通过注入bean的方式使用,可以灵活地定制实现类及做一些额外的设置。

@Configuration
public class HttpConfig {
    @Bean("smartHttpClient")
    public SmartHttpClient smartHttpClient(){
        //如果要更换http的实现或者做更多的事情,可以对此bean进行配置
        return new NativeSmartHttpClient();
    }
}

详见:

https://gitee.com/xxssyyyyssxx/unihttp-all/tree/master/src/test/java/top/jfunc/http

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值