【项目】关于汇付宝支付对接

前言

本文是结合第三方demo提供,然后整理的代码,主要涉及的接口有,签约,支付,流程是,用户输入身份证、银行卡等信息,调用平台接口,返回url,在url发送短信确认签约,然后异步回调确认是否签约,
成功则返回唯一标识,然后通过唯一标识调用支付接口,进行支付。
请添加图片描述
请添加图片描述

引入maven

   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
   </dependency>

   <dependency>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
       <optional>true</optional>
   </dependency>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <scope>test</scope>
   </dependency>

   <dependency>
       <groupId>org.codehaus.jackson</groupId>
       <artifactId>jackson-mapper-asl</artifactId>
       <version>1.9.12</version>
   </dependency>

   <dependency>
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpclient</artifactId>
       <version>4.5.12</version>
   </dependency>
   
   <dependency>
       <groupId>commons-codec</groupId>
       <artifactId>commons-codec</artifactId>
       <version>1.11</version>
   </dependency>

   <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-lang3</artifactId>
   </dependency>

   <dependency>
       <groupId>org.bouncycastle</groupId>
       <artifactId>bcprov-jdk15on</artifactId>
       <version>1.62</version>
   </dependency>

   <dependency>
       <groupId>com.alibaba</groupId>
       <artifactId>fastjson</artifactId>
       <version>1.2.73</version>
   </dependency>

   <dependency>
       <groupId>org.dom4j</groupId>
       <artifactId>dom4j</artifactId>
       <version>2.1.1</version>
   </dependency>

项目结构

目录结构
在这里插入图片描述

常量类

通用常量

public class Constants {

    /**
     * UTF-8 字符集(小写)
     */
    public static final String UTF8 = "utf-8";

    /**
     * GBK 字符集
     */
    public static final String GBK = "GBK";


}
public class HeePayConst {


    //商户私钥
    public static final String MC_PRIVATE_KEY = "";
    // 商户公钥
    public static final String MC_PUBLIC_KEY = "";
    // 汇付宝公钥
    public static final String HEEPAY_PUBLIC_KEY = "";
    // 汇付宝商户号
    public static final String MERCHANT_ID = "";

	

    // 查看卡bind密钥 
    public static final String SIGN_KEY = "";

    /**
     * 请求方法
     */
    public static final String REQUEST_URL = "http://locahost:8080";

    /**
     * 商户平台用户ip(真实)服务器ip
     * ip地址
     */
    public static final String FROM_USER_IP= "";

    /**
     * 银行卡类型:0
     */
    public static final String BANK_CARD_TYPE = "0";

    /**
     * 版本号
     */
    public static final String VERSION = "1.0";

    // ================================ 请求method ======================================================
    /**
     * 请求头:method
     * 申请签约
     */
    public static final String SIGN_SMS = "heepay.agreement.bank.sign.page";

    /**
     * 请求头:method
     * 签约查询
     */
    public static final String QUERY_SIGN = "heepay.agreement.bank.sign.query";

    // ========================================== 平台自定义api =============================================
    // 签约异步回调
    public static final String SING_NOTIFY_URL = REQUEST_URL + "/card_notify";
    // 签约成功返回前端地址
    public static final String SING_RESULT_URL = REQUEST_URL +"/card_success";
    // 支付成功异步处理
    public static final String PAY_NOTIFY_URL = REQUEST_URL + "/notify";
    // 支付成功前端页面
    public static final String PAY_RESULT_URL = REQUEST_URL +"/success";

    //=========================================== 请求地址 ======================================================
    // 签约url
    public static final String SING_SERVER_URL = "https://Pay.Heepay.com/API/PageSign/Index.aspx";
    // 发送支付短信
    public static final String SEND_PAY_SMS_URL = "Https://Pay.Heepay.com/WithholdAuthPay/SendPaySMS.aspx";
    // 确认支付
    public static final String CONFIRM_PAY_URL = "Https://Pay.Heepay.com/WithholdAuthPay/ConfirmPay.aspx";
    // 解约接口
    public static final String CANCEL_AUTH_URL = "https://Pay.Heepay.com/WithholdAuthPay/CancelAuth.aspx";
    // 卡bin查询
    public static final String QUERY_BANK_CARD_INFO_URL = "https://Pay.heepay.com/API/PayTransit/QueryBankCardInfo.aspx";

    public static final String BANK_CERITFY_URL = "https://www.heepay.com/API/Merchant/BankCeritfy.aspx";
    // 支付查询订单
    public static final String QUERY_ORDER_URL = "https://query.heepay.com/Payment/Query.aspx";
    // 代付查询订单
    public static final String QUERY_TRANSFER_URL = "https://Pay.heepay.com/API/PayTransit/QueryTransfer.aspx";

}

request

@Data
public class BasePayRequest {
	//
    private String agent_id;
    // 
    private String encrypt_data;
    // 
    private String sign;
}
@Data
public class BaseRequest {
	// 具体业务接口名称
    private String method;
    // 版本号:固定值 1.0
    private String version;
    // 商户编号
    private String merch_id;
    // Json参数集合
    private String biz_content;
    // 时间戳格式(注意有空格)yyyy-MM-dd HH:mm:ss
    private String timestamp;
    // 公共请求参数&拼接签名串(a-z),此参数串RSA签名结果。biz_content传原数据
    private String sign;
}

@Data
public class CancelAuthRequest extends BasePayRequest {
    private String version;
    private String hy_auth_uid;// 授权码
}

@Data
public class CertRequest {
    private String method;
    private String version;
    private String serverUrl;
    private String privateKeyStr;
    private String publicKeyStr;
    private String merchantId;
}

