JAVA通用¶
简介¶
为了提高客户的接入时效,特提供通用封装的开发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 {
// 通信失败
}