1. 程式人生 > >Spring Boot 2關於http介面呼叫1

Spring Boot 2關於http介面呼叫1

使用HttpClient

HttpClient介面中常用方法

HttpResponse execute(HttpUriRequest request) throws IOException, ClientProtocolException;

HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException, ClientProtocolException;

HttpResponse execute(HttpHost target, HttpRequest request) throws IOException, ClientProtocolException;

HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException, ClientProtocolException;

<T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler) throws IOException, ClientProtocolException;

<T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context) throws IOException, ClientProtocolException;

<T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler) throws IOException, ClientProtocolException;

<T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context) throws IOException, ClientProtocolException;

HttpClient重要的實現類CloseableHttpClient

封裝HttpClient

public static <T> T doPostWithJson(String url, Object params, Class<T> t);
public static <T> T doPostWithJson(String url, Object params, TypeReference<T> typeReference);
public static <T> T doPostWithJson(String url, Object params, ParameterizedType parameterizedType);
public static <T> T doPostWithJson(String url, Object params, Class rawType, Type ownerType, Type... argType);

public static <T> T doGet(String url, Map params, Class<T> t);
public static <T> T doGet(String url, Map params, TypeReference<T> typeReference);
public static <T> T doGet(String url, Map params, ParameterizedType parameterizedType) ;
public static <T> T doGet(String url, Map params, Class rawType, Type ownerType, Type... argType);

// 這裡在JSON的反序列化採用了Jackson庫,下面是ObjectMapper幾個常用的反序列化方法
public <T> T readValue(String content, Class<T> valueType) throws IOException, JsonParseException, JsonMappingException;
public <T> T readValue(String content, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException;
public <T> T readValue(String content, JavaType valueType) throws IOException, JsonParseException, JsonMappingException;

// 泛型型別的構造
// List<String>型別構造
ParameterizedType listType = ParameterizedTypeImpl.make(List.class, new Type[]{String.class}, ArrayList.class);

// Map<String,Object>型別構造
ParameterizedType mapType = ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, Object.class}, HashMap.class);

// List<Map<String, Object>>型別構造
ParameterizedType listMapType = ParameterizedTypeImpl.make(List.class, new Type[]{mapType}, ArrayList.class);

// TypeReference型別構造
TypeReference<List<Map<String, Object>>> typeReference = new TypeReference<List<Map<String, Object>>>() {
      @Override
      public Type getType() {
          return listMapType;
      }
  };

進一步封裝HttpClient

public static void invoke(HttpRequestBuilder builder);
public static <T> T invoke(HttpRequestBuilder builder, Class<T> cls);
public static <T> T invoke(HttpRequestBuilder builder, TypeReference<T> typeReference);
public static <T> T invoke(HttpRequestBuilder builder, ParameterizedType parameterizedType);
public static <T> T invoke(HttpRequestBuilder builder, Class rawType, Type ownerType, Type... argType);

HttpRequestBuilder類構造請求引數