@Data
public class ConfirmPayRequest extends BasePayRequest {
    // 子商户号,传了要参与签名
    private String ref_agent_id;
    private String version;
    private String hy_token_id;
    private String verify_code;

}
@Data
public class QuerySignRequest {
    private String out_trade_no;
}

@Data
public class SendPaySMSRequest extends BasePayRequest {

    private String ref_agent_id;// 否 子商户号,传了要参与签名
    private String version;// int 版本号,固定为1
    private String agent_bill_id;//  商户订单号
    private String agent_bill_time;// 商户订单时间,格式为“yyyyMMddhhmmss”
    private String pay_amt;// decimal 支付金额,单位:元,保留二位小数
    private String goods_name;// 商品名称
    private String hy_auth_uid;// 授权码
    private String user_ip; // ip地址
    private String notify_url; // 是
    private String return_url;// 否

}

@Data
public class SignRequest {
    private String sub_merch_id;
    private String out_trade_no;
    private String out_trade_time;
    private String merch_user_id;
    private String bank_card_type;
    private String bank_type;
    private String notify_url;
    private String return_url;
    private String from_user_ip;
    private String bank_card_no;
    private String bank_user_name;
    private String mobile;
    private String cert_no;
}

reponse

@Data
public class BaseResponse {

    private String code;
    private String msg;
    private String sub_code;
    private String sub_msg;
    private String data;
    private String sign;
}
@Data
public class QuerySignResponse extends BaseResponse{
    private String merch_id;
    private String out_trade_no;
    private String out_trade_time;
    private String sign_no;
    private String mobile;
    private String cert_no;
    private String bank_name;
    private String bank_type;
    private String bank_card_no;
    private String bank_user_name;
}
@Data
public class SendPayResponse {

    private String agent_id;
    private String sign;
    private String encrypt_data;
}

@Data
public class SendPaySMSResponse {
    private String agent_id;
    private String hy_token_id;
    private String ret_code;
    private String ret_msg;
}

@Data
public class SignResponse extends BaseResponse{
    private String merch_id;
    private String out_trade_no;
    private String out_trade_time;
    private String sign_url;
    private String sign_no;

}

utils

  • a
public final class a {
    private static final byte[] a = new byte[]{65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47};
    private static final byte[] b = new byte[128];

    static {
        int var0;
        for(var0 = 0; var0 < 128; ++var0) {
            b[var0] = -1;
        }

        for(var0 = 65; var0 <= 90; ++var0) {
            b[var0] = (byte)(var0 - 65);
        }

        for(var0 = 97; var0 <= 122; ++var0) {
            b[var0] = (byte)(var0 - 97 + 26);
        }

        for(var0 = 48; var0 <= 57; ++var0) {
            b[var0] = (byte)(var0 - 48 + 52);
        }

        b[43] = 62;
        b[47] = 63;
    }

    public a() {
    }

    public static String a(byte[] var0) {
        byte[] var1;
        int var2;
        if((var2 = var0.length % 3) == 0) {
            var1 = new byte[4 * var0.length / 3];
        } else {
            var1 = new byte[4 * (var0.length / 3 + 1)];
        }

        int var3 = var0.length - var2;
        int var7 = 0;

        int var8;
        for(var8 = 0; var7 < var3; var8 += 4) {
            int var4 = var0[var7] & 255;
            int var5 = var0[var7 + 1] & 255;
            int var6 = var0[var7 + 2] & 255;
            var1[var8] = a[var4 >>> 2 & 63];
            var1[var8 + 1] = a[(var4 << 4 | var5 >>> 4) & 63];
            var1[var8 + 2] = a[(var5 << 2 | var6 >>> 6) & 63];
            var1[var8 + 3] = a[var6 & 63];
            var7 += 3;
        }

        switch(var2) {
            case 0:
            default:
                break;
            case 1:
                var7 = (var2 = var0[var0.length - 1] & 255) >>> 2 & 63;
                var8 = var2 << 4 & 63;
                var1[var1.length - 4] = a[var7];
                var1[var1.length - 3] = a[var8];
                var1[var1.length - 2] = 61;
                var1[var1.length - 1] = 61;
                break;
            case 2:
                var2 = var0[var0.length - 2] & 255;
                int var9 = var0[var0.length - 1] & 255;
                var7 = var2 >>> 2 & 63;
                var8 = (var2 << 4 | var9 >>> 4) & 63;
                var9 = var9 << 2 & 63;
                var1[var1.length - 4] = a[var7];
                var1[var1.length - 3] = a[var8];
                var1[var1.length - 2] = a[var9];
                var1[var1.length - 1] = 61;
        }

        return new String(var1);
    }

