基于SpringBoot RestTemplate封装的curl请求类库

小菜鸟
发布于 2023-12-22 / 61 阅读
2
1

基于SpringBoot RestTemplate封装的curl请求类库

1、RestTemplate是什么

  • 传统情况下在java代码里访问restful服务,一般使用Apache的HttpClient。不过此种方法使用起来太过繁琐。spring提供了一种简单便捷的模板类来进行操作,这就是RestTemplate。

2、封装使用

package com.recallg.demo.utils;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URLEncoder;
import java.util.*;
import java.util.zip.GZIPInputStream;

import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;

/**
 * Curl Api请求类库
 */
@Slf4j
public class Curl {

    // 请求结果
    private String result = "";

    /**
     * RestTemplate 请求构造内部类
     */
    public static class Builder {

        // 请求URL
        private String url;

        // basic auth用户名
        private String userName;

        // basic auth密码
        private String passWord;

        // 请求方式 默认为GET
        private HttpMethod methodType = GET;

        // 请求参数
        private HashMap<String, String> paramMap;

        // 请求header头
        private HashMap<String, String> headerMap;

        // RestTemplate 实例
        private RestTemplate client;

        // header头实例
        private HttpHeaders headers;

        // 请求结果
        private String result;

        public Builder(String url) {
            this.url = url;
        }

        /**
         * basic auth 认证类型请求
         * @param url
         * @param userName
         * @param passWord
         */
        public Builder(String url, String userName, String passWord) {
            this.url = url;
            this.userName = userName;
            this.passWord = passWord;
        }

        /**
         * 添加参数
         * @param key               参数key
         * @param value             参数内容
         * @return                  Builder
         */
        public Builder addParam(String key, String value) {
            if (paramMap == null) {
                paramMap = new LinkedHashMap<>(16);
            }
            paramMap.put(key, value);
            return this;
        }

        /**
         * 添加header参数
         * @param key               参数key
         * @param value             参数内容
         * @return                  Builder
         */
        public Builder addHeader(String key, String value) {
            if (headerMap == null) {
                headerMap = new LinkedHashMap<>(16);
            }
            headerMap.put(key, value);
            return this;
        }

        /**
         * GET 请求
         * @return                  Curl
         */
        public Curl get() {
            this.methodType = GET;
            this.getResponse(MediaType.APPLICATION_FORM_URLENCODED);
            return new Curl(this);
        }

        /**
         * post 请求
         * @return                  Curl
         */
        public Curl post() {
            this.methodType = POST;
            this.getResponse(MediaType.APPLICATION_FORM_URLENCODED);
            return new Curl(this);
        }

        /**
         * raw 方式提交json 请求
         * @return                  Curl
         */
        public Curl postRaw() {
            HashMap<String, Object> paramRawMap = new HashMap<>();
            return this.raw(paramRawMap);
        }

        /**
         * raw 方式提交json 请求
         * @param paramRawMap       Map数据
         * @return                  Curl
         */
        public Curl postRaw(HashMap<String, Object> paramRawMap) {
            return this.raw(paramRawMap);
        }

        private Curl raw(HashMap<String, Object> paramRawMap) {
            client = new RestTemplate();
            client.setErrorHandler(new RestErrorHandler());
            headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            this.setHeadersMapData();
            this.responseRawExchange(JSON.toJSONString(paramRawMap));
            return new Curl(this);
        }

        public SimpleClientHttpRequestFactory getFactory() {
            SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
            //单位为ms
            factory.setReadTimeout(10 * 1000);
            //单位为ms
            factory.setConnectTimeout(30 * 1000);
            // 代理的url网址或ip, port端口
            InetSocketAddress address = new InetSocketAddress("36.110.168.141", 9039);
            Proxy proxy = new Proxy(Proxy.Type.HTTP, address);
            factory.setProxy(proxy);
            return factory;
        }

        /**
         * 初始化请求体
         * @param type              请求类型
         */
        private void getResponse(MediaType type) {
            client = new RestTemplate();
            client.setErrorHandler(new RestErrorHandler());
            headers = new HttpHeaders();
            headers.setContentType(type);
            this.setHeadersMapData();
            MultiValueMap<String, String> params = this.setHttpMethodParamsMap();
            this.responseExchange(params);
        }

        /**
         * 设置header头数据
         */
        private void setHeadersMapData() {
            if (headerMap != null){
                headerMap.forEach((k, v) -> {
                    this.headers.set(k, v);
                });
            }

            // 设置basic auth请求方式认证信息
            if (this.userName != null && this.passWord != null) {
                String secretKey = this.userName + ":" + this.passWord;
                String authValue = "Basic " + Base64.getEncoder()
                        .encodeToString(secretKey.getBytes());
                this.headers.set("Authorization", authValue);
            }
        }

        /**
         * 组装请求体参数
         * @return                  MultiValueMap<String, String>
         */
        private MultiValueMap<String, String> setHttpMethodParamsMap() {
            MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
            if (this.methodType.equals(GET)) {
                if (this.paramMap != null) {
                    String _UrlParams = getUrlParamsByMap(this.paramMap);
                    this.url = this.url + "?" + _UrlParams;
                }

                if (this.paramMap != null) {
                    this.paramMap.forEach((k, v) -> {
                        params.put(k, Collections.singletonList(v));
                    });
                }
            } else if (this.methodType.equals(POST)) {
                if (this.paramMap != null) {
                    this.paramMap.forEach((k, v) -> {
                        params.put(k, Collections.singletonList(v));
                    });
                }
            }
            return params;
        }

