前言:由于支付宝和微信支付都须要提供这个那个的认证材料,对于个人开发者想尝试,确实有不少麻烦,今天介绍的银联支付,对于个人开发者,可以说是福音了。来自chentravelling的实践银联支付,chentravelling对应的blog地址为:http://blog.csdn.net/chentravelling。点击【阅读原文】,可看对应原文。

一.功能描述

因为是自己开发了一个app应用,没资格去申请微信支付和支付宝支付,于是就采用了银联支付功能,银联支付分为了两种环境:测试环境和生产环境,一般前期开发的时候都是使用测试环境,数据都是测试数据,不会发生真实交易。第一次做Android项目+IDE为Android Studio+第一次集成支付功能,所以个人觉得整个集成过程可能有点复杂,而且银联支付产品众多:网关支付产品、手机控件支付、手机网页支付等等,第一次看的时候真是云里雾里,不知道选哪个,不知道他们的区别,最后自己选择了手机控件支付,先试试,光看没有用。自己做了多少写多少,好记性不如烂笔头,就怕后面想记录的时候忘记了前面的过程。

二.实现过程

2.1下载银联支付SDK和Demo

(1)银联商家服务地址:https://open.unionpay.com/ajweb/index

第一步:注册;

第二步:然后在帮助中心界面的产品分类下载里选择手机控件支付; 

第三步:下载安卓版的开发包。 

(2)下载的文件如下

2.2集成过程

个人建议可以先把服务器端的工程跑一下,这样结合代码的时候就很容易明白怎么集成到自己的工程里了。所以这一小部分内容是官方Demo的运行情况,需要修改的配置很少,但是还是有小地方需要调整一下。

(1)先试官方Demo

  • 将工程导入

  • 修改acp_sdk_properties的配置

将这三个路径修改为测试环境证书的路径(证书在assets文件夹下),可以使用相对路径或者绝对路径都行,下面图中是绝对路径,我把assets/测试环境证书下的三个文件移动到了C盘。 

我的测试环境证书地址: 

  • Run一个试试

启动tomcat过程中比较关键的一处就是 

  • 首页

  • 获取tn


最后打印的报文

(2)集成到自己的工程里

先讲服务器端,因为自己也才完成了这部分工作。运行了官方Demo以及相关说明文档后,整体思路其实就有了。 
首先试试配置!!!

  • jar包

将Demo工程lib中的jar包复制到自己工程的lib里(如果已经有jar包了,就不需要复制了) 

  • 修改acp_sdk_propertise和log4j.properties

    主要是一些路径的修改,因为我的服务器上只有C盘,所以我必须得改,acp_sdk_properties的修改见(1)运行Demo部分)

  • 导入相关java文件

之所以写用import的方式是为了少出现乱码的问题,见下图

  • 第一部分 controller对应于Demo中的ACPSample_AppServer\src\com\unionpay\acp\demo,其中PayController是我自己写的Controller。

  • 第二部分model对应于Demo中的ACPSample_AppServer\src\com\unionpay\acp\sdk

  • 第三部分的两个java文件对应于Demo中的\ACPSample_AppServer\src\web中的两个java文件

  • web.xml配置

<servlet><servlet-name>autoLoadServlet</servlet-name><servlet-class>com.XXX.component.pay.AutoLoadServlet</servlet-class><load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>autoLoadServlet</servlet-name><url-pattern>/autoLoadServlet</url-pattern>
</servlet-mapping>

ok,配置过程就算完事了,现在就该写PayController来接受请求了。

  • PayController控制器 
    其实就是Form05_6_2_AppConsume.java中的代码,因为使用是SSM架构,就改了改架构而已。

