ApiClientUtils.java 9.87 KB
package com.xiniunet.service.railway.util;

import com.taobao.api.Constants;
import com.taobao.api.internal.util.StringUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.*;

/**
 * @author
 */
public class ApiClientUtils {

    private static final String API_URI = "/router2";

    private static final ApiClient API_CLIENT;

    static {
        API_CLIENT = new ApiClient(API_URI, "FEDA506D38D8E930626E850139E74E0C", "9019951CC31D86A31D2E911D4BE51142");
    }

    public static String execute(Map<String, String> request, String openMethod) throws Exception {
        return API_CLIENT.execute(request, openMethod);
    }

    private static class ApiClient {

        public String execute(Map<String, String> request, String openMethod) throws Exception {
            Map<String, String> requestParameters = new HashMap<>(request);

            Map<String, String> params = new HashMap<>();
            String ctype = "application/x-www-form-urlencoded;charset=" + StandardCharsets.UTF_8;
            String query = buildQuery(params);
            byte[] content = {};
            if (query != null) {
                content = query.getBytes(StandardCharsets.UTF_8);
            }

            Map<String, String> protocolMustParams = new HashMap<>();
            protocolMustParams.put(METHOD, openMethod);
            protocolMustParams.put(VERSION, "1.0");
            protocolMustParams.put(APP_KEY, appKey);
            protocolMustParams.put(TIMESTAMP, System.currentTimeMillis() + "");
            requestParameters.putAll(protocolMustParams);

            // protocolOptParams
            requestParameters.put(FORMAT, format);
            requestParameters.put(SIGN_METHOD, signMethod);
            requestParameters.put(PASSPORT_ID, null);

            protocolMustParams.put(SIGN, signTopRequestNew(requestParameters, appSecret));

            StringBuilder reqUrl = new StringBuilder(serverUrl);
            try {
                String sysMustQuery = buildQuery(protocolMustParams);
                String sysOptQuery = buildQuery(protocolMustParams);

                if (reqUrl.indexOf("?") != -1) {
                    reqUrl.append("&");
                } else {
                    reqUrl.append("?");
                }
                reqUrl.append(sysMustQuery);
                if (sysOptQuery != null && sysOptQuery.length() > 0) {
                    reqUrl.append("&").append(sysOptQuery);
                }
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            }

            HttpURLConnection conn = null;
            try {
                conn = getConnection(new URL(reqUrl.toString()), ctype, connectTimeout, readTimeout);
                try (OutputStream out = conn.getOutputStream()) {
                    out.write(content);
                    return getResponseAsString(conn);
                }
            } finally {
                if (conn != null) {
                    conn.disconnect();
                }
            }
        }


        // region

        private static final String APP_KEY = "app_key";
        private static final String FORMAT = "format";
        private static final String METHOD = "method";
        private static final String TIMESTAMP = "timestamp";
        private static final String VERSION = "v";
        private static final String SIGN = "sign";
        private static final String SIGN_METHOD = "sign_method";
        private static final String PASSPORT_ID = "passportId";
        private final String serverUrl;
        private final String appKey;
        private final String appSecret;
        private final String format;
        private final String signMethod;
        private final int connectTimeout;
        private final int readTimeout;

        public ApiClient(String serverUrl, String appKey, String appSecret) {
            this.format = "json";
            this.signMethod = "md5";
            this.connectTimeout = 3000;
            this.readTimeout = 60000;
            this.appKey = appKey;
            this.appSecret = appSecret;
            this.serverUrl = serverUrl;
        }

        // endregion