package org.ghost.springboot2.demo.common.http;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.auth.Credentials;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;
import org.ghost.springboot2.demo.util.ExceptionUtil;
import org.ghost.springboot2.demo.util.JacksonUtil;
import org.ghost.springboot2.demo.util.UriUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class HttpRequestBuilder {
    private static final transient Logger logger = LoggerFactory.getLogger(HttpRequestBuilder.class);
    private transient HttpRequestBase httpRequestBase;
    private transient Credentials credentials;

    public HttpRequestBase getHttpRequestBase() {
        return httpRequestBase;
    }

    public HttpRequestBuilder() {
    }

    public HttpRequestBuilder(final HttpMethod method, final String url) {
        this.build(method, url);
    }

    public HttpRequestBuilder build(final HttpMethod method, final String url) {
        switch (method) {
            case GET:
                httpRequestBase = new HttpGet(url);
                break;
            case POST:
                httpRequestBase = new HttpPost(url);
                break;
            case PUT:
                httpRequestBase = new HttpPut(url);
                break;
            case DELETE:
                httpRequestBase = new HttpDelete(url);
                break;
            case PATCH:
                httpRequestBase = new HttpPatch(url);
                break;
            case OPTIONS:
                httpRequestBase = new HttpOptions(url);
                break;
            case HEAD:
                httpRequestBase = new HttpHead(url);
                break;
            case TRACE:
                httpRequestBase = new HttpTrace(url);
                break;
            default:
                ExceptionUtil.throwRuntimeException("HttpRequestBuilder.build", "方法未實現", logger);
                break;
        }

        return this;
    }

    /**
     * 新增請求頭
     *
     * @param name
     * @param value
     * @return
     */
    public HttpRequestBuilder addHeader(String name, String value) {
        if (StringUtils.isNotEmpty(name) && StringUtils.isNotBlank(value)) {
            httpRequestBase.addHeader(name, value);
        }
        return this;
    }

    /**
     * 新增請求頭
     *
     * @param headers
     * @return
     */
    public HttpRequestBuilder addHeaders(Map<String, String> headers) {
        if (MapUtils.isNotEmpty(headers)) {
            headers.forEach(
                    (key, value) -> {
                        if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
                            httpRequestBase.addHeader(key, value);
                        }
                    });
        }
        return this;
    }

    /**
     * 拼接url引數
     *
     * @param name
     * @param value
     * @return
     */
    public HttpRequestBuilder addUrlPara(String name, String value) {
        if (StringUtils.isNotBlank(name)) {
            if (httpRequestBase.getURI().toString().contains("?")) {
                this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "&" + name + "=" + value));
            } else {
                this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "?" + name + "=" + value));
            }
        }
        return this;
    }

    /**
     * 拼接url引數
     *
     * @param param
     * @return
     */
    public HttpRequestBuilder addUrlPara(Object param) {
        if (param != null) {
            String value = UriUtil.urlParaEncode(param);
            if (StringUtils.isNotBlank(value)) {
                if (httpRequestBase.getURI().toString().contains("?")) {
                    this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "&" + value));
                } else {
                    this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "?" + value));
                }
            }
        }
        return this;
    }


    /**
     * 拼接url引數
     *
     * @param params
     * @return
     */
    public HttpRequestBuilder addUrlPara(Map<String, String> params) {
        if (MapUtils.isNotEmpty(params)) {
            StringBuilder builder = new StringBuilder();
            params.forEach((key, value) -> {
                if (StringUtils.isNotBlank(key)) {
                    try {
                        if (builder.length() > 0) {
                            builder.append("&");
                        }
                        builder.append(URLEncoder.encode(key, "UTF-8")).append("=").append(URLEncoder.encode(value, "UTF-8"));
                    } catch (UnsupportedEncodingException e) {
                        logger.error("*****HttpRequestBuilder.addUrlPara:{}", e);
                    }
                }
            });

            if (builder.length() > 0) {
                if (httpRequestBase.getURI().toString().contains("?")) {
                    this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "&" + builder.toString()));
                } else {
                    this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "?" + builder.toString()));
                }
            }
        }

        return this;
    }

    /**
     * Form表單鍵值對引數
     *
     * @param params
     * @return
     * @throws UnsupportedEncodingException
     */
    public HttpRequestBuilder addFormPara(Map<String, String> params) throws UnsupportedEncodingException {
        if (this.httpRequestBase instanceof HttpEntityEnclosingRequestBase && MapUtils.isNotEmpty(params)) {
            List<NameValuePair> nameValuePairs = params.entrySet().stream()
                    .filter(it -> StringUtils.isNotBlank(it.getKey()))
                    .map(it -> new BasicNameValuePair(it.getKey(), it.getValue()))
                    .collect(Collectors.toList());

            ((HttpEntityEnclosingRequestBase) httpRequestBase).setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
        }

        return this;
    }

    /**
     * Body存放json資料
     *
     * @param body
     * @return
     */
    public HttpRequestBuilder addBody(Object body) {
        if (this.httpRequestBase instanceof HttpEntityEnclosingRequestBase) {
            StringEntity stringEntity = new StringEntity(Objects.requireNonNull(JacksonUtil.nonNull().toJson(body)), Charset.forName("UTF-8"));
            ((HttpEntityEnclosingRequestBase) httpRequestBase).setEntity(stringEntity);
        }

        return this;
    }

    public Credentials getCredentials() {
        return credentials;
    }

    public HttpRequestBuilder setCredentials(Credentials credentials) {
        this.credentials = credentials;
        return this;
    }
}

