银联支付,实现代码对接

简介: 和其他支付平台一样,根据不同的移动端银联也提供了相应的支付渠道,比如在线网关支付、云闪付APP支付(原手机支付控件)、企业网银支付(商户版)、手机网页支付(WAP支付)、二维码支付等。

做过支付的同学都知道,支付宝和微信支付只适合小额付款,如果遇到业务场景是大额支付的,还是得对接银联支付。

和其他支付平台一样,根据不同的移动端银联也提供了相应的支付渠道,比如在线网关支付、云闪付APP支付(原手机支付控件)、企业网银支付(商户版)、手机网页支付(WAP支付)、二维码支付等。

要对接平台接口第一步自然是要有账号,注册账号的过程就不多说了。

image.png

选择需要对接的产品填写信息,提交入网申请,会有商务对接。

image.png

很友好的是,平台会提供测试参数用来调试接口,在个人中心-商户入网测试中心-测试参数,包括测试商户号、测试证书、测试地址。

image.png

有了这些东西,就可以开始写代码调试接口了,当然了,最让人舒心的是,平台也有提供SDK供你参考,实测了一下,确实只是仅供参考,因为跑不起来,哈哈😀。
代码虽然很简单,但要成功集成还是要花功夫的。

acp_sdk.properties配置文件主要放置一些证书文件,证书从商户入网测试中心下载。

# 报文版本号,固定5.1.0
acpsdk.version=5.1.0

# 签名方式,证书方式固定01
acpsdk.signMethod=01

##测试交易请求地址
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

# 是否验证验签证书的CN,测试环境设置false,生产环境设置true。
acpsdk.ifValidateCNName=false

# 是否验证https证书,测试环境设置false,生产环境设置true。
acpsdk.ifValidateRemoteCert=false

######################### 入网测试环境签名证书配置 ################################
# 签名证书路径
acpsdk.signCert.path=/data/acp_test_sign.pfx

# 签名证书密码,测试环境固定000000
acpsdk.signCert.pwd=000000
# 签名证书类型,固定不需要修改
acpsdk.signCert.type=PKCS12

########################## 加密证书配置 ################################
# 敏感信息加密证书路径
acpsdk.encryptCert.path=/data/acp_test_enc.cer

########################## 验签证书配置 ################################
# 验签中级证书路径
acpsdk.middleCert.path=/data/acp_test_middle.cer
# 验签根证书路径
acpsdk.rootCert.path=/data/acp_test_root.cer

将acp_sdk.properties配置文件放到根目录下

image.png

再写个配置类UnionPayConfig,启动的时候加载证书内容

@Component
@Configuration
@EnableConfigurationProperties({UnionProperties.class})
public class UnionPayConfig {
    private UnionProperties union;
    public UnionPayConfig(UnionProperties union) {
        this.union = union;
        SDKConfig.getConfig().loadPropertiesFromSrc();
    }
}

PC端唤起支付页面,注意交易金额,单位为分,不能带小数点,结果是以form表单的形式打开支付页面。

    public void  webPay(HttpServletResponse resp) throws IOException {
        logger.info("银联电脑端支付");
        UnionPayParam param = new UnionPayParam();
        param.setOrderId(UnionConfig.getCurrentTime())
                .setTxnTime(UnionConfig.getCurrentTime())
                .setTxnAmt("330000")
                .setReqReserved(param.getOrderId());
        unionPayService.webPay000202(param, resp);
        Map<String, String> data = new HashMap<>(29);
        // 版本号,全渠道默认值
        data.put("version", UnionConfig.version);
        // 字符集编码,可以使用UTF-8,GBK两种方式
        data.put("encoding", UnionConfig.encoding_UTF8);
        // 签名方法
        data.put("signMethod", SDKConfig.getConfig().getSignMethod());
        // 交易类型 ,01:消费
        data.put("txnType", "01");
        // 交易子类型, 01:自助消费
        data.put("txnSubType", "01");
        // 业务类型 000202: B2B
        data.put("bizType", "000202");
        // 渠道类型 固定07
        data.put("channelType", "07");
        // 商户号码
        data.put("merId", unionProperties.getMerId());
        // 接入类型,0:直连商户
        data.put("accessType", "0");
        // 商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则
        data.put("orderId", param.getOrderId());
        // 订单发送时间,取系统时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效
        data.put("txnTime", param.getTxnTime());
        // 交易币种(境内商户一般是156 人民币)
        data.put("currencyCode", "156");
        // 交易金额,单位分,不要带小数点
        data.put("txnAmt", CommonUtils.subZeroAndDot(param.getTxnAmt()));
        // 业务场景,取值参考接口规范
        data.put("bizScene", "110001");
        // 收款方账户名称
        data.put("payeeAcctNm", URLEncoder.encode(unionProperties.getPayeeAcctNm(),UnionConfig.encoding_UTF8));
        // 收款方账号
        data.put("payeeAcctNo", unionProperties.getPayeeAcctNo());
        // 收款银行名称
        data.put("payeeBankName", URLEncoder.encode(unionProperties.getPayeeBankName(),UnionConfig.encoding_UTF8));
        // 前台通知地址
        data.put("frontUrl", unionProperties.getFrontUrl());
        // 后台通知地址
        data.put("backUrl", unionProperties.getBackUrl());
        // 订单超时时间
        data.put("payTimeout", new SimpleDateFormat("yyyyMMddHHmmss").format(System.currentTimeMillis() + 15 * 60 * 1000));
        // 请求方保留域, 内容不会出现&={}[]"'等符号时,可以直接填写数据
        data.put("reqReserved", Base64.encodeBase64String(param.getReqReserved().getBytes(UnionConfig.encoding_UTF8)));
        Map<String, String> reqData = AcpUtils.sign(data,UnionConfig.encoding_UTF8);
        String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();
        String html = AcpUtils.createAutoFormHtml(requestFrontUrl,reqData,UnionConfig.encoding_UTF8);
        logger.info("打印请求HTML,此为请求报文:{}", html);
        resp.getWriter().write(html);
}