        private static String buildQuery(Map<String, String> params) throws IOException {
            if (params == null || params.isEmpty()) {
                return null;
            }
            StringBuilder query = new StringBuilder();
            Set<Map.Entry<String, String>> entries = params.entrySet();
            boolean hasParam = false;

            for (Map.Entry<String, String> entry : entries) {
                String name = entry.getKey();
                String value = entry.getValue();
                // 忽略参数名或参数值为空的参数
                if (StringUtils.areNotEmpty(name, value)) {
                    if (hasParam) {
                        query.append("&");
                    } else {
                        hasParam = true;
                    }
                    query.append(name).append("=").append(URLEncoder.encode(value, Constants.CHARSET_UTF8));
                }
            }
            return query.toString();
        }

        private static HttpURLConnection getConnection(URL url, String ctype, int connectTimeout, int readTimeout) throws IOException {
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setRequestProperty("Accept", "text/xml,text/javascript");
            conn.setRequestProperty("User-Agent", "xiniunet-sdk-java");
            conn.setRequestProperty("Content-Type", ctype);
            conn.setConnectTimeout(connectTimeout);
            conn.setReadTimeout(readTimeout);
            return conn;
        }

        protected static String getResponseAsString(HttpURLConnection conn) throws IOException {
            String charset = getResponseCharset(conn.getContentType());
            InputStream es = conn.getErrorStream();
            if (es == null) {
                return getStreamAsString(conn.getInputStream(), charset);
            } else {
                String msg = getStreamAsString(es, charset);
                if (StringUtils.isEmpty(msg)) {
                    throw new IOException(conn.getResponseCode() + ":" + conn.getResponseMessage());
                } else {
                    throw new IOException(msg);
                }
            }
        }

        private static String getResponseCharset(String ctype) {
            String charset = Constants.CHARSET_UTF8;

            if (!StringUtils.isEmpty(ctype)) {
                String[] params = ctype.split(";");
                for (String param : params) {
                    param = param.trim();
                    if (param.startsWith("charset")) {
                        String[] pair = param.split("=", 2);
                        if (pair.length == 2) {
                            if (!StringUtils.isEmpty(pair[1])) {
                                charset = pair[1].trim();
                            }
                        }
                        break;
                    }
                }
            }

            return charset;
        }

        private static String getStreamAsString(InputStream stream, String charset) throws IOException {
            try {
                Reader reader = new InputStreamReader(stream, charset);
                StringBuilder response = new StringBuilder();

                final char[] buff = new char[1024];
                int read = 0;
                while ((read = reader.read(buff)) > 0)
                {
                    response.append(buff, 0, read);
                }

                return response.toString();
            } finally {
                if (stream != null) {
                    stream.close();
                }
            }
        }

        private static String signTopRequestNew(Map<String, String> paramValues, String secret) throws IOException {

            StringBuilder sb = new StringBuilder();
            List<String> paramNames = new ArrayList<String>(paramValues.size());
            paramNames.addAll(paramValues.keySet());
            Collections.sort(paramNames);
            sb.append(secret);
            for (String paramName : paramNames) {
                sb.append(paramName).append(paramValues.get(paramName));
            }
            sb.append(secret);
            byte[] digests = encryptMd5(sb.toString());
            return byte2hex(digests);

        }

        private static byte[] encryptMd5(String data) throws IOException {
            byte[] bytes;
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                bytes = md.digest(data.getBytes(StandardCharsets.UTF_8));
            } catch (GeneralSecurityException gse) {
                String msg = getStringFromException(gse);
                throw new IOException(msg);
            }
            return bytes;
        }

        private static String getStringFromException(Throwable e) {
            String result = "";
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            PrintStream ps = new PrintStream(bos);
            e.printStackTrace(ps);
            try {
                result = bos.toString(Constants.CHARSET_UTF8);
            } catch (IOException ignore) {}
            return result;
        }

        private static String byte2hex(byte[] bytes) {
            StringBuilder sign = new StringBuilder();
            for(byte aByte : bytes) {
                String hex = Integer.toHexString(aByte & 0xFF);
                if(hex.length() == 1) {
                    sign.append("0");
                }
                sign.append(hex.toUpperCase());
            }
            return sign.toString();
        }

    }

}