废话不多说,直切如题。
前几天写了一篇对接微信支付的,因为项目和农行合作,需要对接农行支付,在对接的过程中遇到太多坑了,和我对接的是客户经理,我需要资料和咨询技术方面的东西都需要他传递,效率大大降低。好在项目周期比较充足,连猜带蒙终于搞定了。下面介绍具体流程,给后来的老哥闭闭坑~~~~~~~~~
首先农行会提供对接文档,农行根证书,商户证书,网上支付平台证书等必要资料

里面会有基本的配置介绍。
会有两个配置文件,将它们放入到项目的resources文件夹下
按照里面的要求配置好参数,然后将TurstPayClient-V3.1.8.jar导入项目;
提示:农行支付接口支持多商户模式,就是说同个项目可以配置多个商户号,交易的时候可以指定使用哪一个商户号。
因为实际项目需要微信支付和农行掌银支付,所以以下内容会介绍这两张支付模式。
一切都配置好了之后开始敲代码了。
在微信中调用农行的微信支付,也就是农行对接微信,我对接农行。体验是和微信支付一模一样的。
将参数按照要求封装之后调用jar包里的微信下单接口,实例代码如下
- public JSON abcWxOrder(String outTradeNo, String appId, String openId, String totalFee, String body) {
- //封装参数
- UnifiedPaymentRequest unifiedPaymentRequest = new UnifiedPaymentRequest();
- //设置订单属性
- //微信支付类型,1:NATIVE 2:JSAPI 3:APP 4:MICROPAY
- unifiedPaymentRequest.dicOrder.put("PayTypeID", Constants.PAY_TYPE_JSAPI);
- //订单日期
- unifiedPaymentRequest.dicOrder.put("OrderDate", DateUtil.format(new Date(), "yyyy/MM/dd"));
- //订单时间
- unifiedPaymentRequest.dicOrder.put("OrderTime", DateUtil.format(new Date(), "HH:mm:ss"));
- //订单号
- unifiedPaymentRequest.dicOrder.put("OrderNo", outTradeNo);
- //OpenID
- unifiedPaymentRequest.dicOrder.put("OpenID", openId);
- //交易币种 156-人民币
- unifiedPaymentRequest.dicOrder.put("CurrencyCode", "156");
- //交易金额
- unifiedPaymentRequest.dicOrder.put("OrderAmount", NumberUtil.roundStr(Double.parseDouble(totalFee) / 100, 2));
- //刷卡支付时,请上送授权码;公众号、小程序、APP支付时,请上送应用的APPID
- unifiedPaymentRequest.dicOrder.put("AccountNo", appId);
- //订单描述
- unifiedPaymentRequest.dicOrder.put("OrderDesc", body);
- //支付请求对象属性
- //支付账户类型,8:微信支付
- unifiedPaymentRequest.dicRequest.put("PaymentType", "8");
- //支付交易渠道,1:internet网络接入 2:手机网络接入 3:数字电视网络接入 4:智能客户端 5:线下渠道
- unifiedPaymentRequest.dicRequest.put("PaymentLinkType", "2");
- //支付结果通知方式,0:仅URL页面通知 1:服务器通知和URL页面通知
- unifiedPaymentRequest.dicRequest.put("NotifyType", "1");
- //商户接收支付结果通知地址,商户自己填写
- unifiedPaymentRequest.dicRequest.put("ResultNotifyURL", systemConfig.getNotifyUrl() + "/unitePay/abcNotify.api");
- //商品类型
- unifiedPaymentRequest.dicRequest.put("CommodityType", "0401");
- //农行模板分账或者平台商户的二级商户分账时必输,1:进行分账 0:不进行分账
- unifiedPaymentRequest.dicRequest.put("IsBreakAccount", "0");
- try {
- JSON json = unifiedPaymentRequest.postRequest();
- return json;
- } catch (Exception e) {
- log.error("农行微信支付下单接口异常:{}", e.getMessage());
- throw new RuntimeException();
- }
- }
正确拿到返回参数JSAPI,这是微信APP支付唤起支付控件所需字段,
String JSAPI = json.GetKeyValue("JSAPI");
JSAPI返回示例如下:
- "JSAPI": {
- "sub_appId": "wxa4f5c9918ecXXXX",
- "timeStamp": "1576556760",
- "nonceStr": "017f7061615d7812a6b102644c11e",
- "package": "prepay_id=wx1712270edf3298e1734690300",
- "signType": "RSA",
- "timestamp": "1576556760",
- "paySign": "0MrX0DKYR+JN5xqL1wp++h80i+zoU1K+8tR//LMur9bsg06Z08L3BuhlAqk7IdQ0HxWR5MOHeh4Gu7n+GYzlAyfMmNFUtm7zxAmcdb7mOgpCrbSD8eUPpjXviZYisK/8MEnNBekC1L0QtwujqgImdzvNpvtShCjPsdPOTfvu7sHQ3hhve6YdF9d5c7M7K3D0iONucohGBiairWO7ObAh6N2nUg7w++XB+/lupl3iIlmDCROew=="
- },
然后将这些参数给前端,调用微信支付控件就能唤醒微信支付了。
首先使用农行的一码多扫下单接口,先拼接参数,再调用jar里的方法,示例代码如下:
- public JSON abcUniteOrder(String orderNo, String totalFee) {
- try {
- PaymentRequest paymentRequest = new PaymentRequest();
- paymentRequest.dicRequest.put("PaymentType", "A");
- paymentRequest.dicRequest.put("PaymentLinkType", "2");
- paymentRequest.dicRequest.put("NotifyType", "1");
- paymentRequest.dicRequest.put("ResultNotifyURL", "");
- paymentRequest.dicRequest.put("IsBreakAccount", "0");
- paymentRequest.dicOrder.put("PayTypeID", "ImmediatePay");
- paymentRequest.dicOrder.put("OrderDate", DateUtil.format(new Date(), "yyyy/MM/dd"));
- paymentRequest.dicOrder.put("OrderTime", DateUtil.format(new Date(), "HH:mm:ss"));
- paymentRequest.dicOrder.put("OrderNo", orderNo);
- paymentRequest.dicOrder.put("CurrencyCode", "156");
- paymentRequest.dicOrder.put("OrderAmount", NumberUtil.roundStr(Double.parseDouble(totalFee) / 100, 2));
- paymentRequest.dicOrder.put("CommodityType", "0401");
- paymentRequest.dicOrder.put("BuyIP", InetAddress.getLocalHost().getHostAddress());
- LinkedHashMap orderItems = new LinkedHashMap();
- orderItems.put("ProductName", "水费");
- paymentRequest.orderitems.put("ProductName", orderItems);
- JSON json = paymentRequest.postRequest();
- return json;
- } catch (Exception e) {
- log.error("农行支付下单接口请求异常:{}", e.getMessage());
- throw new RuntimeException();
- }
- }
然后拿到返回参数PaymentURL,如:method=invokePayFromBrowser&tokenID=144057162720037182
String paymentURL = json.GetKeyValue("PaymentURL");
接着按照文档要求拼接唤醒掌银app的url,示例代码如下,方法里的tokenId是paymentURL中的tokenID值,加密方法DES用的是hutool包里封装的方法(网上能搜到的,hutool工具)
- public String getAbcUrlByNew(String tokenId) {
- String method = "https://wx.abchina.com/webank/main-view/openTagFor?id=ycA%3D&dynamicData=";
- DES des = new DES(Mode.CBC, Padding.PKCS5Padding, "abc".getBytes(), "abc".getBytes());
- String s = des.encryptBase64("tokenID="+tokenId);
- String encode = URLEncoder.encode(s, "UTF-8");
- return method+encode;
- }
最后将这个拼接后的url给前端,打开就自动跳转到掌银APP了。
支付下单的时候有回调url传参的,农行会按照这个url进行支付结果通知,示例代码如下
- @RequestMapping(value = "/abc.api")
- @AuthMethod(type = RequestType.APIOUT)
- public String abcNotify(@RequestBody String xmlStr){
- System.out.println("-------接收到农行回调信息------"+xmlStr);
- // return "
https://xxx.xxx.com/result/index.shtml "; - return commonPayService.abcNotify(xmlStr);
- }
- public String abcNotify(String xmlStr) {
- String decode = URLDecoder.decode(xmlStr, "utf-8");
- //支付结果对象
- PaymentResult paymentResult = new PaymentResult(decode);
- //支付订单号
- String orderNo = paymentResult.getValue("OrderNo");
- log.info("开始接收农行回调信息,支付订单号:{}",orderNo);
- //订单金额(分)
- // String amount = (Double.parseDouble(paymentResult.getValue("Amount")) * 100) + "";
- BigDecimal aa = new BigDecimal(Double.parseDouble(paymentResult.getValue("Amount")) + "");
- BigDecimal bb = new BigDecimal("100");
- BigDecimal multiply = aa.multiply(bb);
- String amount = multiply.intValue() + "";
- //交易批次号
- paymentResult.getValue("BatchNo");
- //交易凭证号(建议使用iRspRef作为对账依据)
- paymentResult.getValue("VoucherNo");
- //银行交易日期(YYYY/MM/DD)
- String day = paymentResult.getValue("HostDate");
- //银行交易时间(HH:MM:SS)
- String time = paymentResult.getValue("HostTime");
- String timeEnd = day.replace("/", "-") + " " + time;
- //商户备注信息(商户在支付请求时所提交的信息)
- paymentResult.getValue("MerchantRemarks");
- //消费者支付方式
- paymentResult.getValue("PayType");
- //支付结果通知方式
- paymentResult.getValue("NotifyType");
- //银行返回交易流水号
- String bankOrderId = paymentResult.getValue("iRspRef");
- //付款银行(微信支付时返回)
- String bank_type = paymentResult.getValue("bank_type");
- //第三方订单号(微信和支付宝)
- String thirdOrderNo = paymentResult.getValue("ThirdOrderNo");
- WxOrder info = getInfo(orderNo, amount);
- if (info == null) {
- //平台系统找不到订单
- log.error("农行支付回调订单查询不到,订单号:{},银行流水号:{},订单金额:{},支付完成时间:{}",
- orderNo, bankOrderId, amount, day + "-" + time);
- return null;
- }
- if (info.getStatus() != 0) {
- //订单已经处理,无需进一步操作
- return null;
- } else {
- //处理订单
-
-
- if (!paymentResult.isSuccess()) {
- //支付失败
- log.info("农行回调:订单支付失败,订单号:{},失败原因:{}", orderNo, paymentResult.getErrorMessage());
- return "
" + systemConfig.getNotifyUrl() + "/result/fail.shtml"; - }
- }
- return "
" + systemConfig.getNotifyUrl() + "/result/success.shtml"; - }
农行这里有点奇葩的,返回要用
还有一点,农行退费没有回调的,跟我对接的老哥告诉我没有,不知道是不是真的没有,文档也没找到。