    public static byte[] a(String var0) {
        var0 = var0;
        StringBuffer var1 = new StringBuffer();
        int var2 = var0.length();

        byte var4;
        for(int var3 = 0; var3 < var2; ++var3) {
            boolean var10000;
            label54: {
                if((var4 = (byte)var0.charAt(var3)) != 61) {
                    if(var4 < 0 || var4 >= 128) {
                        var10000 = false;
                        break label54;
                    }

                    if(b[var4] == -1) {
                        var10000 = false;
                        break label54;
                    }
                }

                var10000 = true;
            }

            if(var10000) {
                var1.append(var0.charAt(var3));
            }
        }

        byte[] var8;
        if((var0 = var1.toString()).charAt(var0.length() - 2) == 61) {
            var8 = new byte[(var0.length() / 4 - 1) * 3 + 1];
        } else if(var0.charAt(var0.length() - 1) == 61) {
            var8 = new byte[(var0.length() / 4 - 1) * 3 + 2];
        } else {
            var8 = new byte[var0.length() / 4 * 3];
        }

        int var6 = 0;

        byte var5;
        byte var9;
        byte var10;
        for(int var7 = 0; var6 < var0.length() - 4; var7 += 3) {
            var9 = b[var0.charAt(var6)];
            var10 = b[var0.charAt(var6 + 1)];
            var4 = b[var0.charAt(var6 + 2)];
            var5 = b[var0.charAt(var6 + 3)];
            var8[var7] = (byte)(var9 << 2 | var10 >> 4);
            var8[var7 + 1] = (byte)(var10 << 4 | var4 >> 2);
            var8[var7 + 2] = (byte)(var4 << 6 | var5);
            var6 += 4;
        }

        if(var0.charAt(var0.length() - 2) == 61) {
            var9 = b[var0.charAt(var0.length() - 4)];
            var10 = b[var0.charAt(var0.length() - 3)];
            var8[var8.length - 1] = (byte)(var9 << 2 | var10 >> 4);
        } else if(var0.charAt(var0.length() - 1) == 61) {
            var9 = b[var0.charAt(var0.length() - 4)];
            var10 = b[var0.charAt(var0.length() - 3)];
            var4 = b[var0.charAt(var0.length() - 2)];
            var8[var8.length - 2] = (byte)(var9 << 2 | var10 >> 4);
            var8[var8.length - 1] = (byte)(var10 << 4 | var4 >> 2);
        } else {
            var9 = b[var0.charAt(var0.length() - 4)];
            var10 = b[var0.charAt(var0.length() - 3)];
            var4 = b[var0.charAt(var0.length() - 2)];
            var5 = b[var0.charAt(var0.length() - 1)];
            var8[var8.length - 3] = (byte)(var9 << 2 | var10 >> 4);
            var8[var8.length - 2] = (byte)(var10 << 4 | var4 >> 2);
            var8[var8.length - 1] = (byte)(var4 << 6 | var5);
        }

        return var8;
    }

    private static String b(String var0) {
        StringBuffer var1 = new StringBuffer();
        int var2 = var0.length();

        for(int var3 = 0; var3 < var2; ++var3) {
            boolean var10000;
            label29: {
                byte var4;
                if((var4 = (byte)var0.charAt(var3)) != 61) {
                    if(var4 < 0 || var4 >= 128) {
                        var10000 = false;
                        break label29;
                    }

                    if(b[var4] == -1) {
                        var10000 = false;
                        break label29;
                    }
                }

                var10000 = true;
            }

            if(var10000) {
                var1.append(var0.charAt(var3));
            }
        }

        return var1.toString();
    }

    private static boolean a(byte var0) {
        return var0 == 61?true:(var0 >= 0 && var0 < 128?b[var0] != -1:false);
    }
}

  • Des
public class Des {
    private static final String b = "DES/ECB/NoPadding";
    private static final String c = "DES";
    private static final String CODE = "GBK";

    public Des() {
    }

    private static char a(byte var0) {
        return (var0 = (byte)(var0 & 15)) < 10?(char)(var0 + 48):(char)(var0 + 65 - 10);
    }

    private static String a(byte[] var0) {
        if(var0 == null) {
            return null;
        } else {
            StringBuffer var1 = new StringBuffer();

            for(int var2 = 0; var2 < var0.length; ++var2) {
                byte var3 = (byte)((var0[var2] & 240) >> 4);
                byte var4 = (byte)(var0[var2] & 15);
                var1.append(a(var3));
                var1.append(a(var4));
            }

            return var1.toString();
        }
    }

    private static byte a(char var0) {
        return var0 >= 48 && var0 <= 57?(byte)(var0 - 48):(var0 >= 97 && var0 <= 102?(byte)(10 + (var0 - 97)):(var0 >= 65 && var0 <= 70?(byte)(10 + (var0 - 65)):0));
    }

    private static byte[] a(String var0) {
        int var1;
        byte[] var2 = new byte[var1 = var0.length() / 2];

        for(int var3 = 0; var3 < var1; ++var3) {
            char var4 = var0.charAt(var3 << 1);
            char var5 = var0.charAt((var3 << 1) + 1);
            var2[var3] = (byte)((a(var4) << 4) + a(var5));
        }

        return var2;
    }

