Java-Spring Boot集成银联在线网关支付及回调处理(银联扫码等方式支付)
前言:最近开发银联支付功能,总结一下做个分享
官方API文档:https://open.unionpay.com/tjweb/api/dictionary?apiSvcId=448
银联测试地址:https://open.unionpay.com/tjweb/user/mchTest/index
SKD和DEMO下载:https://open.unionpay.com/tjweb/acproduct/list?apiSvcId=448&index=4
银联支付流程:
1、准备工作:获取银联测试参数数据(商户号,证书5.1.0)
2、集成SpringBoot,使用Java代码发起支付请求
3、银联收到支付请求后,返回HTML代码,用于前端展示二维码
4、扫码支付成功后,银联发送同步、异步通知请求,同步、异步通知路径可在配置文件中进行配置
5、收到异步通知结果后,进行验签,验签通过,返回成功信息通知银联不在进行异步通知
6、此时银联支付流程完成,调用银联查询接口,确认支付成功
一、准备工作,获取测试参数
打开上述银联测试地址,获取测试参数,需要使用云闪付账号进行登陆,登陆成功后,查看下图信息
二、集成Spring Boot,使用Java代码发起支付请求
1、从上述下载DEMO地址,下载SDK和DEMO
2、从DEMO里面把:
(1)acp_sdk.properties配置文件
(2)ACPSample_B2C\src\com\unionpay\acp\sdk目录下的工具类放进项目中
(3)ACPSample_B2C\src\com\unionpay\acp\demo目录下的DemoBase.java类放进项目中
(4)其他工具类视实际情况添加
3、acp_sdk.properties配置如下:
##############SDK配置文件(证书方式签名)################
# 说明:
# 1. 使用时请将此文件复制到src文件夹下替换原来的acp_sdk.properties。
# 2. 具体配置项请根据注释修改。
#
##########################################################################入网测试环境交易发送地址(线上测试需要使用生产环境交易请求地址)###############################交易请求地址
acpsdk.frontTransUrl=https://gateway.test.95516.com/gateway/api/frontTransReq.do
acpsdk.backTransUrl=https://gateway.test.95516.com/gateway/api/backTransReq.do
acpsdk.singleQueryUrl=https://gateway.test.95516.com/gateway/api/queryTrans.do
acpsdk.batchTransUrl=https://gateway.test.95516.com/gateway/api/batchTrans.do
acpsdk.fileTransUrl=https://filedownload.test.95516.com/
acpsdk.appTransUrl=https://gateway.test.95516.com/gateway/api/appTransReq.do
acpsdk.cardTransUrl=https://gateway.test.95516.com/gateway/api/cardTransReq.do#以下缴费产品使用,其余产品用不到
acpsdk.jfFrontTransUrl=https://gateway.test.95516.com/jiaofei/api/frontTransReq.do
acpsdk.jfBackTransUrl=https://gateway.test.95516.com/jiaofei/api/backTransReq.do
acpsdk.jfSingleQueryUrl=https://gateway.test.95516.com/jiaofei/api/queryTrans.do
acpsdk.jfCardTransUrl=https://gateway.test.95516.com/jiaofei/api/cardTransReq.do
acpsdk.jfAppTransUrl=https://gateway.test.95516.com/jiaofei/api/appTransReq.do######################################################################### 报文版本号,固定5.1.0,请勿改动
acpsdk.version=5.1.0# 签名方式,证书方式固定01,请勿改动
acpsdk.signMethod=01# 是否验证验签证书的CN,测试环境请设置false,生产环境请设置true。非false的值默认都当true处理。
acpsdk.ifValidateCNName=false# 是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false。非true的值默认都当false处理。
acpsdk.ifValidateRemoteCert=false#后台通知地址,填写接收银联后台通知的地址,必须外网能访问
acpsdk.backUrl=http://222.222.222.222:8080/ACPSample_B2C/backRcvResponse#前台通知地址,填写银联前台通知的地址,必须外网能访问
acpsdk.frontUrl=http://localhost:8080/ACPSample_B2C/frontRcvResponse#########################入网测试环境签名证书配置 ################################
# 多证书的情况证书路径为代码指定,可不对此块做配置。
# 签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到。
# windows样例:
acpsdk.signCert.path=D:/certs/acp_test_sign.pfx
# linux样例(注意:在linux下读取证书需要保证证书有被应用读的权限)(后续其他路径配置也同此条说明)
#acpsdk.signCert.path=/SERVICE01/usr/ac_frnas/conf/ACPtest/acp700000000000001.pfx# 签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败
acpsdk.signCert.pwd=000000
# 签名证书类型,固定不需要修改
acpsdk.signCert.type=PKCS12##########################加密证书配置################################
# 敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用)
acpsdk.encryptCert.path=D:/certs/acp_test_enc.cer##########################验签证书配置################################
# 验签中级证书路径(银联提供)
acpsdk.middleCert.path=D:/certs/acp_test_middle.cer
# 验签根证书路径(银联提供)
acpsdk.rootCert.path=D:/certs/acp_test_root.cer
4、创建Controller
public class UnionpayOnLineController{@PostMapping("/goPay")@ResponseBodypublic Result<Object> goPay(@RequestBody Map<String, Object> map) throws Exception {// 1、获取参数resp.setContentType("text/html; charset="+ DemoBase.encoding);String merId = req.getParameter("merId");String txnAmt = req.getParameter("txnAmt");String orderId = req.getParameter("orderId");String txnTime = req.getParameter("txnTime");// 2、封装报文Map<String, String> requestData = new HashMap<String, String>();/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/requestData.put("version", DemoBase.version); //版本号,全渠道默认值requestData.put("encoding", DemoBase.encoding); //字符集编码,可以使用UTF-8,GBK两种方式requestData.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法requestData.put("txnType", "01"); //交易类型 ,01:消费requestData.put("txnSubType", "01"); //交易子类型, 01:自助消费requestData.put("bizType", "000201"); //业务类型,B2C网关支付,手机wap支付requestData.put("channelType", "07"); //渠道类型,这个字段区分B2C网关支付和手机wap支付;07:PC,平板 08:手机/***商户接入参数***/requestData.put("merId", merId); //商户号码,请改成自己申请的正式商户号或者open上注册得来的777测试商户号requestData.put("accessType", "0"); //接入类型,0:直连商户 requestData.put("orderId",orderId); //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则 requestData.put("txnTime", txnTime); //订单发送时间,取系统时间,格式为yyyyMMddHHmmss,必须取当前时间,否则会报txnTime无效requestData.put("currencyCode", "156"); //交易币种(境内商户一般是156 人民币) requestData.put("txnAmt", txnAmt); //交易金额,单位分,不要带小数点//requestData.put("reqReserved", "透传字段"); //请求方保留域,如需使用请启用即可;透传字段(可以实现商户自定义参数的追踪)本交易的后台通知,对本交易的交易状态查询交易、对账文件中均会原样返回,商户可以按需上传,长度为1-1024个字节。出现&={}[]符号时可能导致查询接口应答报文解析失败,建议尽量只传字母数字并使用|分割,或者可以最外层做一次base64编码(base64编码之后出现的等号不会导致解析失败可以不用管)。 requestData.put("riskRateInfo", "{commodityName=测试商品名称}");//前台通知地址 (需设置为外网能访问 http https均可),支付成功后的页面 点击“返回商户”按钮的时候将异步通知报文post到该地址//如果想要实现过几秒中自动跳转回商户页面权限,需联系银联业务申请开通自动返回商户权限//异步通知参数详见open.unionpay.com帮助中心 下载 产品接口规范 网关支付产品接口规范 消费交易 商户通知requestData.put("frontUrl", DemoBase.frontUrl);//后台通知地址(需设置为【外网】能访问 http https均可),支付成功后银联会自动将异步通知报文post到商户上送的该地址,失败的交易银联不会发送后台通知//后台通知参数详见open.unionpay.com帮助中心 下载 产品接口规范 网关支付产品接口规范 消费交易 商户通知//注意:1.需设置为外网能访问,否则收不到通知 2.http https均可 3.收单后台通知后需要10秒内返回http200或302状态码 // 4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200,那么银联会间隔一段时间再次发送。总共发送5次,每次的间隔时间为0,1,2,4分钟。// 5.后台通知地址如果上送了带有?的参数,例如:http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签,否则将会验签失败requestData.put("backUrl", DemoBase.backUrl);// 订单超时时间。// 超过此时间后,除网银交易外,其他交易银联系统会拒绝受理,提示超时。 跳转银行网银交易如果超时后交易成功,会自动退款,大约5个工作日金额返还到持卡人账户。// 此时间建议取支付时的北京时间加15分钟。// 超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败。requestData.put("payTimeout", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date().getTime() + 15 * 60 * 1000));////// 报文中特殊用法请查看 special_use_purchase.txt/////**请求参数设置完毕,以下对请求参数进行签名并生成html表单,将表单写入浏览器跳转打开银联页面**/Map<String, String> submitFromData = AcpService.sign(requestData,DemoBase.encoding); //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl(); //获取请求银联的前台地址:对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrlString html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData,DemoBase.encoding); //生成自动跳转的Html表单//将生成的html写到浏览器中完成自动跳转打开银联支付页面;这里调用signData之后,将html写到浏览器跳转到银联页面之前均不能对html中的表单项的名称和值进行修改,如果修改会导致验签不通过return Result.success(html);}/*** 异步通知支付结果* * @param request* @return* @throws AlipayApiException* @throws ParseException*/@PostMapping("/callBack")public void callBack(HttpServletRequest request, HttpServletResponse resp) throws Exception {LogUtil.writeLog("callBack接收后台通知开始");String encoding = req.getParameter(SDKConstants.param_encoding);// 获取银联通知服务器发送的后台通知参数Map<String, String> reqParam = getAllRequestParam(req);LogUtil.printRequestLog(reqParam);//重要!验证签名前不要修改reqParam中的键值对的内容,否则会验签不过if (!AcpService.validate(reqParam, encoding)) {LogUtil.writeLog("验证签名结果[失败].");//验签失败,需解决验签问题} else {LogUtil.writeLog("验证签名结果[成功].");//【注:为了安全验签成功才应该写商户的成功处理逻辑】交易成功,更新商户订单状态String orderId =reqParam.get("orderId"); //获取后台通知的数据,其他字段也可用类似方式获取String respCode = reqParam.get("respCode");//判断respCode=00、A6后,对涉及资金类的交易,请再发起查询接口查询,确定交易成功后更新数据库。}LogUtil.writeLog("callBack接收后台通知结束");//返回给银联服务器http 200 状态码resp.getWriter().print("ok");}/*** @Title: alipayQuery @Description: 交易查询 @param @param* map @param @return @param @throws Exception 设定文件 @return Result<Object>* 返回类型 @throws*/@PostMapping("/unionPayQuery")@ResponseBodypublic Result<Object> unionPayQuery(@RequestBody Map<String, Object> map) throws Exception {/** 调取支付订单号 */String outTradeNo = (String) map.get("rechargeId");if (StringUtils.isEmpty(outTradeNo)) {return Result.paramIsEmpty();}Map<String, String> data = new HashMap<String, String>();/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/data.put("version", DemoBase.version); //版本号data.put("encoding", DemoBase.encoding); //字符集编码 可以使用UTF-8,GBK两种方式data.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法data.put("txnType", "00"); //交易类型 00-默认data.put("txnSubType", "00"); //交易子类型 默认00data.put("bizType", "000201"); //业务类型 B2C网关支付,手机wap支付/***商户接入参数***/data.put("merId", "777290058110048"); //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试data.put("accessType", "0"); //接入类型,商户接入固定填0,不需修改/***要调通交易以下字段必须修改***/data.put("orderId", orderId); //****商户订单号,每次发交易测试需修改为被查询的交易的订单号data.put("txnTime", txnTime); //****订单发送时间,每次发交易测试需修改为被查询的交易的订单发送时间/**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/Map<String, String> reqData = AcpService.sign(data,DemoBase.encoding);//报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。String url = SDKConfig.getConfig().getSingleQueryUrl();// 交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.singleQueryUrl//这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过Map<String, String> rspData = AcpService.post(reqData,url,DemoBase.encoding);/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**///应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》if(!rspData.isEmpty()){if(AcpService.validate(rspData, DemoBase.encoding)){LogUtil.writeLog("验证签名成功");if("00".equals(rspData.get("respCode"))){//如果查询交易成功//处理被查询交易的应答码逻辑String origRespCode = rspData.get("origRespCode");if("00".equals(origRespCode)){//交易成功,更新商户订单状态//TODO}else if("03".equals(origRespCode) ||"04".equals(origRespCode) ||"05".equals(origRespCode)){//需再次发起交易状态查询交易 //TODO}else{//其他应答码为失败请排查原因//TODO}}else{//查询交易本身失败,或者未查到原交易,检查查询交易报文要素//TODO}}else{return Result.failError("验证签名失败");//TODO 检查验证签名失败的原因}}else{//未返回正确的http状态LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");}String reqMessage = DemoBase.genHtmlResult(reqData);String rspMessage = DemoBase.genHtmlResult(rspData);resp.getWriter().write("</br>请求报文:<br/>"+reqMessage+"<br/>" + "应答报文:</br>"+rspMessage+"");return Result.failError("系统异常,请重试");}
}
Result是自己定义的消息处理类,这里就不放出代码了,大家根据实际情况做处理
这里偷了一个懒,把所有代码都写在Controller里面了,大家写的时候记得分开写哦
到此SpringBoot整合银联扫码支付,就完成了
有什么问题大家多互相交流^_^
Java-Spring Boot集成银联在线网关支付及回调处理(银联扫码等方式支付)相关推荐
- spring boot 自动跳转登录页面_徒手撸一个扫码登录示例工程
徒手撸一个扫码登录示例工程 不知道是不是微信的原因,现在出现扫码登录的场景越来越多了,作为一个有追求.有理想新四好码农,当然得紧跟时代的潮流,得徒手撸一个以儆效尤 本篇示例工程,主要用到以下技术栈 q ...
- Spring boot 项目(十二)——实现电脑网页微信扫码自动授权
引言 电脑端微信网页扫码授权登录有2种方式: 第一种:基于微信公众号,单独获取登录二维码扫码,然后扫码登录,程序控制跳转逻辑,例如CSDN 第二种:基于微信开放平台,跳转到微信二维码页面进行扫码登录, ...
- Java Spring Boot 2.0实战Docker容器与架构原理,视频与课件,基于Linux环境...
Java Spring Boot 2.0实战Docker容器Linux与架构原理 内容摘要:Docker是最流行的开源容器引擎,Go语言开发,在互联网大规模集群.云计算.微服务等架构中广泛使用.本次课 ...
- Spring Boot集成支付宝电脑网站支付功能
Spring Boot集成支付宝电脑网站支付功能 接入准备 登录 创建应用 添加能力 生成私钥与公钥 开发设置 沙箱环境 示例Demo的使用与学习 下载Demo 启动项目 参数配置 执行测试 Spri ...
- PHP接入银联在线网关支付
网站支付:一般接入微信支付.支付宝支付.银联支付,本文介绍的是如何接入中国银联在线网关支付 银联介绍 银联在线支付网关是中国银联联合各商业银行为持卡人提供的集成化.综合性互联网支付工具,主要支持输入卡 ...
- 【Java进阶】Spring Boot集成ES
目录 spring boot集成ES ElasticSearchConfig 测试文档的基本操作 Elasticsearch Clients 文档 spring boot集成ES Java REST ...
- Spring Boot 集成 Druid 监控数据源
关注"Java后端技术全栈" 回复"面试"获取全套大厂面试资料 Druid 介绍 Druid 是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池.插件框架和 ...
- spring boot 集成 websocket 实现消息主动推送
前言 http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单向的,在很多场景就不适合,比如实时的推送,消息通知或者股票等信息 ...
- Spring Boot集成阿里云视频点播服务的过程记录
阿里云视频点播 效果预览 视频点播 视频点播概述 功能 优势 流程 环境准备 开通视频点播 创建RAM用户并授权 上传SDK 上传流程 下载上传SDK 安装上传SDK 集成Java上传SDK 异常说明 ...
- Spring Boot集成支付宝(最新版SDK)—— 手机支付
前言 前些日子写了一篇关于H5网页集成支付宝的文章: Spring Boot集成支付宝(最新版SDK)-- H5/网页支付 当时写了好久,往那一坐就是俩小时,写完直接就发布了,发布之后才感觉少点啥-- ...
最新文章
- JWT 身份认证优缺点分析以及常见问题解决方案
- linux运维新手参观机房后的心得体会
- gh0st源码分析:屏幕监控
- clob类型字段最大存储长度_请教oracle的CLOB字段的最大长度?
- 配置jdk和maven环境并测试
- 除了加强风控,大数据还能为FinTech做些什么?
- SysUtils.CompareStr、SysUtils.CompareText - 字符串比较
- JEP JAVA 初体验
- 百度ORC识别身份证,JXL导出信息到excel流水作业。
- 程序发生run time error原因及解决方案
- MyExcel 2.1.3 发布,提供行级读取处理能力
- Easyx-----c语言实现图形化打砖块
- 垂涎欲滴的互联网灰色产业链!
- 智能云防雷,信号浪涌保护器防雷接地方案
- MATLAB图像处理—imfindcircles的输出变量含义
- 虚幻4与现代C++:转移语义和右值引用
- 使用Tableau对综测成绩进行可视化数据分析
- K均值与DBSCAN聚类效果
- 使用微信小程序获取附近人的位置遇到的坑
- 刘邦韩信java_刘邦曾言三不杀韩信, 看懂后才知道是在玩他!