首先吐槽一个工行的效率问题,兜圈子,回复慢,人家事还多。对接和一堆业务员对接,完全不懂技术,说不到点上。给的账号三番五次是错的,并且文档描述也和实际demo不一致,完全靠百度一点一点磨出来的。
微信小程序只能走微信支付,所以应客户需求走工行渠道的微信支付。
先贴可以执行的代码:
package com.hbbc.pi;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.hbbc.icbc.testxcx;
import com.hbbc.util.DBUtil;
import com.hbbc.util.LogUtil;
import com.hbbc.util.SignArithmeticUtil;
import com.hbbc.util.hf.HFContext;
import com.icbc.api.DefaultIcbcClient;
import com.icbc.api.IcbcApiException;
import com.icbc.api.IcbcConstants;
import com.icbc.api.request.AggregatePayHidePayRequestV1;
import com.icbc.api.request.AggregatePayHidePayRequestV1.AggregatePayHidePayRequestV1Biz;
import com.icbc.api.response.AggregatePayHidePayResponseV1;
import Decoder.BASE64Decoder;
public class PayICBC {
private String MY_PRIVATE_KEY = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCyisf78uAWzRXlTspmRyiY7nl6pAgBBVxJiRXKTqzvEayu0VacBEegEWZaHqR0trIQ80FRO845bvHYGERtOIqWDGIGqT3FOeXg+cYC+dQWr/2mZpTSyt3n68vxUpJQKCiOP4B8TDQ+1pMRcgiVcAnBqOwzNrTF8nZzHfogfHpYrvO4J+OLGditU3qpuFfc4uaNjkUkQ4r2/0nIc2XiHC3i2ex3pWVjgz706jCbAb0iJiVDxefdYgUwIx5q5KjnjzmHPT5GPLdW+H8LeA0eiWlzI/KZ46mUK9v6UOasjtFko6sLmwbmveMhAMLKB6WqLYE2g9HfHBaMfqOYVvzX7RWLAgMBAAECggEBAKJIlOgEZf0zonBQgpYend8L++0mhYPwDGdmrCC8DGIs7YnlC1U6aqQqzJ6jdZYEravMf5/XaSwbBYAjquMUUMlGdqWDIdJNeVMZFsKqCgwqp+SH0dWklobUS+ZzUM7DANZhFZ8OqI/labkTull+pnDAczImUDmgqWj0HB+nsaWyXfv+8qxyWYjYYkwYVZa9leI5Q/2veAzjXkMhQOWnFT7Rcd5OncJExrpH5EifbFYknLEoNS7ZHqtEAgI3euOh9NcxWOeZ5YEuE9rUm0lsGrQinRzqEp4FQUDSNImJCGTzKJuUs68rKS9Yb4hawGXYd++erfhvgwKexgBuCgYEA/i7Y9j8XQ9JiUUD2zNEVohMK4FTBkz/DGPBkO5L+Gkhkx3OQAPt3+EsTnW/qard+VqZ/4TYOYo/8jPWgL5Q5Nun9btJYltsN4boclB6TTuNHlV2nGPtvQUfQ5B+WidXKSJ77dLaP7qrl0K36xLr0LuO/VVw/bG4K5JXJNOnWNNkCgYEAs9GC9pme6MoSc4tA1wlgTwjBu+wtsJRG7yttlowe+dbyVYhCBKKh3o+73vlcjgGv5ucrwwfpTWPaxakgzITCoOiBq4JLdvy9T/lfeef/o9TYUEWcG0c7va+ifQtQvj9DsgTDBbIRgFB5WJBgcKGwaqJlcw3ba08FPhrnHzwMCgYEAw/CpH2oTLR0I3UoO9mRXINE9GSE89523b4ogOixd5TTZO0dCQv+Ww7hcLokPU6SPp4xCGAHrpN8J+D+AdCz2zfYif0N3NxM16EPns+a995oMnH/NR9zLLq+Fv9T53tcHUGP9w0LYQUtMTUlQfkb/5QV7gPnTimppyzwMFtYLYkECgYA9/W85ljILLIZ54LrEpw3VkT5Ai6Ygpq1hjEYmTT3sgWZfiC7CLFLDSCfLMYnvxrMeVflnLdYHAPKNi8Wr2+SPt7njuANAUkExxJ4fI6mlw0xLJI58hVj7gWxWdgZZYo7W9H5j9yvnPidlKCQoI0upv8Lc9qndFJ9RuuWwm2E/gwKBgQCCIsoHkplSzFLkEalvJ2O8E4jf/PgrVKxa5bHruS7fNNQIhTGCyO5mCkWjCKLhTaFiHiOSUg+vMIP9rUP/zYmPoqVF47EfKNTwHgShtt0pwGZ6gh3mJaeaeZB8FYy2xkeKLRdNWXswF6EZGbsLyBbX33iov5OxVyC/SUX8U1qKMg==";
protected static final String APP_ID = "100000000000001xxxxx";
private final String mch_id = "020059xxxxxx";//商户号
//网关公钥 测试
protected static final String APIGW_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwFgHD4kzEVPdOj03ctKM7KV+16bWZ5BMNgvEeuEQwfQYkRVwI9HFOGkwNTMn5hiJXHnlXYCX+zp5r6R52MY0O7BsTCLT7aHaxsANsvI9ABGx3OaTVlPB59M6GPbJh0uXvio0m1r/lTW3Z60RU6Q3oid/rNhP3CiNgg0W6O3AGqwIDAQAB";
public static void main(String[] args) throws Exception {
testxcx payment = new testxcx();
payment.payment();
}
public void payment() throws Exception {
//参数传递自行处理
String openId = postData.getString("openId");
String orderID = postData.getString("orderID");
String total = postData.getString("total");
DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, IcbcConstants.SIGN_TYPE_RSA2, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
AggregatePayHidePayRequestV1 request = new AggregatePayHidePayRequestV1();
request.setServiceUrl("https://xxxx/api/mybank/pay/aggregatepay/hidepayrequest/V2");
AggregatePayHidePayRequestV1Biz bizContent = new AggregatePayHidePayRequestV1Biz();
String today = new SimpleDateFormat("YYYYMMddHHmmss").format(new Date());
Calendar nowTime = Calendar.getInstance();
nowTime.add(Calendar.MINUTE, 10);
String endtoday = new SimpleDateFormat("YYYYMMddHHmmss").format(nowTime.getTime());
String hourString =new SimpleDateFormat("HHmmss").format(new Date());
bizContent.setOutTradeNo(orderID); //商户订单号;需保证商户系统唯一
bizContent.setOrderChannel("100"); // 下单发起渠道,100对应微信小程序, 101对应微信公众号,102对应支付宝生 活号
bizContent.setTpAppId("wxe317859xxx86xx5e"); // 第三方应用ID;商户在微信公众号内接入时必送,上送微信分配的公众账号ID;商户通过支付宝生活号接入时必送,上送支付宝分配的应用ID。目前暂不支持上送
bizContent.setMerId("020059xxxxx"); // 商户号 正常
bizContent.setTpOpenId(openId); //第三方用户标识;商户在微信公众号/支付宝生活号内接入时必送,上送用户在商户appid下的唯一标识。 目前暂不支持上送。
bizContent.setTranType("OfflinePay"); //交易类型。用于区分交易场景为线上支 付还是线下支付,对应数据字典: OfflinePay-线下支付,OnlinePay-线上 支付。
bizContent.setOrderDate(today); //交易提交时间, 格式为: YYYYMMDDHHmmss
bizContent.setEndTime(endtoday); // 交易过期时间
bizContent.setGoodsBody("xxxx");
bizContent.setInstallTimes("1");
bizContent.setOrderAmount(total); //总金额(单位:分)
bizContent.setSpbillCreateIp("127.0.0.1"); //请求发起终端ip(商户后台发起请求的服务器IP地址,如果获取不到上送127.0.0.1即可)
bizContent.setNotifyUrl("http://115.171.19.161:11452/servlet/ICBCOFSTEBizServlet?tokenID=1303");
bizContent.setNotifyType("HS"); //通知类型,表示在交易处理完成后把交 易结果通知商户的处理模式。 取 值“HS”:在交易完成后将通知信息,主 动发送给商户,发送地址为notify_url指 定地址; 取值“AG”:在交易完成后不通 知商户
bizContent.setReturnUrl("http://paycenter.uboxol.com/payment/notify/icbcpay_wap");
bizContent.setInterfaceVersion("1.1.0.0"); //接口号,目前仅支持上送1.1.0.0
bizContent.setResultType("0");
request.setBizContent(bizContent);
AggregatePayHidePayResponseV1 response;
try {
response = client.execute(request,today);
LogUtil.log("getPrepayId:"+response.getPrepayId());
LogUtil.log("getReturnMsg:"+response.getReturnMsg());
LogUtil.log("getReturnUrl:"+response.getReturnUrl());
LogUtil.log("getTranErrorCode:"+response.getTranErrorCode());
LogUtil.log("isSuccess:"+String.valueOf(response.isSuccess()));
LogUtil.log("ReturnMsg:"+String.valueOf(response.getReturnMsg()));
LogUtil.log("Returncode:"+String.valueOf(response.getReturnCode()));
if (response.getReturnCode()==0) {
LogUtil.log("下单成功!");
List<String> resultList=new ArrayList<String>();
BASE64Decoder decoder = new BASE64Decoder();
String aString = new String(decoder.decodeBuffer(response.getSignData()), "utf-8");
Map<String, String> map = (Map)JSON.parse(aString);
String nonceString = map.get("nonceStr");
String timeStamp = map.get("timeStamp");
String paySign =map.get("paySign");
resultList.add(paySign);
resultList.add("prepay_id="+response.getPrepayId());
resultList.add(nonceString);
resultList.add(timeStamp);
String reString= JSON.toJSONStringWithDateFormat(resultList, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat);
LogUtil.log("[payment]最终接口返回数据:" + reString);
ctx.output.returnStringDirectly(reString);
}else {
LogUtil.log("下单失败!");
ctx.output.returnStringDirectly("下单失败!");
}
} catch (IcbcApiException e) { e.printStackTrace(); }
}
}
踩坑:一脚一个大坑
1. 如果出现APPID没授权,无效等去找工行,是他们没开权限。
2.文档上写的result_type参数选输,但是这项为空就过不去,在官网上找的和他相关的文档为必输项。
3.给的我请求地址是V2,但是文档上的参考是V1
4.文档上的tran_type是线上线下,业务为线上支付,但是工行就让传线下支付,没有原因。
5.当你完成了工行支付请求,它会响应一个预支付成功,工行业务回复没有预支付这个概念????最后还是预支付成功的。
6.当预支付成功以后,会返回一个sign_data用于唤起微信支付,但是它是base64编码,需解码,解码完之后会有一串内容,用于小程序即可。
7.但是问题来了,小程序API上写的签名类型只有两种,但是工行返回的签名类型是RSA,为此我找了半天转格式,一直签名错误,不用管这些说明,直接拿过来用,signType就是RSA就行。
8.测试网关公钥和线上网关公钥不同,拿着线上网关公钥报 Signature length not correct: got 128 but was expecting 256,工行就是说公钥没问题,最后发现给的是网站的网关公钥,并且生产环境的商户号也没有建档。