JAVA通用

简介

为了提高客户的接入时效,特提供通用封装的开发SDK,使用本SDK将极大的简化开发者的工作,开发者将无需考虑通信、签名、验签等,只需要关注业务参数的拼装。

下载地址

SDK下载

通用接口调用实例

以下以聚合反扫接口为例,展示如何使用 SDK 来调用接口。

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Calendar cl = Calendar.getInstance();
String nowStr = sdf.format(cl.getTime());

// 参数组装
Map<String, Object> dataMap = new HashMap<String, Object>();
// 请求流水号,需保证当天商户下唯一,推荐采用日期时间+几位流水号的形式
dataMap.put("req_seq_id", nowStr + "01234567890");
// 请求日期,请求接口的日期,因服务器时间可能有差异,允许前后1天
dataMap.put("req_date", new SimpleDateFormat("yyyyMMdd").format(cl.getTime()));
// 系统编号,由汇付分配
dataMap.put("sys_id", DemoConstants.DEMO_SYS_ID);
// 商户订单号,需保证商户下唯一,推荐采用日期时间+几位流水号的形式
dataMap.put("mer_ord_id", nowStr + "1234567890");
// 分配商户号
dataMap.put("huifu_id", DemoConstants.DEMO_HUIFU_ID);
// 渠道号,若需使用自有渠道请联系业务对接人
dataMap.put("bank_channel_no", "");
// 交易金额
dataMap.put("trans_amt", "0.02");
// 商品描述
dataMap.put("goods_desc", "测试商品");
// 支付授权码,本接口会自动识别微信、支付宝、银联二维码
// dataMap.put("auth_code", DemoConstants.ALIPAY_AUTH_CODE);
dataMap.put("auth_code", DemoConstants.WX_AUTH_CODE);
// dataMap.put("auth_code", DemoConstants.UNIONPAY_AUTH_CODE);
// 风控信息
Map<String, String> riskMngInfo = new HashMap<>();
riskMngInfo.put("subTradeType", "4300");
Map<String, Object> riskCheckInfo = new HashMap<>();
riskCheckInfo.put("riskMngInfo", riskMngInfo);
riskCheckInfo.put("ipAddr", "139.207.19.246");
// 注意,风控信息为JSON字符串
// dataMap.put("risk_check_info", JSON.toJSONString(riskCheckInfo));
dataMap.put("risk_check_info", riskCheckInfo);
// 设备信息
JSONObject terminalDeviceInfo = new JSONObject();
terminalDeviceInfo.put("device_type", "4");
terminalDeviceInfo.put("device_ip", "139.207.19.246");
dataMap.put("terminal_device_info", terminalDeviceInfo);
// 异步通知地址
dataMap.put("notify_url", "virgo://http://www.vclinker.com");
// 交易有效期
cl.add(Calendar.MINUTE, 2);
dataMap.put("time_expire", sdf.format(cl.getTime()));
// 是否禁止用户使用信用卡支付。默认不禁用,若禁止请填1
dataMap.put("limit_pay", "0");
// 是否延时交易,1为延迟 0为不延迟
dataMap.put("is_delay_acct", "0");
// 传入分帐遇到优惠的处理规则 1-按比例分 2-按顺序保障 3-只给交易商户
dataMap.put("term_div_coupon_type", "3");
// 分账串,无需实时分账时可不传
JSONObject acctSplitBunch = new JSONObject();
JSONArray acctInfos = new JSONArray();
// 分账方1
JSONObject acctInfo = new JSONObject();
acctInfo.put("huifu_id", DemoConstants.DEMO_HUIFU_ID);
acctInfo.put("div_amt", "0.01");
acctInfos.add(acctInfo);
// 分账方2
acctInfo = new JSONObject();
acctInfo.put("huifu_id", DemoConstants.DIV_HUIFU_ID);
acctInfo.put("div_amt", "0.01");
acctInfos.add(acctInfo);
acctSplitBunch.put("acct_infos", acctInfos);
dataMap.put("acct_split_bunch", acctSplitBunch);
// 商户私有域
dataMap.put("mer_priv", "");
// 微信扩展参数集合
dataMap.put("wx_data", "");
// 支付宝扩展参数集合
dataMap.put("alipay_data", "");
// 银联扩展参数集合
dataMap.put("unionpay_data", "");
// 商户私有域
dataMap.put("mer_priv", "");
// 手续费类型 01:标准费率线上,02:标准费率线下,03:非盈利费率,04:缴费费率,05:保险费率,06:行业活动费率,07:校园餐饮费率,08:K12中小幼费率
// 不送时取业务入驻配置的默认费率
dataMap.put("pay_scene", "02");

Map<String, Object> pullPayInfo = new HashMap<>();
try {
        System.out.println("聚合反扫请求参数:" + JSON.toJSONString(dataMap));
        // 单商户模式可不指定merchantKey,会自动套用default配置
        pullPayInfo = BasePayClient.request(dataMap, "top.trans.authCodePay");
        // 多商户模式需指定merchantKey
        // pullPayInfo = BasePayClient.request(dataMap, "top.trans.authCodePay", "merchantKey1");
        System.out.println("聚合反扫返回参数:" + JSON.toJSONString(pullPayInfo));
} catch (BasePayException e) {
        e.printStackTrace();
}

