对接农行支付

废话不多说,直切如题。

        前几天写了一篇对接微信支付的,因为项目和农行合作,需要对接农行支付,在对接的过程中遇到太多坑了,和我对接的是客户经理,我需要资料和咨询技术方面的东西都需要他传递,效率大大降低。好在项目周期比较充足,连猜带蒙终于搞定了。下面介绍具体流程,给后来的老哥闭闭坑~~~~~~~~~ 

首先农行会提供对接文档,农行根证书,商户证书,网上支付平台证书等必要资料

 里面会有基本的配置介绍。

环境配置:

        会有两个配置文件,将它们放入到项目的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=="
            },

 然后将这些参数给前端,调用微信支付控件就能唤醒微信支付了。

唤醒农行掌银APP支付:

        首先使用农行的一码多扫下单接口,先拼接参数,再调用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 "<URL>https://xxx.xxx.com/result/index.shtml</URL>";
        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 "<URL>" + systemConfig.getNotifyUrl() + "/result/fail.shtml</URL>";
            }
        }
        return "<URL>" + systemConfig.getNotifyUrl() + "/result/success.shtml</URL>";
    }

农行这里有点奇葩的,返回要用<URL>标签包起来,而且我试过这个路径随便写也是能通过的。

还有一点,农行退费没有回调的,跟我对接的老哥告诉我没有,不知道是不是真的没有,文档也没找到。

评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值