    public static String Encrypt3Des(String var0, String var1, String var2)  {
        try {
            String var3 = var1.substring(0, 8);
            String var4 = var1.substring(8, 16);
            var1 = var1.substring(16, 24);
            boolean var12 = "ToHex16".equalsIgnoreCase(var2);
            int var5;
            byte[] var7;
            byte[] var10;
            if((var5 = (var10 = var0.getBytes(CODE)).length + 8 & -8) != var10.length) {
                var7 = new byte[var5];

                int var6;
                for(var6 = 0; var6 < var10.length; ++var6) {
                    var7[var6] = var10[var6];
                }

                for(var6 = var10.length; var6 < var7.length; ++var6) {
                    var7[var6] = (byte)(var5 - var10.length);
                }

                var10 = var7;
            }

            byte[] var16 = new byte[var10.length];
            var7 = new byte[8];

            for(var5 = 0; var5 + 8 <= var10.length; var5 += 8) {
                byte[] var8 = new byte[8];

                int var9;
                for(var9 = 0; var9 < 8; ++var9) {
                    var8[var9] = var10[var5 + var9];
                }

                if(var5 == 0) {
                    var7 = var3.getBytes(CODE);
                } else {
                    for(var9 = 0; var9 < 8; ++var9) {
                        var7[var9] = var16[var5 + var9 - 8];
                    }
                }

                var8 = b(a(b(var8, var3, "DES/ECB/NoPadding", var7), var4, "DES/ECB/NoPadding", (byte[])null), var1, "DES/ECB/NoPadding", (byte[])null);

                for(var9 = 0; var9 < 8; ++var9) {
                    var16[var5 + var9] = var8[var9];
                }
            }

            String var17;
            if(var12) {
                var10 = var16;
                String var10000;
                if(var16 == null) {
                    var10000 = null;
                } else {
                    StringBuffer var11 = new StringBuffer();
                    for(int var13 = 0; var13 < var10.length; ++var13) {
                        byte var14 = (byte)((var10[var13] & 240) >> 4);
                        byte var15 = (byte)(var10[var13] & 15);
                        var11.append(a(var14));
                        var11.append(a(var15));
                    }
                    var10000 = var11.toString();
                }
                var17 = var10000;
            } else {
                var17 = a.a(var16);
            }
            return var17;
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String Decrypt3Des(String var0, String var1, String var2) {
        try {
            String var3 = var1.substring(0, 8);
            String var4 = var1.substring(8, 16);
            var1 = var1.substring(16, 24);
            byte[] var5 = new byte[8];
            byte[] var6;
            byte[] var12;
            if("ToHex16".equalsIgnoreCase(var2)) {
                int var11;
                var6 = new byte[var11 = (var0 = var0).length() / 2];
                for(int var7 = 0; var7 < var11; ++var7) {
                    char var8 = var0.charAt(var7 << 1);
                    char var9 = var0.charAt((var7 << 1) + 1);
                    var6[var7] = (byte)((a(var8) << 4) + a(var9));
                }
                var12 = var6;
            } else {
                var12 = a.a(var0);
            }
            var6 = new byte[var12.length];
            int var10;
            for(var10 = 0; var10 + 8 <= var12.length; var10 += 8) {
                byte[] var13 = new byte[8];
                int var14;
                for(var14 = 0; var14 < 8; ++var14) {
                    var13[var14] = var12[var10 + var14];
                }
                var13 = b(a(var13, var1, "DES/ECB/NoPadding", (byte[])null), var4, "DES/ECB/NoPadding", (byte[])null);
                if(var10 == 0) {
                    var5 = var3.getBytes(CODE);
                } else {
                    for(var14 = 0; var14 < 8; ++var14) {
                        var5[var14] = var12[var10 + var14 - 8];
                    }
                }
                var13 = a(var13, var3, "DES/ECB/NoPadding", var5);
                for(var14 = 0; var14 < 8; ++var14) {
                    var6[var10 + var14] = var13[var14];
                }
            }

            byte var15;
            if((var15 = var6[var6.length - 1]) > 0 && var15 <= var6.length) {
                if(var15 == var6.length) {
                    return "";
                } else {
                    byte[] var16 = new byte[var6.length - var15];

                    for(var10 = 0; var10 < var16.length; ++var10) {
                        var16[var10] = var6[var10];
                    }

                    return new String(var16, CODE);
                }
            } else {
                return new String(var6, CODE);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static byte[] a(byte[] var0, String var1, String var2, byte[] var3) throws Exception {
        Cipher var4 = Cipher.getInstance(var2);
        DESKeySpec var6 = new DESKeySpec(var1.getBytes(CODE));
        SecretKey var7 = SecretKeyFactory.getInstance("DES").generateSecret(var6);
        if(var2.contains("/CBC/") && var3 != null) {
            IvParameterSpec var8 = new IvParameterSpec(var3);
            var4.init(2, var7, var8);
        } else {
            var4.init(2, var7);
        }

        return var4.doFinal(var0);
    }

    private static byte[] b(byte[] var0, String var1, String var2, byte[] var3) throws Exception {
        Cipher var4 = Cipher.getInstance(var2);
        DESKeySpec var6 = new DESKeySpec(var1.getBytes(CODE));
        SecretKey var7 = SecretKeyFactory.getInstance("DES").generateSecret(var6);
        if(var2.contains("/CBC/")) {
            IvParameterSpec var8 = new IvParameterSpec(var3);
            var4.init(1, var7, var8);
        } else {
            var4.init(1, var7);
        }

        return var4.doFinal(var0);
    }
}

  • HttpUtil
@Slf4j
public class HttpUtil {

    private RequestConfig requestConfig = RequestConfig.custom()
            .setSocketTimeout(30000)
            .setConnectTimeout(30000)
            .setConnectionRequestTimeout(30000)
            .build();

    /**
     * 发送 post请求
     * @param httpUrl 地址
     * @param params 参数(Json格式)
     */
    public String sendJsonHttpPost(String httpUrl, String params) {
        //log.info("请求地址及请求参数 {}, {}", httpUrl, params);
        //log.info("====================================================");
        HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost
        try {
            //设置参数
            StringEntity stringEntity = new StringEntity(params, "UTF-8");// GBK
            stringEntity.setContentType("text/json");

            httpPost.setEntity(stringEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sendHttpPost(httpPost);
    }

    public String sendFormHttpPost(String httpUrl, Map<String, Object> data, String charset) {
        HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost

        List<NameValuePair> form = new ArrayList<>();
        for (Map.Entry entry : data.entrySet()) {
            if (null != entry.getValue()) {
                form.add(new BasicNameValuePair(entry.getKey() + "", entry.getValue() + ""));
            }
        }

        try {
            httpPost.setEntity(new UrlEncodedFormEntity(form, charset));
        } catch (Exception e) {
            log.error("method postForm error|message={}", e.getMessage(), e);
            e.printStackTrace();
        }
        return sendHttpPost(httpPost);
    }


    /**
     * 发送Post请求
     * @param httpPost
     * @return
     */
    private String sendHttpPost(HttpPost httpPost) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        HttpEntity entity = null;
        String responseContent = null;
        try {
            // 创建默认的httpClient实例.
            httpClient = HttpClients.createDefault();
            httpPost.setConfig(requestConfig);

            // 执行请求
            response = httpClient.execute(httpPost);
            entity = response.getEntity();
            responseContent = EntityUtils.toString(entity, "UTF-8");// GBK
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 关闭连接,释放资源
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //log.error("请求结果:"+ responseContent);
        return responseContent;
    }

}
  • SignEncryptUtil
@Slf4j
public class SignEncryptUtil {

    public static final String BC_PROV_ALGORITHM_SHA1RSA = "SHA1withRSA";

    private static final int MAX_ENCRYPT_BLOCK = 117;

    //private static final int MAX_DECRYPT_BLOCK = 128;
    private static final int MAX_DECRYPT_BLOCK = 256;

    // 验签
    public static boolean verify(String data,String sign,PublicKey publicKey) {
        try {
            Signature signature = Signature.getInstance(BC_PROV_ALGORITHM_SHA1RSA);
            signature.initVerify(publicKey);
            signature.update(data.getBytes(Constants.UTF8));
            return signature.verify(org.bouncycastle.util.encoders.Base64.decode(sign.getBytes()));
        } catch (Exception e) {
            log.error("验签错误:{}",e);
            return false;
        }
    }

    // 签名
    public static String sign(String obj,PrivateKey privateKey){
        String sign = "";
        try {
            Signature signature = Signature.getInstance(BC_PROV_ALGORITHM_SHA1RSA);
            signature.initSign(privateKey);
            signature.update(obj.getBytes(StandardCharsets.UTF_8));
            sign = new String(org.bouncycastle.util.encoders.Base64.encode(signature.sign()));
        } catch (Exception e) {
            log.error("签名错误:{}",e);
        }
        return sign;
    }

    // 加密
    public static String encrypt(String data,PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        while (inputLen - offset > 0) {
             if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                     cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
                 } else {
                     cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
                 }
             out.write(cache, 0, cache.length);
             i++;
             offset = i * MAX_ENCRYPT_BLOCK;
         }
         byte[] encryptedData = out.toByteArray();
         out.close();
         return new String(org.bouncycastle.util.encoders.Base64.encode(encryptedData),Constants.UTF8);
    }

    // 解密
    public static String decrypt(String data,PrivateKey privateKey) throws Exception {
         Cipher cipher = Cipher.getInstance("RSA");
         cipher.init(Cipher.DECRYPT_MODE, privateKey);
         byte[] dataBytes = org.bouncycastle.util.encoders.Base64.decode(data.getBytes());
         int inputLen = dataBytes.length;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         int offset = 0;
         byte[] cache;
         int i = 0;
         while (inputLen - offset > 0) {
             if (inputLen - offset > MAX_DECRYPT_BLOCK) {
             cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                 cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
             }
             out.write(cache, 0, cache.length);
            i++;
             offset = i * MAX_DECRYPT_BLOCK;
         }
         byte[] decryptedData = out.toByteArray();
         out.close();
         return new String(decryptedData, Constants.UTF8);
    }

}

  • SmallTools
public class SmallTools {
    /**
     * MD5加密
     * @param str 需要加密的值
     * @return 加密完成的值(小写)
     */
    public static String MD5en(String str){
        String re_md5 = new String();
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes());
            byte b[] = md.digest();

            int i;

            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }

            re_md5 = buf.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return re_md5;
    }


    /**
     * 获取当前时间(格式自传)
     * @param dateFormat 要返回的时间格式,例如yyyy/MM/dd HH:mm:ss
     * @return
     */
    public static String getDate(String dateFormat){
        Date date = new Date();
        SimpleDateFormat dateF = new SimpleDateFormat(dateFormat);//可以方便地修改日期格式
        String retu = dateF.format(date);
        return retu;
    }


    /**
     * @param str 传入例如aaa=123&bbb=234这种&符号连接的字符串
     * @return 返回key=aaa value=123这样的HashMap
     */
    public static HashMap<String,String> getHash(String str){
        HashMap<String,String> hash = new HashMap<String, String>();
        String[] list = str.split("&");
        for (int i=0; i<list.length; i++){
            String[] i_ss = list[i].split("=");
            if (i_ss.length==1){
                hash.put(i_ss[0],"");
            }else {
                hash.put(i_ss[0],i_ss[1]);
            }
        }
        return hash;
    }
}

  • StrUtil
@Slf4j
public class StrUtil {

    /**
     * 将对象转换为map
     * @param bean
     * @return
     * @throws IntrospectionException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static Map convertBeanNoneEmpty(Object bean)
            throws IntrospectionException, IllegalAccessException, InvocationTargetException {
        Class type = bean.getClass();
        Map returnMap = new HashMap();
        BeanInfo beanInfo = Introspector.getBeanInfo(type);

        PropertyDescriptor[] propertyDescriptors =  beanInfo.getPropertyDescriptors();
        for (int i = 0; i< propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();
            if (!propertyName.equals("class")&&!propertyName.equals("sign")){
                Method readMethod = descriptor.getReadMethod();
                Object result = readMethod.invoke(bean, new Object[0]);
                if (result != null) {
                    returnMap.put(propertyName, result);
                }
            }
        }
        return returnMap;
    }

    /**
     * 将map转换为字符串
     * @param data
     * @return
     */
    public static String coverMap2String(Map<String, String> data) {
        TreeMap<String, String> tree = new TreeMap<>();
        Iterator<Map.Entry<String, String>> it = data.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> en = it.next();
            tree.put(en.getKey(), en.getValue());
        }
        it = tree.entrySet().iterator();
        StringBuilder sb = new StringBuilder();
        while (it.hasNext()) {
            Map.Entry<String, String> en = it.next();
            sb.append(en.getKey()).append("=").append(en.getValue()).append("&");
        }
        return sb.substring(0, sb.length() - 1);
    }

    public static byte[] readResourceFileByBytes(String fileName) throws IOException {
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            ClassPathResource classPathResource = new ClassPathResource(fileName);
            in = classPathResource.getInputStream();
            out = new ByteArrayOutputStream();
            byte[] tempbytes = new byte[in.available()];
            for(int i =0;(i=in.read(tempbytes))!=-1;){
                out.write(tempbytes,0,i);
            }
            log.info("读取文件 " + fileName + " 成功!");
        }finally {
            in.close();
            out.close();
        }
        return out.toByteArray();
    }

    public static byte[] readFileByBytes(String fileName) throws IOException{
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = new BufferedInputStream(new FileInputStream(fileName));
            out = new ByteArrayOutputStream();
            byte[] tempbytes = new byte[in.available()];
            for(int i =0;(i=in.read(tempbytes))!=-1;){
                out.write(tempbytes,0,i);
            }
            log.info("读取文件 " + fileName + " 成功!");
        }finally {
            in.close();
            out.close();
        }
        return out.toByteArray();
    }

    /**
     * 解析出url参数中的键值对
     * @param urlParams username=admin&password=1234...
     * @return url请求参数部分
     */
    public static Map<Object, Object> urlSplit (String urlParams) {
        Map<Object, Object> map = new HashMap<>();
        String[] arrSplit=null;
        if (urlParams == null) {
            return map;
        }
        arrSplit = urlParams.split("[&]");
        for (String strSplit : arrSplit) {
            String[] arrSplitEqual=null;
            arrSplitEqual= strSplit.split("[=]");
            //解析出键值
            if(arrSplitEqual.length>1){
                //正确解析
                map.put(arrSplitEqual[0], arrSplitEqual[1]);
            } else {
                if(arrSplitEqual[0]!=""){
                    //只有参数没有值,不加入
                    map.put(arrSplitEqual[0], "");
                }
            }
        }
        return map;
    }
}