String subRespCode = (String) pullPayInfo.get("sub_resp_code");
if ("00000000".equals(subRespCode)) {
        // 业务处理成功
        System.out.println("处理成功");
} else if ("00000100".equals(subRespCode)) {
        // 聚合反扫返回处理中,等待异步通知结果
        // 前台如需要交易结果展示可调用交易查询来获取后续交易状态
} else {
        String subRespDesc = (String) pullPayInfo.get("sub_resp_desc");
        // 业务处理失败
        System.out.println("处理失败,失败信息:"  + subRespDesc);
}

调用示例2:

HttpPost httpPost = new HttpPost("https://spin.cloudpnr.com/top/trans/authCodePay");
// 分配产品号
httpPost.addHeader("product_id", "xxx");
httpPost.addHeader("format","JSON");
httpPost.addHeader("charset","UTF-8");
httpPost.addHeader("version","1.0.0");

Map<String, Object> dataMap = new HashMap<>();
// 请求流水号
dataMap.put("req_seq_id", UUID.randomUUID().toString());//保持唯一,建议YYYYMMDD+流水形式
// 请求日期
dataMap.put("req_date", "20210311");//YYYYMMDD
// 分配商户号
dataMap.put("huifu_id", "xxx");
// 异步通知地址、交易类需带virgo://前缀
dataMap.put("notify_url", "virgo://http://www.gangcai.com");

// 注意风控信息为JSON字符串
Map<String, String> riskMngInfo = new HashMap<>();
riskMngInfo.put("subTradeType", "4300");
Map<String, Object> riskCheckInfo = new HashMap<>();
riskCheckInfo.put("riskMngInfo", riskMngInfo);
riskCheckInfo.put("ipAddr", "139.207.19.246");
dataMap.put("risk_check_info", JSON.toJSONString(riskCheckInfo));

// 微信扩展参数为JSON格式,不需要转换为字符串
Map<String, String> wxData = new HashMap<>();
wxData.put("sub_appid", "wxtest");
dataMap.put("wx_data", wxData);

// 以下为业务参数,请参考API接口文档进行参数设置
// .....

final String PRIVATE_KEY = "xxx"; // 从汇付获取的私钥
final String PUBLIC_KEY = "XXXX"; // 汇付公钥
String data = JSON.toJSONString(dataMap);
String sign = RsaUtils.sign(data, PRIVATE_KEY);

Map<String, String> bodyMap = new HashMap<String, String>();
bodyMap.put("data", data);
bodyMap.put("sign", sign);
// 分配系统号
bodyMap.put("sys_id", "xxxx");
bodyMap.put("sign_type", "RSA2");
String body = JSON.toJSONString(bodyMap);
StringEntity entity = new StringEntity(body, "UTF-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);

// CloseableHttpClient httpClient = HttpClients.createDefault(); // 也可采用此方式
CloseableHttpClient httpClient = HttpClientUtils.getHttpClient("https://spin.cloudpnr.com/top/trans/authCodePay");

CloseableHttpResponse response = null;
try {
    response = httpClient.execute(httpPost);
} catch (Exception ex) {
    // 通信失败
}
int respCode = response.getStatusLine().getStatusCode();

StringBuilder sb = new StringBuilder();
boolean isStream = true; // 是否以流方式接收
BufferedReader br = null;
if (200 == respCode) {

    HttpEntity entityResponse = response.getEntity();
    try {
        if (isStream) {
            br = new BufferedReader(new InputStreamReader(entityResponse.getContent(), "UTF-8"));
            String len;
            while ((len = br.readLine()) != null) {
                sb.append(len);
            }
        } else {
            sb.append(EntityUtils.toString(entityResponse, "UTF-8"));
        }
    } catch (IOException ioe) {
        if (br != null) {
            try {
                br.close();
            } catch (IOException ex) {
                ;
            }
        }
    }

    System.out.println("response:" + sb.toString());
    JSONObject jsonRes = JSON.parseObject(sb.toString());
    String responseCode = jsonRes.getString("resp_code");

    if ("10000".equals(responseCode)) {
        // 成功调用接口
        String responseData = jsonRes.getString("data");
        String responseSign = jsonRes.getString("sign");
        // 使用汇付公钥验签
        if (!RsaUtils.verify(responseData, PUBLIC_KEY, responseSign)) {
            // 验签失败处理
            return;
        }
        JSONObject dataObj = JSON.parseObject(responseData);
        String subRespCode = dataObj.getString("sub_resp_code");
        if ("00000000".equals(subRespCode)) {
            // 业务处理成功
            System.out.println("处理成功");
        } else {
            // 业务处理失败
            System.out.println("处理失败");
        }

    } else {
        // 调用接口出错
    }
} else {
    // 通信失败
}