聊一聊Java如何接入招行一网通支付功能

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。博客源地址为zhixiang.org.cn https://blog.csdn.net/myFirstCN/article/details/81844046 1.前提条件 相比较于支付宝和微信的支付功能接入这一块,银行相对来说更加严格,比如说支付宝,在你签约之前可以进行一些测试。

版权声明:本文为博主原创文章,未经博主允许不得转载。博客源地址为zhixiang.org.cn https://blog.csdn.net/myFirstCN/article/details/81844046

1.前提条件
相比较于支付宝和微信的支付功能接入这一块,银行相对来说更加严格,比如说支付宝,在你签约之前可以进行一些测试。但是银行来说就不是这样了,如果您现在要进行招行的支付功能开发的话,请务必先让相关人员去进行签约

  1. 测试开发必须条件
    进行测试开发之前有几个比较重要的东西是不可避免的,我们来看一下都是有什么:

商户号、商户分行号以及商户秘钥
验证码查询地址(测试环境招行所发的验证码都可以在此网站查询到http://121.15.180.69/GetMsgVerifyCode/Default.aspx
API文档(进行签约时招行一般会给我们一份文档,但是此文档也是很有参考价值的
3.测试开发
咱们这次一个完整的支付流程为例
进入正式的开发之前咱们先来看一下一个图,这个图呢,简单介绍了一下这个支付的流程,并没有考虑失败的因素。仅供大家参考!

这里写图片描述

接下来呢,我们就按照上图所示的流程进行开发。

第一个相信不用费心,APP请求时携带一个订单号就行。
我们根据订单号查询出此订单关联的订单金额及用户等信息,然后呢参考此链接的请求报文要求的必填字段一一组合起来。

这里组合的时候有几个小小的问题,因为招行对我们发送的请求报文是有要求的:测试环境回调地址不支持域名,只能是纯IP地址,且端口只能为80、443、8081其中的一个。另外请求报文中的reqData字段里的内容要进行排序。最后,排序完的报文要进行签名。

这里进行排序的话我可以提供一种全新的思路,我们可以把待排序的字段使用一个dto封装起来类似于下面这种:

 //客户协议号。
private String agrNo;

//金额
private String amount;

 //银行订单流水号
private String bankSerialNo;

// 商户分行号
private String branchNo;

这样的dto转换成json串的时候是已经有序了的。

对参数进行签名的话怎可以参考招行为我们提供的代码示例。
需要注意的就是上方我们dto转成的是一个json串,但是签名要求的待签名的字符串格式是这样的。agrNo=xxx&amount=88.88&bankSerialNo=1234567&branchNo=xxx

排序以及签名完毕以后就可以把这个发送给APP了,我们发送给APP的就是下方这个形式的json:

{
  "version":"1.0",
  "charset":"UTF-8",
  "sign":"见签名处理章节",
  "signType":"SHA-256",
  "reqData":{
       "dateTime":"20161209112230",
       "branchNo":"0755",
       "merchantNo":"000054",
       "date":"20161209",
       "orderNo":"9999000001",
       "amount":"0.01",
       "expireTimeSpan":"30",
       "payNoticeUrl":"http://www.merchant.com/path/payNotice.do",
       "payNoticePara":"12345678|ABCDEFG|HIJKLM",
       "returnUrl":"http://www.merchant.com/path/return.do",
       "clientIP":"99.12.38.165",
       "cardType":"A",
       "agrNo":"12345678901234567890",
       "merchantSerialNo":"2016062014308888",
       "userID":"2016062388888"
       }
 }

APP收到服务器返回的请求报文,就可以组成如下表单向招行发送请求:

"http://121.15.180.66:801/NetPayment/BaseHttp.dll?MB_EUserPay" method="post" >
    type="hidden" name="jsonRequestData" value='服务端返回的请求报文' />
type="submit" >

这一块呢,也有一个需要注意的地方,因为有的时候我们服务端开发的时候可能APP还没有时间,如果我们每次都让人家帮忙也挺浪费时间的。这里也有一个快速测试的好办法。我们可以把上方的代码拿着自己建一个HTML文件,发送到自己手机上,然后使用手机浏览器打开其实也是可以的。

此时招行就会返回一个统一的支付页面
在这我们填入签约时招行给我们的测试账号等信息,账号支付使用的验证码请参考文章刚开始我们所说的网址
假设支付成功,那么招行就会回调我们请求参数所填的回调地址,这里其实是有两个回调地址的,一个是签约成功的回调,一个是支付成功的回调。

关于这些回调的问题一般我们会有两种方式解决,1呢是内网穿透,2呢就是远程Debug,因为招行的测试回调地址只能是ip所以这里我们就是要第二种方式,不熟悉远程Debug的同学可以参考我的另一篇博文IDEA远程Debug

我们就拿支付成功的回调来说。
招行会把参数放到一个jsonRequestData的属性里。我们可以通过以下方式来取得:
JSONObject jsonRequestData=JSONObject.parseObject(request.getParameter(“jsonRequestData”));
这个json里面的东西我们可以参考一下这个链接
有了这些东西我们就可以准确的知道此次支付的一些相关信息。

不过呢,这样有个问题呀,这东西要是别人伪造的怎么办呀。所以呢,这里还一个验签的过程,验证此次回调到底是不是招行发来的。

这个验签还牵扯到一个问题,那就是验签需要招行的公钥,而招行的公钥是会定期更新的,所以我们可以做一个定时任务定期去请求招行的公钥(关于定时任务的相关可以参考我的这篇博客:Java定时任务解决方案

使用我们上方所说的如何排序请求参数,如何进行签名。不过这个只需要在服务端请求就可以了,至于在服务端如何发送请求大家可以使用一下方式:

public static String doPost(String jsonParam, String url, String charset) {
       OutputStreamWriter out = null;
       BufferedReader in = null;
       StringBuffer result = new StringBuffer();
       try {
           URL httpUrl = new URL(url);
           HttpURLConnection urlCon = (HttpURLConnection) httpUrl.openConnection();
           urlCon.setRequestMethod("POST");
           urlCon.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
           urlCon.setDoOutput(true);
           urlCon.setDoInput(true);
           urlCon.setReadTimeout(5 * 1000);
           out = new OutputStreamWriter(urlCon.getOutputStream(), charset);
           out.write("jsonRequestData=" + jsonParam);
           log.info("the request to cmb jsonRequestData is :{}",jsonParam);
           out.flush();

           in = new BufferedReader(new InputStreamReader(urlCon.getInputStream(), charset));
           String str = null;
           while ((str = in.readLine()) != null) {
               result.append(str);
           }

       } catch (MalformedURLException e) {
           e.printStackTrace();
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           try {
               if (out != null) {
                   out.close();
               }
               if (in != null) {
                   in.close();
               }
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       return result.toString();
   }

既然公钥有了,我们就可以进行验签了。

如果验签通过的情况下我们就可以happy进行各种操作了。

不过呢,还有一点。记得给招行返回一个收到的信息
`

response.setStatus(HttpStatus.SC_OK);

`
你要是不告诉人家你收到了,他是会在间隔一段时间后再次发送通知,直到10个以后。

这个大流程终于走到这了,这个时候你是使用APP轮训,或者向APP推送告知支付完成的信息就是看你需求了。
结语
关于招行的支付功能是我上周刚刚亲手撸出来的代码,我想能踩的坑我基本上已经踩过了,如果大家在开发过程中遇到什么问题的话都可以来我的网站,我们一起交流讨论:石玉军的个人博客

本文出自http://zhixiang.org.cn,转载请保留。

相关文章
|
4月前
|
Java API Spring
打造未来电商新引擎:揭秘Java可扩展API设计,让支付与物流灵活如丝,引领电商时代潮流!
【8月更文挑战第30天】本文通过电商平台案例,探讨了如何设计可扩展的Java API。首先定义支付和物流服务的接口与抽象类,然后实现具体服务,接着引入工厂模式或依赖注入管理服务实例,最后通过配置实现灵活扩展。这种设计确保了应用架构的灵活性和长期稳定性。
60 3
|
1月前
|
安全 Java 测试技术
🎉Java零基础:全面解析枚举的强大功能
【10月更文挑战第19天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
116 60
|
26天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
27 2
|
2月前
|
Java 程序员
在Java编程中,关键字不仅是简单的词汇,更是赋予代码强大功能的“魔法咒语”。
【10月更文挑战第13天】在Java编程中,关键字不仅是简单的词汇,更是赋予代码强大功能的“魔法咒语”。本文介绍了Java关键字的基本概念及其重要性,并通过定义类和对象、控制流程、访问修饰符等示例,展示了关键字的实际应用。掌握这些关键字,是成为优秀Java程序员的基础。
25 3
|
2月前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
62 2
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
|
2月前
|
Java 数据安全/隐私保护
Java ffmpeg 实现视频加文字/图片水印功能
【10月更文挑战第22天】在 Java 中使用 FFmpeg 实现视频加文字或图片水印功能,需先安装 FFmpeg 并添加依赖(如 JavaCV)。通过构建 FFmpeg 命令行参数,使用 `drawtext` 滤镜添加文字水印,或使用 `overlay` 滤镜添加图片水印。示例代码展示了如何使用 JavaCV 实现文字水印。
124 1
|
2月前
|
机器学习/深度学习 算法 Java
通过 Java Vector API 利用 SIMD 的强大功能
通过 Java Vector API 利用 SIMD 的强大功能
50 10
|
2月前
|
Oracle 安全 Java
Java 22 为开发人员带来了重大增强功能
Java 22 为开发人员带来了重大增强功能
43 9
|
2月前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
27 1
|
4月前
|
Java 开发者
Java多线程教程:使用ReentrantLock实现高级锁功能
Java多线程教程:使用ReentrantLock实现高级锁功能
47 1