        /**
         * 执行Curl请求操作
         * @param params            请求体参数
         */
        private void responseExchange(MultiValueMap<String, String> params) {
            HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, this.headers);
            // 执行HTTP请求,将返回的结构使用spring ResponseEntity处理http响应
            ResponseEntity<byte[]> responseEntity = this.client.exchange(this.url, this.methodType, requestEntity, byte[].class);
            String contentEncoding = responseEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);
            int httpCode            = responseEntity.getStatusCodeValue();
            String httpCodeValue    = responseEntity.getStatusCode().toString();
            log.info("状态码:{}", httpCodeValue);
            try {
                if ("gzip".equals(contentEncoding)) {
                    // gzip解压服务器的响应体
                    byte[] data = unGZip(new ByteArrayInputStream(responseEntity.getBody()));
                    // log.info(new String(data, StandardCharsets.UTF_8));
                    this.result = new String(data);
                } else {
                    // 其他编码暂时不做处理(如果需要处理其他编码请自行扩展)
                    this.result = new String(responseEntity.getBody());
                }
            } catch (NullPointerException e) {
                log.error("请求错误: {}", e.getMessage());
                this.result = httpCodeValue;
            }
        }

        /**
         * 执行Curl Raw JSON请求操作
         * @param params            请求体参数
         */
        private void responseRawExchange(String params) {
            HttpEntity<String> requestEntity = new HttpEntity<>(params, this.headers);
            // 执行HTTP请求,将返回的结构使用spring ResponseEntity处理http响应
            ResponseEntity<byte[]> responseEntity = this.client.postForEntity(this.url, requestEntity, byte[].class);
            String contentEncoding = responseEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);

            if ("gzip".equals(contentEncoding)) {
                // gzip解压服务器的响应体
                byte[] data = unGZip(new ByteArrayInputStream(responseEntity.getBody()));
                this.result = new String(data);
            } else {
                // 其他编码暂时不做处理(如果需要处理其他编码请自行扩展)
                this.result = new String(responseEntity.getBody());
            }
        }

        /**
         * Gzip解压缩
         * @param inputStream      数据流
         * @return                 byte[]
         */
        private byte[] unGZip(InputStream inputStream) {
            byte[] result = null;
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            try {
                try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {
                    byte[] buf = new byte[4096];
                    int len = -1;
                    while ((len = gzipInputStream.read(buf, 0, buf.length)) != -1) {
                        byteArrayOutputStream.write(buf, 0, len);
                    }
                    result = byteArrayOutputStream.toByteArray();
                } finally {
                    byteArrayOutputStream.close();
                }
            } catch (IOException e) {
                log.error("unGZip error :", e);
            }
            return result;
        }

        /**
         * 组装GET参数
         * @param params            参数
         * @return                  String
         */
        private String getUrlParamsByMap(Map<String, String> params) {
            List<String> keys = new ArrayList<String>(params.keySet());
            Collections.sort(keys);
            String prestr = "";
            try {
                for (int i = 0; i < keys.size(); i++) {
                    String key = keys.get(i);
                    String value = params.get(key);
                    value = URLEncoder.encode(value, "UTF-8");
                    if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
                        prestr = prestr + key + "=" + value;
                    } else {
                        prestr = prestr + key + "=" + value + "&";
                    }
                }
            } catch (UnsupportedEncodingException e) {
                log.error("GET params error: {}", e);
            }
            return prestr;
        }
    }

    /**
     * RestTemplate 异常处理
     */
    public static class RestErrorHandler implements ResponseErrorHandler {

        /**
         * 判断返回结果response是否是异常结果
         * 主要是去检查response 的HTTP Status
         * 仿造DefaultResponseErrorHandler实现即可
         */
        @Override
        public boolean hasError(ClientHttpResponse response) throws IOException {
            int rawStatusCode = response.getRawStatusCode();
            HttpStatus statusCode = HttpStatus.resolve(rawStatusCode);
            return (statusCode != null ? statusCode.isError(): hasError(rawStatusCode));
        }

        protected boolean hasError(int unknownStatusCode) {
            HttpStatus.Series series = HttpStatus.Series.resolve(unknownStatusCode);
            return (series == HttpStatus.Series.CLIENT_ERROR || series == HttpStatus.Series.SERVER_ERROR);
        }

        @Override
        public void handleError(ClientHttpResponse response) throws IOException {
            // 里面可以实现你自己遇到了Error进行合理的处理
            //TODO 将接口请求的异常信息持久化
        }
    }

    public Curl(Builder builder) {
        this.result = builder.result;
    }

    public String build() {
        return this.result;
    }

}

3、使用方法

1、GET方式

String result = new Curl.Builder("http://api.test.com/list")
                .addParam("test", "A")
                .addParam("ssss", "B")
                .addHeader("Content-Type", "application/json; charset=utf-8")
                .get().build();
log.info("测试GET:{}", result);

2、POST方式

String result = new Curl.Builder("http://api.test.com/add")
                .addParam("test", "A")
                .addParam("ssss", "B")
                .addHeader("Content-Type", "application/json; charset=utf-8")
                .post().build();
log.info("测试POST:{}", result);

3、POST JSON方式(RAW)

ArrayList arr = new ArrayList<>();
arr.add("test params");
HashMap<String, Object> params = new HashMap<>();
params.put("tags", arr);

String result = new Curl.Builder("http://api.test.com/test")
                .addHeader("Content-Type", "application/json; charset=utf-8")
                .postRaw(params).build();
log.info("测试POST JSON:{}", result);

4、POST/GET 方式basic auth验证

String url = "http://api.test.com/test";
result = new Curl.Builder(url, "username", "password")
                .addHeader("Content-Type", "application/json; charset=utf-8")
                .post().build();
log.info("测试POST/GET basic auth:{}", result);


评论