和其他支付方式一样,支付结果以异步通知告知开发者,在这里处理业务逻辑,比如更改订单状态为已支付。

    public void unionPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.info("银联接收后台通知开始");
        String encoding = request.getParameter(SDKConstants.param_encoding);
        // 获取银联通知服务器发送的后台通知参数
        Map<String, String> reqParam = AcpUtils.getAllRequestParam(request);
        Map<String, String> valideData = new HashMap<>();
        if (!reqParam.isEmpty()) {
            Iterator<Map.Entry<String, String>> it = reqParam.entrySet().iterator();
            valideData = new HashMap<>(reqParam.size());
            while (it.hasNext()) {
                Map.Entry<String, String> e = it.next();
                String key = e.getKey();
                String value = e.getValue();
                value = new String(value.getBytes(encoding), encoding);
                valideData.put(key, value);
            }
        }
        if (!AcpUtils.validate(valideData, encoding)) {
            logger.info("银联验证签名结果[失败].");
        } else {
            logger.info("银联回调结果参数=====:{}", JSON.toJSONString(valideData));
            logger.info("银联验证签名结果[成功].");
            AsyncNotifyResult result = JSON.parseObject(JSON.toJSONString(valideData), AsyncNotifyResult.class);
            // 应答码
            String respCode = result.getRespCode();
            // 应答信息
            String respMsg = result.getRespMsg();
            if (StringUtils.equals("00", respCode) && StringUtils.equals("成功[0000000]", respMsg)) {
                // 商户订单号
                String orderId = result.getOrderId();
                // 银联查询流水号
                String queryId = result.getQueryId();
                // 银联订单发送时间
                String txnTime = result.getTxnTime();

                String txnAmt = result.getTxnAmt();
                // 辅助信息
                String reqReserved = result.getReqReserved();
                logger.info("reqReserved=====:{}", new String(Base64.decodeBase64(reqReserved), UnionConfig.encoding_UTF8));
                // TODO
                // 银联没有返回付款时间,系统自己生成
                logger.info("处理业务逻辑,orderId:{},更新queryId:{},txnTime:{}=====", orderId, queryId, txnTime);

            }
            response.getWriter().print("ok");
        }
    }

看一下效果

image.png

这是测试环境,选择卡号,输入验证码,点击提交

image.png

image.png

image.png

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海

上一篇:美团联盟怎么实现用户订单跟单功能

相关文章
|
弹性计算
2024年阿里云免费云服务器及学生云服务器申请教程参考
2024年阿里云继续推出免费学生云服务器与免费试用云服务器,其中学生云服务器最长可免费7个月(1个月首次领用+6个月免费续领),免费试用云服务器分为个人免费云服务器和企业免费云服务器,最长免费试用时长是3个月。下面小编来介绍一下阿里云免费云服务器及学生云服务器的申请教程。
54111 54
2024年阿里云免费云服务器及学生云服务器申请教程参考
|
消息中间件 网络性能优化 开发工具
消息队列 MQ使用问题之如何确保消息的唯一性
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
4月前
|
安全 Cloud Native 数据中心
Windows Server 2016 中文版、英文版下载 (2025 年 7 月更新)
Windows Server 2016 中文版、英文版下载 (2025 年 7 月更新)
578 1
Windows Server 2016 中文版、英文版下载 (2025 年 7 月更新)
|
7月前
|
人工智能
WEB CAD 利用AI编程实现多行文本的二次开发
本文介绍了在MxCAD插件中实现自定义编辑器实体类的功能,重点展示如何通过MxCADMText类在CAD中渲染和管理富文本。文章详细说明了注册同心圆实体文本的步骤,包括实现自定义文本类、注册自定义文本以及交互式修改参数的方法。此外,还扩展实践了粗糙度实体文本的注册与应用,涵盖构造粗糙度自定义实体文本类、注册及初始化过程,并通过示例图展示了运行效果。这些功能可帮助用户将复杂图形以文本形式插入多行文本中,提升项目设计效率。
|
11月前
|
机器学习/深度学习 数据采集 TensorFlow
使用Python实现智能食品消费偏好分析的深度学习模型
使用Python实现智能食品消费偏好分析的深度学习模型
233 8
|
缓存 网络协议 算法
c++理论篇(一) ——浅谈tcp缓存与tcp的分包与粘包
c++理论篇(一) ——浅谈tcp缓存与tcp的分包与粘包
449 0
c++理论篇(一) ——浅谈tcp缓存与tcp的分包与粘包
|
机器学习/深度学习 人工智能 搜索推荐
构建未来:基于AI的自适应学习系统
【4月更文挑战第28天】 随着人工智能技术的不断进步,其在教育领域的应用也日益广泛。本文将探讨如何利用AI技术构建一个自适应学习系统,以提供更加个性化的学习体验。我们将讨论AI在教育中的应用,包括智能教学系统的设计、学习内容的个性化推荐以及学习进度的自动调整等方面。此外,我们还将探讨如何通过数据分析来优化学习过程,以及如何保护学习者的隐私。
438 0
|
Serverless 定位技术 Windows
ArcGIS中ArcMap快速自动计算单一波段或多波段栅格遥感影像NDVI的方法
ArcGIS中ArcMap快速自动计算单一波段或多波段栅格遥感影像NDVI的方法
643 1
|
SQL 存储 数据库
【数据库SQL server】自学终极笔记
【数据库SQL server】自学终极笔记
465 0