@Controller
public class PayController extends BasicController{@RequestMapping(value = "/pay/pay")@ResponseBodypublic void pay(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {request.setCharacterEncoding(DemoBase.encoding_UTF8);//response.setContentType("text/html; charset="+ DemoBase.encoding_UTF8);//这两句是我临时加的,因为出现了乱码Map<String, String> contentData = new HashMap<String, String>();/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/contentData.put("version", DemoBase.version);            //版本号 全渠道默认值contentData.put("encoding", DemoBase.encoding_UTF8);     //字符集编码 可以使用UTF-8,GBK两种方式contentData.put("signMethod", "01");                    //签名方法 目前只支持01:RSA方式证书加密contentData.put("txnType", "01");                       //交易类型 01:消费contentData.put("txnSubType", "01");                    //交易子类 01:消费contentData.put("bizType", "000201");                   //填写000201contentData.put("channelType", "08");                   //渠道类型 08手机String merId = request.getParameter("merId");String txnAmt = request.getParameter("txnAmt");String orderId = request.getParameter("orderId");String txnTime = request.getParameter("txnTime");/***商户接入参数***/contentData.put("merId", merId);                        //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试contentData.put("accessType", "0");                     //接入类型,商户接入填0 ,不需修改(0:直连商户, 1: 收单机构 2:平台商户)contentData.put("orderId", orderId);                    //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则   contentData.put("txnTime", txnTime);                    //订单发送时间,取系统时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效contentData.put("accType", "01");                       //账号类型 01:银行卡02:存折03:IC卡帐号类型(卡介质)contentData.put("txnAmt", txnAmt);                      //交易金额 单位为分,不能带小数点contentData.put("currencyCode", "156");                 //境内商户固定 156 人民币//contentData.put("reqReserved", "透传字段");              //商户自定义保留域,交易应答时会原样返回//后台通知地址(需设置为外网能访问 http https均可),支付成功后银联会自动将异步通知报文post到商户上送的该地址,【支付失败的交易银联不会发送后台通知】//后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知//注意:1.需设置为外网能访问,否则收不到通知    2.http https均可  3.收单后台通知后需要10秒内返回http200或302状态码 //    4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200或302,那么银联会间隔一段时间再次发送。总共发送5次,银联后续间隔1、2、4、5 分钟后会再次通知。//    5.后台通知地址如果上送了带有?的参数,例如:http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签,否则将会验签失败contentData.put("backUrl", DemoBase.backUrl);//[其实还没搞明白这个地址的作用]/**对请求参数进行签名并发送http post请求,接收同步应答报文**/Map<String, String> reqData = AcpService.sign(contentData,DemoBase.encoding_UTF8);           //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。String requestAppUrl = SDKConfig.getConfig().getAppRequestUrl();                                 //交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrlMap<String, String> rspData = AcpService.post(reqData,requestAppUrl,DemoBase.encoding_UTF8);  //发送请求报文并接受同步应答(默认连接超时时间30秒,读取返回结果超时时间30秒);这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**///应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》if(!rspData.isEmpty()){if(AcpService.validate(rspData, DemoBase.encoding_UTF8)){LogUtil.writeLog("验证签名成功");String respCode = rspData.get("respCode") ;if(("00").equals(respCode)){//成功,获取tn号//String tn = resmap.get("tn");//这里应该是rspData.get("tn");//TODO}else{//其他应答码为失败请排查原因或做失败处理//TODO}}else{LogUtil.writeErrorLog("验证签名失败");//TODO 检查验证签名失败的原因}}else{//未返回正确的http状态LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");}String reqMessage = DemoBase.genHtmlResult(reqData);String rspMessage = DemoBase.genHtmlResult(rspData);try {response.getWriter().write("请求报文:<br/>"+reqMessage+"<br/>" + "应答报文:</br>"+rspMessage+"");//response.getOutputStream().write(("请求报文:<br/>"+reqMessage+"<br/>" + "应答报文:</br>"+rspMessage+"").getBytes("UTF-8"));} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
  • 运行

然后浏览器输入(get方式,在Form05_6_2_AppConsume.java中get和post方式是一样的,我的PayController因为没有指定请求方式,所以两种方式也是兼容的,而且只是为了测试采用的get,后面把客户端搭好,就用post方式) 
:http://123.XX.XXX.127:8080/intveh/pay/pay?merId=777290058110048&txnTime=20160505092851&orderId=20160505092851&txnAmt=5

效果和官方Demo一样: 

目前就把服务器端的tn获取搭好了.

2016年5月6日补充

服务器端还应该有“后台通知接收处理”部分。可参见Demo中ACPSample_AppServer\src\com\unionpay\acp\demo\BackRcvResponse.java。这部分的功能很重要:见下图所示(银联支付流程图)

见下图所示(银联支付流程图)

第七步是银联后台将支付结果返回给我们的服务器端,我们将根据返回结果更新订单的状态,请注意:虽然第八步是将客户端的支付控件也会支付结果,但是能作为订单支付结果的只有后台的通知,官方文档中有一处说的有歧义,客服是这样说的:

关于客户端支付结果+验签,在下一篇文档中说明。

3.3后台通知接收处理配置

(1)修改DemoBase.java中的backUrl

请注意:这个backUrl必须填写真实ip地址,回路地址不行、localhost不行,银联后台返回通知必须能post到你的backUrl。

2)后台通知处理部分

/**
* 后台通知处理
* @param sign
* @param request
* @param response
*/
@RequestMapping(value = "/pay/backRcvResponse")
@ResponseBody
public void backRcvResponse(HttpServletRequest request, HttpServletResponse response) {System.out.println("后台通知验签开始");//return AcpService.validateAppResponse(sign, DemoBase.encoding_UTF8);//System.out.println("验签开始");String encoding = request.getParameter(SDKConstants.param_encoding);// 获取银联通知服务器发送的后台通知参数Map<String, String> reqParam = Tool.getAllRequestParam(request);LogUtil.printRequestLog(reqParam);Map<String, String> valideData = null;try{if (null != reqParam && !reqParam.isEmpty()) {Iterator<Entry<String, String>> it = reqParam.entrySet().iterator();valideData = new HashMap<String, String>(reqParam.size());while (it.hasNext()) {Entry<String, String> e = it.next();String key = (String) e.getKey();String value = (String) e.getValue();value = new String(value.getBytes(encoding), encoding);valideData.put(key, value);}}//重要!验证签名前不要修改reqParam中的键值对的内容,否则会验签不过if (!AcpService.validate(valideData, encoding)) {LogUtil.writeLog("验证签名结果[失败].");//验签失败,需解决验签问题} else {LogUtil.writeLog("验证签名结果[成功].");//【注:为了安全验签成功才应该写商户的成功处理逻辑】交易成功,更新商户订单状态//valideData里封装了很多数据,可参考官方文档,做相应后续处理}}LogUtil.writeLog("BackRcvResponse接收后台通知结束");//返回给银联服务器http 200  状态码response.getWriter().print("ok");}catch(Exception e){}
}

ok,backUrl配置正确,那么进行支付后,商户后台就会得到银联后台的支付通知,如下图: 

这部分工作不能少,一定要记住后台通知处理的作用:真正作为接收订单支付结果的地方。

以上是服务端的过程,接下来看客户端的过程

一.功能描述

银联支付流程如下所示: 

上一篇尝试了tn的获取,本篇将跑通整个流程。

二.实现部分

先说一下我的IDE是as(Android Studio)+win7 64位

2.1配置,依旧是配置

按照官方说明文档,就可以完成,我在这里贴上结构图,因为as的特殊性。

  • jar包、.so文件和.bin文件

    因为我的工程资源有点多了,一张图截不下,所以我只给出文件夹的结构图。

  • 拷贝upmp_android/sdkPro/jar/data.bin到工程的assets文件夹中;

  • 拷贝upmp_android/sdkPro/jar/xxx/libentryexpro.so和upmp_android/sdkPro/jar/xxx/libuptsmaddon.so到工程的armeabi-v7a文件夹中(官方说v8 v7 abi都行)

    拷贝upmp_android/sdkPro/UPPayAssistEx.jar到工程的libs/目录下;

    拷贝upmp_android/sdkPro/jar/UPPayPluginExPro.jar到工程的libs/目录下;

  • AndroidManifest.xml添加配置

<!-- 银联支付相关配置 -->
<uses-libraryandroid:name="org.simalliance.openmobileapi"android:required="false" />
<activityandroid:name="com.unionpay.uppay.PayActivity"android:configChanges="orientation|keyboardHidden"android:excludeFromRecents="true"android:label="@string/app_name"android:screenOrientation="portrait"android:windowSoftInputMode="adjustResize" />
<activityandroid:name="com.unionpay.UPPayWapActivity"android:configChanges="orientation|keyboardHidden"android:screenOrientation="portrait"android:windowSoftInputMode="adjustResize" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc.hce" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="org.simalliance.openmobileapi.SMARTCARD" />

2.2.1调用支付接口

import com.unionpay.UPPayAssistEx;
//在调用支付控件的代码按以下方式调用支付控件
//比如onclick或者handler等等...
/*参数说明:
activity —— 用于启动支付控件的活动对象
spId —— 保留使用,这里输入null
sysProvider —— 保留使用,这里输入null
orderInfo —— 订单信息为交易流水号,即TN,为商户后台从银联后台获取。
mode —— 银联后台环境标识,“00”将在银联正式环境发起交易,“01”将在银联测试环境发起交易
返回值:
UPPayAssistEx.PLUGIN_VALID —— 该终端已经安装控件,并启动控件
UPPayAssistEx.PLUGIN_NOT_FOUND — 手机终端尚未安装支付控件,需要先安装支付控件
*/
String serverMode = "01";
UPPayAssistEx.startPay (activity, null, null, tn, serverMode);

2.2.2接收支付结果

支付完成后,获取支付控件支付结果,并添加相应处理逻辑,只需实现调用Activity中的onActivityResult()方法即可,支付成功时会返回商户客户端支付结果的签名信息。

  • 官方Demo是这样的: 
    其中有一句:此处的verify,商户需送去商户后台做验签 ,请注意并不是在这里向后台请求验签,因为后台也会接收到银联后台的支付结果通知,验签是在商户后台做.

protected void onActivityResult(int requestCode, int resultCode, Intent data) {if (data == null) {return;}String str = data.getExtras().getString("pay_result");if (str.equalsIgnoreCase(R_SUCCESS)) {// 支付成功后,extra中如果存在result_data,取出校验// result_data结构见c)result_data参数说明if (data.hasExtra("result_data")) {String sign = data.getExtras().getString("result_data");// 验签证书同后台验签证书// 此处的verify,商户需送去商户后台做验签if (verify(sign)) {//验证通过后,显示支付结果showResultDialog(" 支付成功! ");} else {// 验证不通过后的处理// 建议通过商户后台查询支付结果}} else {// 未收到签名信息// 建议通过商户后台查询支付结果}} else if (str.equalsIgnoreCase(R_FAIL)) {showResultDialog(" 支付失败! ");} else if (str.equalsIgnoreCase(R_CANCEL)) {showResultDialog(" 你已取消了本次订单的支付! ");}
}

由此就基本完成了客户端的集成,当然还有一些:支付失败的处理、取消订单的处理,以及退货、退款等等处理,等有时间再完善了。

本想截图的!!手机暂时出现了无法截图的毛病...

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

Android支付实践(三)之银联支付功能(客户端+服务端)相关推荐

  1. 急急急~!求一款源码~!背背恋Android约会交友APP完整源码(客户端+服务端)~!

    急急急!求一款源码!背背恋Android约会交友APP完整源码(客户端+服务端)~!

  2. android 仿微信demo————注册功能完善添加头像功能(服务端)

    android 仿微信demo----微信启动界面实现 android 仿微信demo----注册功能实现(移动端) android 仿微信demo----注册功能实现(服务端) android 仿微 ...

  3. 手机版电台功能php源码,android音乐电台APP源码(客户端+服务端)

    android音乐电台APP源码(客户端+服务端),支持MP3 , AAC | AAC+ stream,包含Android Studio 2客户端源码.php+mysql服务端源码,功能强大,代码规范 ...

  4. android 仿微信demo————微信消息界面实现(服务端)

    android 仿微信demo----微信启动界面实现 android 仿微信demo----注册功能实现(移动端) android 仿微信demo----注册功能实现(服务端) android 仿微 ...

  5. Android:在同一WiFi下通讯(局域网下服务端和客户端通讯)

    ​ 看了几天的Android WiFi通讯,总结一下,并附相关Demo(也是仿网上做的),建议收藏 ​ 两台设备(手机与手机,手机与硬件都一样)在同一WiFi下通讯,用的是TCP/IP协议,那我们应如 ...

  6. 导出Excel功能-从服务端到浏览器的简单处理

    导出Excel功能 从服务端到浏览器的简单处理, 仅供参考 服务端定义一个导出功能的关键代码 Java 定义一个export的功能函数,以下为关键代码(接口中的一部分处理逻辑): @Override ...

  7. android校园二手市场客户端+服务端源代码

    前语 最近在做学科期末设计,就想做一个校园二手市场(有JSP服务端),就在网上找了好多的资料,终于做完了,快吐血了(噗噗)不说废话,把效果图粘一下. 效果图 主界面 商品浏览 上传商品 查看留言界面 ...

  8. 支付系统设计三:渠道网关设计02-客户端报文解析

    文章目录 前言 一.后台配置管理 1.1 渠道配置 1.1.1 渠道基本信息新增 1.1.2 渠道交易类型配置 1.1.3 渠道商户信息配置 1.1.4 账户配置 1.1.5 交易类型机构配置 1.2 ...

  9. java 银联支付_java服务器端移动银联支付的流程

    一,银联支付的整体流程 客户端提供服务器给服务器订单信息----服务器端拿到数据推送给银联指定的地址----银联给服务器端返回一个流水账号----服务器将流水账号返给客户端 ----客户端由于集成了银 ...

  10. 基于Springboot+支付宝小程序会员开卡功能的服务端实现总结

    简述 因为业务需要,公司项目的支付宝小程序服务端,要能够支持在线会员卡的开卡与发卡操作,自己参考支付宝官方文档实现了功能,但是开发过程中遇到很多问题,索性基本都解决了,现在有时间做一下总结. 官方开发 ...

最新文章

  1. react入门代码_如何在React中构建温度控制应用程序-包括提示和入门代码
  2. 例题5-8 Unixls命令(Unix ls,UVa400)
  3. Docker部署Jmeter 性能监控服务(常用命令)
  4. 简要说明__python3中的进程/线程/协程
  5. Qt中打开excel文件
  6. 2016二级c语言笔试内容,2016年计算机二级c语言笔试试题「最新」
  7. mongo connections url string 的问题
  8. java中判断两个方法是否相同
  9. JPA和Hibernate级联类型的初学者指南
  10. C++课程上 有关“指针” 的小结
  11. 【LeetCode】剑指 Offer 11. 旋转数组的最小数字
  12. PDA平台上MessageBox和SIP的冲突
  13. VS2017如何创建c语言项目
  14. 史上最完美将windows键盘映射成mac键盘,绝对不需要买HHKB了
  15. ENVI下Landsat8辐射定标与大气校正
  16. 暴力破解QQ空间设置的问题
  17. gie拉取Can‘t update master has no tracked branch
  18. 钛资本研究院:科技创投,ToB也性感
  19. C语言 命令行 execl函数
  20. 后台(11)——Servlet(3)

热门文章

  1. std::thread的常用参数传递总结
  2. PCL中的ICP算法(Registration模块之IterativeClosestPoint点云配准)
  3. 深度学习笔记_基本概念_Depthwise卷积与Pointwise卷积
  4. 关于图神经网络的相关学习资源的分享——网站 博客(一)
  5. 给定一个无序数组,包含正数、负数和0,要求从中找出3个数的乘积,使得乘积最大
  6. SSD物体检测(附源代码,可以直接运行)
  7. 使用BAPI批量修改采购信息记录的税率
  8. 【01】魔芋使用MDN的一点点经验
  9. weblogic调整多个服务启动顺序方法
  10. Python之路-Day2