import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class ClientDemo {

    private static String PRIVATE_KEY =
            "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCV7fBo/m2NINtxHxh7ovXAp0PxqgSLqIDgropuCQBmcYF1fTF1wbPFrrjtEXRiipuutfChlaF6ZQeq9aOJXe8VJM2RsHIpmsXQwjjtZLcNSD1klC0sUDuasZpG3eo+f3a8DXbC5p+E7PoBo4cZYBdYoxZp5VgNZgDc0BvebIhZChWUu+Qsm/13Ccl4jmWl2aEX/FCioc3f5PEOlcOKfR5tollYOJsghKX/gNrC/+URc6q+EUCtIczYLHZYFsOcLZ2XzjMueriPpUYOyDapmr6hvhkdFo2dOC3fwyCiVZe8vp+g74qDSQn8j1cmxfouY4PcbGxmny+vNSm0Yf/FP52zAgMBAAECggEANWuVKGPXNtzJM5In0A2tUJqIe/ffLL+6Q9QM4M32RYoV3X3g/Jsq6bmqjFWWyXGnrOWIupos8gZDaCejwFMm17rIQCvFUYujBhHd5L/o9SOTNF4ThmGEC0dSuANj7ibOcIy/jwxLNDqXjbPtdB4n014wo0SjTgrVLdg8xdCX+FkxkAoLzVeg2aJBtuPybudKdip8cP5CcdIH5uJ8Fvac9NYEA5p8UoiIdPGIjwNXO27uZl7XYN7+Wwfpx8Vu0aTVu++qh4pJldvnTBsGhURZO6MuictAOJa+YotSVBrdRiTg8IEUIogbVpzDdUv9/L4gTuDVi/QPgWGKBBlkhCqcOQKBgQDguTLamAQLXvhZTPhfQf4uu4IWv18SJEp2Ulnoe0BefWl1qnd8J4IG4iEbW2NjJ34ybhBTcv3R9DnlNgFVgus6UilgGpV6LhRucJByORq8qH8KekDeJv+gc60hMBE4iWfVj4dz0x1nsodMrdwXK3myjRf0+EC6CCA6mp/CBWAgHQKBgQCqy9zA7Gzm/xfK/4doVhcuSUJ40mF4GbSplOejIbajgYy8rRSEsDpFPqh+VSO8Jwsq9t7pLIUwB0dbmoiDt5TnMaG6Uhou6Rj7DP8oaLTpCFwj8ttdN9ogloyhmOj1CJTGIMbV/7/HtZyJI79CTkiasQgi9moslB11fZhxaZ/sDwKBgBTkgvrZuT6JZNOAmXLZwtT7b9vHjQI1x4p6m4tGsjRWupBK+fLcBXW4XlWZyIK2cEAmBXSMs1Zqu1s5CyS1GEOC0f/yWMVUNWgTJQrJjlfN3onN1ewReiCjwIveWSuFctbjEjfNf+VdLsENRPIOg7D69yg6UGI7USvBpmq2bzptAoGAWuyme8ohe6PnvbjlFCVot8pmab3OB8rfg7vyyMSk30yTaMpXdv/+NWjS+FZI7Nx4NIoyRz3dNaFaWqjc7gooah/g8jjNGZYcJ2JW3+NGFBzQOI8MOwcFx31+JnUp53CHCybd04UQSrgjOlreceUM/9Uo+Lvn8A111VtkcVQCv/8CgYEAu0AEA4uKNeJ4prvFlDah7u9OrAeyBxp2HftoUi0jQIOqRvMZmFi/0R2htYGqetOGKw346r8mhcdpuNDr3kYbVfaSexBNrRHHUVAoCgWj5hRT99OBsYLfOr1iohdFE4UnInJlZZsvepUxUYkGC6vlfF3I6DJT3ZG+QXAFWXpLyqQ=";

    private static String PUBLIC_KEY =
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAle3waP5tjSDbcR8Ye6L1wKdD8aoEi6iA4K6KbgkAZnGBdX0xdcGzxa647RF0YoqbrrXwoZWhemUHqvWjiV3vFSTNkbByKZrF0MI47WS3DUg9ZJQtLFA7mrGaRt3qPn92vA12wuafhOz6AaOHGWAXWKMWaeVYDWYA3NAb3myIWQoVlLvkLJv9dwnJeI5lpdmhF/xQoqHN3+TxDpXDin0ebaJZWDibIISl/4Dawv/lEXOqvhFArSHM2Cx2WBbDnC2dl84zLnq4j6VGDsg2qZq+ob4ZHRaNnTgt38MgolWXvL6foO+Kg0kJ/I9XJsX6LmOD3GxsZp8vrzUptGH/xT+dswIDAQAB";

    private static final String SIGN_FIELD = "bsign";

    public static void main(String[] args) throws Exception {
        Map<String, String> urlParams = new HashMap<>();
        urlParams.put("appId", "xxx");
        urlParams.put("appKey", "xxx");
        urlParams.put("version", "1");
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        urlParams.put("timestamp", timestamp);
        System.out.println("timestamp = " + timestamp);
        urlParams.put("method", "beicang.outer.brand.list.get");
        urlParams.put("pageNo", "1");
        urlParams.put("pageSize", "20");

        Map<String, Object> bodyParams = new HashMap<>();

        // 私钥签名
        String sign = URLEncoder.encode(sign(urlParams, bodyParams, PRIVATE_KEY), "UTF-8");
        urlParams.put(SIGN_FIELD, sign);
        System.out.println("sign = " + sign);

        // 公钥验签
        boolean verify = checkSign(urlParams, bodyParams, PUBLIC_KEY, URLDecoder.decode(sign, "UTF-8"));
        System.out.println("verify = " + verify);

        // 获取GET结果
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : urlParams.entrySet()) {
            sb.append(entry.getKey() + "=" + entry.getValue() + "&");
        }
        String url = "http://gw.beicang.com/openapi?" + sb.toString();
        if (url.endsWith("%")) url = url.substring(0, url.length()-1);
        String result = new HttpClient().doGet(url);
        System.out.println(result);
    }

    public static String sign(Map<String, String> urlParams, Map<String, Object> bodyParams, String privateKey)
            throws Exception {
        String signContent = buildSignContent(urlParams, bodyParams);
        Signature signature = Signature.getInstance("SHA256WithRSA");
        PrivateKey privateKey1 =
                KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(base64Decode(privateKey.getBytes(
                        StandardCharsets.UTF_8))));
        signature.initSign(privateKey1);
        signature.update(signContent.getBytes(StandardCharsets.UTF_8));
        byte[] sign = signature.sign();

        return new String(base64Encode(sign));
    }

    private static String buildSignContent(Map<String, String> urlParams, Map<String, Object> bodyParams) {
        StringBuilder signContent = new StringBuilder();
        if (urlParams != null && urlParams.size() > 0) {
            String[] keys = urlParams.keySet().toArray(new String[0]);
            Arrays.sort(keys);
            for (String key : keys) {
                if (!SIGN_FIELD.equals(key)) {
                    signContent.append(key).append(urlParams.get(key));
                }
            }
        }
        if (bodyParams != null && bodyParams.size() > 0) {
            String[] keys = bodyParams.keySet().toArray(new String[0]);
            Arrays.sort(keys);
            for (String key : keys) {
                if (!SIGN_FIELD.equals(key)
                        && (bodyParams.get(key) instanceof Number || bodyParams.get(key) instanceof String ||
                        bodyParams.get(key) instanceof Boolean)) {
                    signContent.append(key).append(bodyParams.get(key));
                }
            }
        }
        return signContent.toString();
    }

    public static boolean checkSign(Map<String, String> urlParams, Map<String, Object> bodyParams, String publicKey,
                                    String sign) throws Exception {
        String signContent = buildSignContent(urlParams, bodyParams);
        PublicKey publicKey1 = KeyFactory.getInstance("RSA")
                .generatePublic(new X509EncodedKeySpec(base64Decode(publicKey.getBytes(StandardCharsets.UTF_8))));
        Signature signature = Signature.getInstance("SHA256WithRSA");
        signature.initVerify(publicKey1);
        signature.update(signContent.getBytes(StandardCharsets.UTF_8));
        return signature.verify(base64Decode(sign.getBytes(StandardCharsets.UTF_8)));
    }

    public static byte[] base64Encode(byte[] src) {
        return src.length == 0 ? src : Base64.getEncoder().encode(src);
    }

    public static byte[] base64Decode(byte[] src) {
        return src.length == 0 ? src : Base64.getDecoder().decode(src);
    }

    static class HttpClient {
        public String doGet(String httpurl) {
            HttpURLConnection connection = null;
            InputStream is = null;
            BufferedReader br = null;
            String result = null;
            try {
                URL url = new URL(httpurl);
                connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(1000);
                connection.setReadTimeout(1000);
                connection.connect();
                if (connection.getResponseCode() == 200) {
                    is = connection.getInputStream();
                    br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
                    StringBuilder sb = new StringBuilder();
                    String temp;
                    while ((temp = br.readLine()) != null) {
                        sb.append(temp);
                        sb.append("\r\n");
                    }
                    result = sb.toString();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != br) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (null != is) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (connection != null) {
                    connection.disconnect();
                }
            }
            return result;
        }
        public String doPost(String httpUrl, String param) {
            HttpURLConnection connection = null;
            InputStream is = null;
            OutputStream os = null;
            BufferedReader br = null;
            String result = null;
            try {
                URL url = new URL(httpUrl);
                connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("POST");
                connection.setConnectTimeout(1000);
                connection.setReadTimeout(1000);
                connection.setDoOutput(true);
                connection.setDoInput(true);
                connection.setRequestProperty("Content-Type", "application/json");
                connection.setRequestProperty("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
                os = connection.getOutputStream();
                os.write(param.getBytes());
                if (connection.getResponseCode() == 200) {
                    is = connection.getInputStream();
                    br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
                    StringBuilder sb = new StringBuilder();
                    String temp;
                    while ((temp = br.readLine()) != null) {
                        sb.append(temp);
                        sb.append("\r\n");
                    }
                    result = sb.toString();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != br) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (null != os) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (null != is) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (connection != null) {
                    connection.disconnect();
                }
            }
            return result;
        }
    }
}