單元測試

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class HttpClientHelperTest {
    @Autowired
    private TaskExecutorConfig taskExecutorConfig;

    /**
     * HttpClient
     */
    @Test
    public void test1() {
        long begin = System.currentTimeMillis();

        HttpRequestBuilder httpRequestBuilder = new HttpRequestBuilder()
                .build(HttpMethod.GET, "http://localhost:9999/demo/hello")
                .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);

        HttpRspDTO<String> rspDTO = HttpClientHelper.invoke(httpRequestBuilder, HttpRspDTO.class, null, String.class);

        long end = System.currentTimeMillis();
        System.out.println("*****消耗時間(秒):" + (end - begin) / 1000.0);
        System.out.println(rspDTO);
    }

    /**
     * 自定義執行緒池 + HttpClient
     */
    @Test
    public void test2() {
        long begin = System.currentTimeMillis();
        List<Future<HttpRspDTO<String>>> futureList = new ArrayList<Future<HttpRspDTO<String>>>();
        for (int i = 0; i < 100; i++) {
            HttpRequestBuilder httpRequestBuilder = new HttpRequestBuilder()
                    .build(HttpMethod.GET, "http://localhost:9999/demo/hello")
                    .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);

            Future<HttpRspDTO<String>> future = taskExecutorConfig.getAsyncTaskExecutor().submit(new Callable<HttpRspDTO<String>>() {
                @Override
                public HttpRspDTO<String> call() throws Exception {
                    return HttpClientHelper.invoke(httpRequestBuilder, HttpRspDTO.class, null, String.class);
                }
            });
            futureList.add(future);
        }

        List<String> resultList = new ArrayList<String>();
        for (Future<HttpRspDTO<String>> future : futureList) {
            try {
                HttpRspDTO<String> rspDTO = future.get();
                if (rspDTO != null && Objects.equals(Boolean.TRUE, rspDTO.getSuccess())) {
                    resultList.add(rspDTO.getData());
                }
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }

        long end = System.currentTimeMillis();
        System.out.println("*****消耗時間(秒):" + (end - begin) / 1000.0);
        System.out.println(resultList.size());
    }

    /**
     * ParallelStream + HttpClient
     */
    @Test
    public void test3() {
        long begin = System.currentTimeMillis();

        List<String> resultList = IntStream.range(0, 100)
                .parallel()
                .mapToObj(it -> {
                    HttpRequestBuilder httpRequestBuilder = new HttpRequestBuilder()
                            .build(HttpMethod.GET, "http://localhost:9999/demo/hello")
                            .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
                            .addUrlPara("msg", String.valueOf(it));
                    HttpRspDTO<String> rspDTO = HttpClientHelper.invoke(httpRequestBuilder, HttpRspDTO.class, null, String.class);
                    if (rspDTO != null && Objects.equals(Boolean.TRUE, rspDTO.getSuccess())) {
                        return rspDTO.getData();
                    } else {
                        return null;
                    }
                }).filter(Objects::nonNull).collect(Collectors.toList());

        long end = System.currentTimeMillis();
        System.out.println("*****消耗時間(秒):" + (end - begin) / 1000.0);
        System.out.println(resultList.size());
    }
}

原始碼位置