  • XMLParseUtil
public class XMLParseUtil {

    public static Map<String, Object> getValueByNode(String xml) throws DocumentException {

        Document doc = DocumentHelper.parseText(xml);
        Map<String, Object> map = new HashMap<String, Object>();
        if(doc == null)
            return map;
        Element root = doc.getRootElement();
        for (Iterator iterator = root.elementIterator(); iterator.hasNext();) {
            Element e = (Element) iterator.next();
            //System.out.println(e.getName());
            List list = e.elements();
            if(list.size() > 0){
                map.put(e.getName(), Dom2Map(e));
            }else
                map.put(e.getName(), e.getText());
        }
        return map;
    }

    public static Map Dom2Map(Element e){
        Map map = new HashMap();
        List list = e.elements();
        if(list.size() > 0){
            for (int i = 0;i < list.size(); i++) {
                Element iter = (Element) list.get(i);
                List mapList = new ArrayList();
                if(iter.elements().size() > 0){
                    Map m = Dom2Map(iter);
                    if(map.get(iter.getName()) != null){
                        Object obj = map.get(iter.getName());
                        if(!obj.getClass().getName().equals("java.util.ArrayList")){
                            mapList = new ArrayList();
                            mapList.add(obj);
                            mapList.add(m);
                        }
                        if(obj.getClass().getName().equals("java.util.ArrayList")){
                            mapList = (List) obj;
                            mapList.add(m);
                        }
                        map.put(iter.getName(), mapList);
                    }else
                        map.put(iter.getName(), m);
                }
                else{
                    if(map.get(iter.getName()) != null){
                        Object obj = map.get(iter.getName());
                        if(!obj.getClass().getName().equals("java.util.ArrayList")){
                            mapList = new ArrayList();
                            mapList.add(obj);
                            mapList.add(iter.getText());
                        }
                        if(obj.getClass().getName().equals("java.util.ArrayList")){
                            mapList = (List) obj;
                            mapList.add(iter.getText());
                        }
                        map.put(iter.getName(), mapList);
                    }else
                        map.put(iter.getName(), iter.getText());//公共map resultCode=0
                }
            }
        }else
            map.put(e.getName(), e.getText());
        return map;
    }
}

