银联支付开发、使用的一些总结
现在的网页支付(PC和微信H5)和app支付,用的比较多的是微信支付、银联支付和支付宝支付,其余的是这些支付的第三方支付,我目前了解的只有这么多。我目前做了银联支付和微信支付,这里说一些银联支付的开发的一些介绍吧。
根据我们公司的应用经验,银联支付时费率最低的,如果和银联商务谈判的好,自身的交易量比较大,费率可能更低(具体不能透露了)。银联支付一种是按百分比收取手续费,另一种按笔数收取手续费,例如,每笔0.9元。我们公司用了2种银联支付,一开始用的是银联支付,后来因费率问题,使用银联支付第三方平台--千引支付,实质上也是银联支付。
我们申请的银联支付,在网上营业厅、微信服务号、Android和iOS平台都在使用,是“手机WAP支付产品”。主要用了2个接口,第一个是“消费类交易”,即银联支付申请接口。它也可以分为两部分,(1)通过拼接报文,签名加密,生成html网页,浏览器跳转请求到银联支付页面。此时,订单生成,用户可以在银联页面完成支付。(2)支付成功后,银联会根据请求参数里的配置,主动回调前台、后台通知地址,通知用户支付成功。第二个接口是“交易状态查询交易”,即查询订单交易结果。
现在具体讲一下代码:
消费类交易接口:官方文档地址:https://open.unionpay.com/ajweb/help/api
(1)交易申请。初始化证书,拼接报文,数据签名,创建表单或取得tn号。调用此接口,微信、网厅可得到一个html的https post表单,浏览器执行js自动提交,访问银联支付申请接口,跳转银联支付页面。此时,服务端只是拼接报文,签名加密,请求的动作,是用户的浏览器做的,可以保证银联支付的安全性。app端则是,调用接口,取得tn号,调用app已安装的银联控件跳往银联支付页面。
private String pc2UnionPay(String orderId, String incMoney,
String txnTime) {
/**
* 初始化证书
*/
SDKConfig.getConfig().loadPropertiesFromSrc();// 从classpath加载acp_sdk.properties文件
/**
* 交易请求url 从配置文件读取
*/
String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();
/**
* 组装请求报文
*/
Map<String, String> data = new HashMap<String, String>();
// 版本号
data.put("version", "5.0.0");
// 字符集编码 默认"UTF-8"
String encoding = "UTF-8";
data.put("encoding", encoding);
// 签名方法 01 RSA
data.put("signMethod", "01");
// 交易类型 01-消费
data.put("txnType", "01");
// 交易子类型 01:自助消费 02:订购 03:分期付款
data.put("txnSubType", "01");
// 业务类型 000201 B2C网关支付
data.put("bizType", "000201");
// 渠道类型 07-互联网渠道
data.put("channelType", "07");
// 商户/收单前台接收地址 选送
// 后台服务对应的写法参照 FrontRcvResponse.java
data.put("frontUrl", frontUrl);
// 商户/收单后台接收地址 必送
// 后台服务对应的写法参照 BackRcvResponse.java
data.put("backUrl", backUrl);
// 接入类型:商户接入填0 0- 商户 , 1: 收单, 2:平台商户
data.put("accessType", "0");
// 商户号码
data.put("merId", merId);
// 订单号 商户根据自己规则定义生成,每订单日期内不重复
data.put("orderId", orderId);
// 订单发送时间 格式: YYYYMMDDhhmmss 商户发送交易时间,根据自己系统或平台生成
data.put("txnTime", txnTime);
// 交易金额 分
data.put("txnAmt", incMoney);
// 交易币种
data.put("currencyCode", "156");
// 若报文中的数据元标识的key对应的value为空,不上送该报文域
/**
* 创建表单
*/
String html = null;
for (int i = 1; i <= 3; i++) {
html = createHtml(requestFrontUrl, signData(data));
if (html != null) {
return html;
}
}
return "服务器忙";
}
public static String createHtml(String action, Map<String, String> hiddens) {
StringBuffer sf = new StringBuffer();
sf.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/></head><body>");
sf.append("<form id = \"pay_form\" action=\"" + action
+ "\" method=\"post\">");
if (null != hiddens && 0 != hiddens.size()) {
Set<Entry<String, String>> set = hiddens.entrySet();
Iterator<Entry<String, String>> it = set.iterator();
while (it.hasNext()) {
Entry<String, String> ey = it.next();
String key = ey.getKey();
String value = ey.getValue();
sf.append("<input type=\"hidden\" name=\"" + key + "\" id=\""
+ key + "\" value=\"" + value + "\"/>");
}
}
sf.append("</form>");
sf.append("</body>");
sf.append("<script type=\"text/javascript\">");
sf.append("document.all.pay_form.submit();");
sf.append("</script>");
sf.append("</html>");
return sf.toString();
}
(2)支付成功通知商户。根据申请时取得的前后台通知地址,银联在支付成功后,会主动通知商户交易结果,但应以后台通知为准。前台应答是通过 浏览器,用户点击“返回商户”按钮发送给商户的,后台通知是银联系统异步把交易状态为成功的交易通知给商户,失败交易不发送。前台应答及后台通知,商户都需要验签。
public class BackNoticeServlet extends HttpServlet {
private static final long serialVersionUID = -900467945307979675L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
LogUtil.writeLog("后台接收银行通知开始……");
BankService bService = (BankService) PayCache.getInstance().getBean("bankService");
RechargeService service = (RechargeService)PayCache.getInstance().getBean("rechargeService");
// request.setCharacterEncoding("ISO-8859-1");
String encoding = request.getParameter(SDKConstants.param_encoding);
// 获取请求参数中所有的信息
Map<String, String> reqParam = getAllRequestParam(request);
// 打印请求报文
LogUtil.printRequestLog(reqParam);
Map<String, String> valideData = null;
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("ISO-8859-1"), encoding);
valideData.put(key, value);
}
Map<String, String> res = new HashMap<String, String>();
// 验证签名
if (!SDKUtil.validate(valideData, encoding)) {
LogUtil.writeLog("验证签名结果[失败].");
} else {
LogUtil.writeLog("验证签名结果[成功].");
// 持久化银行返回的数据
LogUtil.writeLog("持久化银行返回的数据");
String settleDate = reqParam.get("settleDate");
Calendar cal=Calendar.getInstance();
settleDate = String.valueOf(cal.get(Calendar.YEAR)) + settleDate;//加上年份
reqParam.put("settleDate", settleDate);
service.addPayresult(reqParam);
if("00".equals(reqParam.get("respCode"))){
service.updOrder(reqParam.get("orderId"),settleDate);
}
LogUtil.writeLog("返回银行数据给商户开始……");
res.put("respCode", reqParam.get("respCode"));
res.put("respMsg", reqParam.get("respMsg"));
res.put("orderId", reqParam.get("orderId"));
res.put("txnTime", reqParam.get("txnTime"));
res.put("txnAmt", reqParam.get("txnAmt"));
res.put("queryId", reqParam.get("queryId"));
res.put("settleDate", reqParam.get("settleDate"));
res.put("settleAmt", reqParam.get("settleAmt"));
res.put("txnType", reqParam.get("txnType"));
String statusCode = "";
ProfitApplyOrder order = bService.queryOrder(reqParam.get("orderId"));
for(int i=0;i<5;i++){
statusCode = XmlUtil.invokeMethod(res,order.getBackUrl());
if(statusCode.equals("success")){
LogUtil.writeLog("返回银行数据给商户结束[成功].");
break;
}
}
LogUtil.writeLog("银行数据接受完成!");
}
}
} catch (Exception e) {
e.printStackTrace();
LogUtil.writeLog("接受银行数据失败:" + e.getMessage());
} finally {
response.setHeader("Content-type", "text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.print(System.currentTimeMillis());
writer.flush();
}
}
public static Map<String, String> getAllRequestParam(
final HttpServletRequest request) {
Map<String, String> res = new HashMap<String, String>();
Enumeration<?> temp = request.getParameterNames();
if (null != temp) {
while (temp.hasMoreElements()) {
String en = (String) temp.nextElement();
String value = request.getParameter(en);
res.put(en, value);
// 在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段>
// System.out.println(" temp数据的键=="+en+" 值==="+value);
if (null == res.get(en) || "".equals(res.get(en))) {
res.remove(en);
}
}
}
return res;
}
}
交易状态查询交易:(以下摘自银联官方文档)
商户收到后台通知后,应根据通知报文中订单号等关键信息,更新系统中的订单支付状态。
商户在以下情况下,可主动发起交易状态查询,并根据查询结果更新交易状态。
(1)前台交易,在5分钟内未收到后台通知。
(2)后台交易,在1秒内未收到后台通知 。
(3)商户在特殊情况下没有正确处理后台通知,需要重新判定交易状态。
商户应注意对同一笔交易,对不同时间点可能先后收到的查询结果及后台通知进行合适的处理。
以上,此接口调用查询订单交易结果,是商户主动发起的,没什么好说的,把官方文档贴了一下。附上交易应答码地址:https://open.unionpay.com/ajweb/help?id=262
银联支付开发、使用的一些总结相关推荐
- 西米支付:支付宝/微信支付/银联支付通道的接入介绍
本文以电脑网站支付为例,着重对第三方支付通道的接入进行了分析,包括支付宝支付接入.微信支付接入及银联支付接入. 1.支付宝支付接入 支付宝支付能力主要有当面付.刷脸付.App支付.手机网站支付.电脑网 ...
- H5APP WEB 支付开发 (银联 微信 支付宝)流程
这里采用ionic+angular进行前台开发 ssh+jpay做后台支付接口 银联:配置好参数 接口采用JPAY 他会自动生成HTML并提交表单到银联 app只需用iframe套用就行 paylog ...
- php银联支付接口 demo,php版银联支付接口开发简单实例详解
这篇文章主要介绍了php版银联支付接口开发的方法,结合实例形式分析了php银联支付接口开发的具体流程与相关操作技巧,需要的朋友可以参考下 支付接口现在有第三方的支付接口也有银行的支付接口.这里就来介绍 ...
- iOS开发 支付之银联支付集成
iOS开发之银联支付集成 最近在做支付这一块的东西,就记录下来以便以后参考和各位交流学习,这里是银联支付 银联官网在这里,这里能下载SDK或者是看文档.文档嘛,对银联来说,还是不要看的太仔细的好,以前 ...
- Android开发之——银联支付深入
前言 上一遍讲解了银联支付的入门和演示,这篇文章继续介绍银联支付中的一些关键点解析和注意事项,希望对在银联开发接入的你有所帮助. 银联支付接入流程 第一步:申请入网 入网即签约,分银联官网注册和服务商 ...
- Android开发:app工程集成银联支付功能(服务器端)
一功能描述 二实现过程 1下载银联支付SDK和Demo 1银联商家服务地址httpsopenunionpaycomajwebindex 2下载的文件如下 2集成过程 1先试官方Demo 2集成到自己的 ...
- Android开发:app工程集成银联支付功能(客户端)
Android开发:app工程集成银联支付功能(客户端) email:chentravelling@163.com 上一篇博文完成了服务器端的集成,可参考: Android开发:app工程集成银联支付 ...
- 玩转iOS开发:集成 Union Pay - 银联支付
文章转至:https://cainrun.github.io/14740149724404.html 作者感言 前面已经把WeChat SDK的支付, AliPay SDK搞得七七八八了, 接下来就是 ...
- Android开发之——银联支付初探
前言 现在网上支付用的比较多的是微信支付,支付宝支付和银联支付.关于微信和支付宝支付前面已经讲过了,本文主要介绍关于银联支付集成的过程和步骤. 银联支付 资源查找 集成文档 点击上面的集成文档,打开如 ...
最新文章
- 清华大学计算机李雪,李雪 | 北京外国语大学国际商学院|International Business School,BFSU|本硕博,北外留学,来华留学Solbridge,EDP...
- php处理二进制,PHP应用:PHP处理二进制数据的实现方法
- android百度地图覆盖物异步加载图片,Android 百度地图marker中图片不显示的解决方法(推荐)...
- python----面向对象:1类的定义
- 解决QT5中文显示出现乱码
- 滑动窗口解决最小子串问题 leetcode3. Longest Substring Without Repeating Characters
- No qualifying bean of type;Unsatisfied dependency expressed through field 解决办法(总结全网)
- 韦东山freeRTOS系列教程之【第五章】队列(queue)
- 黑苹果卡在苹果logo_黑苹果的历史
- 使程序在后台运行,后台进程实现原理
- 平房误差函数_平方误差函数(square error function)与平方损失函数(square loss function)...
- MATLAB与信号处理课程手册
- 【Windows11+Ubuntu20.04】双系统安装及美化、优化记录
- 【电路设计小白】ADC芯片配置学习之一初期理论
- IDE 的主题应该用亮色还是暗色?终极答案来了!
- 操作教程:大华摄像头通过GB28181协议注册EasyCVR平台的详细配置
- Python爬虫爬取智联招聘(进阶版)
- JVM笔记:Java虚拟机的字节码指令详解
- go module无法下载golang.org/x
- 安卓小项目之EveryDay(6)----使用第三方平台获取短信验证码