  • HeePayService
@Component
@Slf4j
public class HeePayService {

    private static PrivateKey privateKey = null; // 商户私钥
    private static PublicKey heepayPublicKey = null; // 汇付公钥
    private static PublicKey mcPublicKey = null; // 商户公钥

    // 初始化静态块
    static {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] privateKeyPath = org.bouncycastle.util.encoders.Base64.decode(MC_PRIVATE_KEY.getBytes());
            byte[] publicKeyPath =org.bouncycastle.util.encoders.Base64.decode(HEEPAY_PUBLIC_KEY.getBytes());
            byte[] mcPublicKeyPath =org.bouncycastle.util.encoders.Base64.decode(MC_PUBLIC_KEY.getBytes());
            privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec((privateKeyPath)));
            heepayPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyPath));
            mcPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(mcPublicKeyPath));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("加密失败:{}, ",e.getMessage());
        }

    }

    /**
     * 签约银行卡
     * @param orderNumber 订单号
     * @param bankUserName 姓名
     * @param bankType 银行卡类型
     * @param certNo 身份证号
     * @param mobile 签约银行手机号
     * @param bankCardNo 银行卡号
     * @param userId 商户平台用户标识,自定义保证唯一
     * @return
     */
    public SignResponse cardBind(String orderNumber, String bankUserName, String bankType, String certNo, String mobile, String bankCardNo, String userId) {
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SignRequest signRequest = new SignRequest();
        signRequest.setOut_trade_no(orderNumber);
        signRequest.setOut_trade_time(sd.format(new Date()));
        signRequest.setMerch_user_id(userId);

        signRequest.setNotify_url(SING_NOTIFY_URL);
        signRequest.setReturn_url(SING_RESULT_URL);
        signRequest.setBank_card_type(BANK_CARD_TYPE);
        signRequest.setBank_type(bankType);
        signRequest.setFrom_user_ip(FROM_USER_IP);
        signRequest.setBank_card_no(bankCardNo);
        signRequest.setBank_user_name(bankUserName);
        signRequest.setMobile(mobile);
        signRequest.setCert_no(certNo);

        BaseRequest baseRequest = new BaseRequest();
        baseRequest.setBiz_content(JSON.toJSONString(signRequest));

        // 发送请求
        BaseResponse response = doPost1(baseRequest,true,HeePayConst.SIGN_SMS, HeePayConst.SING_SERVER_URL);
        SignResponse signResponse = new SignResponse();
        if(response.getData()!=null){
            signResponse = JSON.parseObject(response.getData(),SignResponse.class);
        }
        signResponse.setCode(response.getCode());
        signResponse.setMsg(response.getMsg());
        signResponse.setSub_code(response.getSub_code());
        signResponse.setSub_msg(response.getSub_msg());
        signResponse.setData(response.getData());
        signResponse.setSign(response.getSign());
        return signResponse;
    }

    /**
     * 查询签约的银行卡信息
     * @param outTradeNo 第三方发返回的订单号
     * @return QuerySignRespone
     */
    public QuerySignResponse queryCardMsg(String outTradeNo){

        QuerySignRequest querySignRequest = new QuerySignRequest();
        querySignRequest.setOut_trade_no(outTradeNo);

        BaseRequest baseRequest = new BaseRequest();
        baseRequest.setBiz_content(JSON.toJSONString(querySignRequest));

        BaseResponse response = doPost1(baseRequest,false, QUERY_SIGN, SING_SERVER_URL);
        QuerySignResponse querySignRespone = new QuerySignResponse();
        if(response.getData()!=null){
            querySignRespone = JSON.parseObject(response.getData(),QuerySignResponse.class);
        }
        querySignRespone.setCode(response.getCode());
        querySignRespone.setMsg(response.getMsg());
        querySignRespone.setSub_code(response.getSub_code());
        querySignRespone.setSub_msg(response.getSub_msg());
        querySignRespone.setData(response.getData());
        querySignRespone.setSign(response.getSign());
        return querySignRespone;
    }

    /**
     * 绑卡-解约
     * @param hyAuthUid
     * @return {agent_id=1664502, cancel_status=-1, ret_msg=商户授权信息不存在, ret_code=E104}
     */
    public Map<Object, Object> untieCardBind(String hyAuthUid) {

        CancelAuthRequest cancelAuthRequest = new CancelAuthRequest();
        cancelAuthRequest.setVersion("1");
        cancelAuthRequest.setHy_auth_uid(hyAuthUid);

        BasePayRequest basePayRequest = new BasePayRequest();
        basePayRequest.setAgent_id(MERCHANT_ID);

        // 发送请求
        return doPost2(cancelAuthRequest, CANCEL_AUTH_URL);

    }

    /**
     * 发起支付
     * 解密后的数据:agent_id=1664502&hy_token_id=H2209199287789AE_3cd86f299dd4a28daf6092f3da86373b&ret_code=0000&ret_msg=已经发送短信验证码
     * @param payAmt 金额
     * @param hyAuthUid hyAuthUid
     * @param agentBillId 订单号
     * @param ipAddr 用户ip地址
     * @return
     */
    public Map<Object, Object> payOrder(String payAmt, String hyAuthUid, String agentBillId, String ipAddr) {
        SendPaySMSRequest sendPaySMSRequest = new SendPaySMSRequest();

        sendPaySMSRequest.setPay_amt(payAmt);
        sendPaySMSRequest.setNotify_url(PAY_NOTIFY_URL);
        sendPaySMSRequest.setReturn_url(PAY_RESULT_URL);
        sendPaySMSRequest.setVersion("1");
        sendPaySMSRequest.setAgent_bill_id(agentBillId);
        // 序列号时间
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
        sendPaySMSRequest.setAgent_bill_time(df.format(new Date()));
        sendPaySMSRequest.setGoods_name("rechargeOrder");
        sendPaySMSRequest.setHy_auth_uid(hyAuthUid);
        sendPaySMSRequest.setUser_ip(ipAddr);

        // 发送http请求
        return doPost2(sendPaySMSRequest, SEND_PAY_SMS_URL);
    }

    /**
     * 支付短信确认
     * @param hyTokenId
     * @param verifyCode
     * @return
     */
    public Map<Object, Object> payOrderConfirm(String hyTokenId, String verifyCode) {

        ConfirmPayRequest confirmPayRequest = new ConfirmPayRequest();
        confirmPayRequest.setVersion("1");
        confirmPayRequest.setHy_token_id(hyTokenId);
        confirmPayRequest.setVerify_code(verifyCode);
        confirmPayRequest.setRef_agent_id("");
        return doPost2(confirmPayRequest, CONFIRM_PAY_URL);
    }

    /**
     * 支付异步回调参数处理
     * @param obj
     * @return
     */
    public Map<Object, Object> payOrderAsyncCallBack(SendPayResponse obj) {
        String encryptData = obj.getEncrypt_data();
        try {
            // 解密
            String decrypt = SignEncryptUtil.decrypt(encryptData, privateKey);
            // 处理
            boolean flag = SignEncryptUtil.verify(decrypt, obj.getSign(), mcPublicKey);
            if (flag) {
                return StrUtil.urlSplit(decrypt);
            }
        } catch (Exception e) {
            log.error("处理支付回调参数,失败 === {}", e.getMessage());
            e.printStackTrace();
        }
        return new HashMap<>();
    }


    

    /**
     * 查询卡bid
     * @param bankCardNo
     * @return
     */
    public Map<String, Object> queryCardBid(String bankCardNo) {

        String version = "3";
        String sign = "";
        StringBuilder sign_sb = new StringBuilder();
        sign_sb.append("agent_id")       .append("=").append(MERCHANT_ID)    .append("&")
                .append("bank_card_no")     .append("=").append(bankCardNo)   .append("&")
                .append("key")     .append("=").append(SIGN_KEY)   .append("&")
                .append("version")       .append("=").append(version);
        // md5 加密签名
        sign = SmallTools.MD5en(sign_sb.toString().toLowerCase());

        //请求参数
        Map<String, Object> map1 = new HashMap<>();
        HttpUtil httpUtil = new HttpUtil();
        map1.put("version", version);
        map1.put("agent_id", MERCHANT_ID);
        map1.put("bank_card_no", bankCardNo);
        map1.put("sign", sign);
        String response = httpUtil.sendFormHttpPost(QUERY_BANK_CARD_INFO_URL, map1, Constants.GBK);

        Map<String, Object> map = new HashMap<>();
        try {
            map = XMLParseUtil.getValueByNode(response);
        } catch (Exception e) {
            log.error("卡BIN查询异常 {}",e.getMessage());
            e.printStackTrace();
        }
        return map;
    }


    /**
     * 发送json请求,签约操作
     * @param baseRequest
     * @param flag
     * @param method
     * @param serverUrl
     * @return
     */
    private BaseResponse doPost1(BaseRequest baseRequest, boolean flag, String method, String serverUrl) {

        HttpUtil httpUtil = new HttpUtil();
        BaseResponse baseResponse = new BaseResponse();
        try {
            baseRequest.setMerch_id(MERCHANT_ID);
            baseRequest.setVersion(VERSION);
            baseRequest.setMethod(method);
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            baseRequest.setTimestamp(df.format(new Date()));
            // 将对象转换为map
            Map<String,String> map = StrUtil.convertBeanNoneEmpty(baseRequest);
            // 将map转换为json字符串
            String bizJson = StrUtil.coverMap2String(map);
            //签名
            String sign = SignEncryptUtil.sign(bizJson,privateKey);
            baseRequest.setSign(sign);
            //bizContent加密
            if (flag) {
                String content =SignEncryptUtil.encrypt(baseRequest.getBiz_content(),heepayPublicKey);
                baseRequest.setBiz_content(content);
            }

            // 发送http请求
            String res = httpUtil.sendJsonHttpPost(serverUrl, JSON.toJSONString(baseRequest));
            log.info("doPost1 返回的请求结果:{}", res);
            // 处理返回信息
            baseResponse = JSON.parseObject(res, BaseResponse.class);
            if(baseResponse.getData()!=null){
                // 解密
                String data = SignEncryptUtil.decrypt(baseResponse.getData(),privateKey);
                baseResponse.setData(data);
            }

            Map<String,String> resMap = StrUtil.convertBeanNoneEmpty(baseResponse);
            String resJson = StrUtil.coverMap2String(resMap);

            if(baseResponse.getSign()!=null){
                // 验签
                boolean result = SignEncryptUtil.verify(resJson,baseResponse.getSign(),heepayPublicKey);
                if(result){
                    return baseResponse;
                }else {
                    baseResponse.setCode("40002");
                    baseResponse.setMsg("返回结果验签异常");
                }
            }
        } catch (Exception e) {
            baseResponse.setCode("40004");
            baseResponse.setMsg("发送请求异常");
            log.error("{}, 请求异常 {}",method,e);
        }
        return baseResponse;
    }

    /**
     * 发送from请求
     * @param bean
     * @param serverUrl 请求地址
     * @return
     */
    private Map<Object, Object> doPost2(Object bean, String serverUrl) {

        try {
            Map<String,String> map2 = StrUtil.convertBeanNoneEmpty(bean);
            String bizJson = StrUtil.coverMap2String(map2);
            String sign = SignEncryptUtil.sign(bizJson, privateKey);
            String decrypt = SignEncryptUtil.encrypt(bizJson, heepayPublicKey);
            Map<String, Object> map = new HashMap<>();
            map.put("agent_id", MERCHANT_ID);
            map.put("encrypt_data", decrypt);
            map.put("sign", sign);
            // 发送请求
            HttpUtil httpUtil = new HttpUtil();
            String response = httpUtil.sendFormHttpPost(serverUrl, map, Constants.UTF8);
            log.info("doPost2 返回的请求结果:{}", response);

            Map<String, Object> map3 = XMLParseUtil.getValueByNode(response);
            String encryptData = String.valueOf(map3.get("encrypt_data"));

            // 解密
            if(encryptData != null) {
                encryptData = SignEncryptUtil.decrypt(encryptData, privateKey);
            }
            // 处理
            return StrUtil.urlSplit(encryptData);

        } catch (Exception e) {
            e.printStackTrace();
            log.error("doPost2 方法调用异常:{}, 请求链接:{}", e.getMessage(), serverUrl);
        }

        return new HashMap<>();
    }

}

签约效果

签约前如果不传入个人信息等,可以直接在此页面填入,如果传入则不能更改
在这里插入图片描述

官网文档

汇付宝开发文档

问题

  1. 测试环境没有问题,正式环境有问题
    请求url有问题,例如:商户与支付平台使用www.baidu.com地址进行授权签约,而平台使用的是api.baidu.com,这样就会造成这个问题,解决方案就是:解析api.baidu.com
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值