支付宝支付-当面付之扫码支付「扫码支付」
前言
支付宝支付—沙箱环境使用
支付宝支付-支付宝PC端扫码支付
支付宝支付-手机浏览器H5支付
支付宝支付-当面付之扫码支付「本文」
当面付包含两种支付方式:商品条形码支付 + 扫码支付
经过前面两篇PC端扫码支付、手机H5支付,我们可以看到一个共同的特点就是接口返回的都是一个Form表单,然后交给提交执行,然后调起支付。其中PC端提交Form表单后跳转至新的窗口进行支付,而手机端H5支付则是唤起支付宝APP支付。
但是现在有这么个场景,我不希望在PC端支付时跳转支付宝网页支付,而是直接将二维码嵌入到系统当中,用户直观看到的就是一个弹窗二维码,然后用户拿支付宝扫码支付…这就是本文的当面付之扫码支付了。
废话不多说,直接进入主题。
本文开发环境:IDEA + Tomcat8.5 + 支付宝沙箱环境 + SpringBoot
补充:调用沙箱环境接口,需要安装沙箱环境下的支付宝APP,不了解的小伙伴可以参考上方 支付宝支付—沙箱环境使用。
一、pom引入依赖 + 参数准备
引入支付宝支付依赖文件,本文基于4.9.153.ALL版本,及供参考, 最新版本可去官方文档查阅。
<!--alipay--><dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>4.9.153.ALL</version></dependency>
关于支付宝公钥、私钥、回调地址啥的就不再重复了,不清楚的去看支付宝支付—沙箱环境使用。
配置可以单独创建一个类,静态初始化参数::AlipayConfig.java
public class AlipayConfig { /** 商户appid **/ public static String APPID = "201610170070"; /** 私钥 pkcs8格式的 **/ public static String RSA_PRIVATE_KEY = ""; /** 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 **/ public static String notify_url = "http://ngrok.sscai.club/alipay_trade_wap_pay_java_utf_8_war_exploded/notify_url.jsp"; /** 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址 **/ public static String return_url = "http://ngrok.sscai.club/alipay_trade_wap_pay_java_utf_8_war_exploded/return_url.jsp"; /** 请求网关地址 **/ public static String URL = "https://openapi.alipaydev.com/gateway.do"; /** 编码 **/ public static String CHARSET = "UTF-8"; /** 返回格式 **/ public static String FORMAT = "json"; /** 支付宝公钥 **/ public static String ALIPAY_PUBLIC_KEY = ""; /** 日志记录目录 **/ public static String log_path = "/log"; /** RSA2 **/ public static String SIGNTYPE = "RSA2"; /** 商户门店编号「需要申请当面付」 **/ public static String STORE_ID = "122211242";}
几个主要的参数:
- APPID :商户appid
- RSA_PRIVATE_KEY:应用私钥
- ALIPAY_PUBLIC_KEY:支付宝公钥「注意不是应用公钥」
这几个参数不清楚的,可以看一下 沙箱环境使用,或者看一下官方文档参数说明。
二、后端代码
还是之前的代码,一个controller接口方法,一个具体的实现方法「没有使用开源SDK」:
Controller
@ApiOperation(value = "获取支付宝支付二维码")public Result<AlipayResponse> getAliPayQrCode(@CurrentUser UserModel user, @RequestBody AlipayOrderRequest alipayOrderRequest ) { /** 返回给前端的二维码内容 **/ String sHtmlText = null; try { /** 判断是否已经存在订单,根据自己业务的不同自行判断**/ if(!StringUtils.isNotBlank(alipayOrderRequest.getWidOutTradeNo())){ Orders orders=ordersService.createOrder(user,alipayOrderRequest.getWidTotalFee(),alipayOrderRequest.getAppType()); alipayOrderRequest.setWidOutTradeNo(orders.getOrderId()); }else{ OrderResponse orders=ordersService.searchOrderDetail(user,alipayOrderRequest.getWidOutTradeNo()); alipayOrderRequest.setWidTotalFee(orders.getAmount().toString()); } /** 这是主要的方法 **/ sHtmlText = alipayService.alipayOrder(alipayOrderRequest); } catch (AlipayApiException e) { e.printStackTrace(); } AlipayResponse alipayResponse = new AlipayResponse(); alipayResponse.setSHtmlText(sHtmlText); alipayResponse.setOrderId(alipayOrderRequest.getWidOutTradeNo()); return ResultUtil.success(alipayResponse);}
ServerImpl
@Transactionalpublic String alipayOrder(AlipayOrderRequest alipayOrderRequest) throws AlipayApiException {
/**获得初始化的AlipayClient**/ AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
/**当面付之「扫码支付」**/ AlipayTradePrecreateRequest alipayTradePrecreateRequest = new AlipayTradePrecreateRequest(); /**回调地址+异步通知**/ alipayTradePrecreateRequest.setNotifyUrl(AlipayConfig.notify_url); alipayTradePrecreateRequest.setReturnUrl(AlipayConfig.return_url);
/**商户订单号,商户网站订单系统中唯一订单号,必填**/ String out_trade_no = alipayOrderRequest.getWidOutTradeNo(); /**付款金额,必填**/ String total_amount = alipayOrderRequest.getWidTotalFee(); /**订单名称,必填**/ String subject = alipayOrderRequest.getWidSubject(); /**商户门店编号,必填**/ String store_id = AlipayConfig.STORE_ID; /**交易超时时间,订单允许的最晚付款时间,必填**/ String timeout_express = "120m";
/**拼接参数**/ alipayTradePrecreateRequest.setBizContent( "{\"out_trade_no\":\""+ out_trade_no +"\"," + "\"total_amount\":\""+ total_amount +"\"," + "\"subject\":\""+ subject +"\"," + "\"store_id\":\""+ store_id +"\"," + "\"timeout_express\":\""+timeout_express+"\"}");
return alipayClient.execute(alipayTradePrecreateRequest).getBody();}
三、返回结果+测试
如上代码调用execute之后的返回结果:
{ "alipay_trade_precreate_response":{ "code":"10000", "msg":"Success", "out_trade_no":"20200508160037744742", "qr_code":"https://qr.alipay.com/bax06173nktjyrrwupss00bf" }, "sign":"sdk3Q6idlQC+SRuuxc6xXv3g4BAkxEgpA9WYJoiE8oYH5mA6K8+GMwAETNKOhOPh/SoYS4CECzswk/H7qw9A=="}
我们可以看到qr_code参数了,剩下的就是交给前端生成二维码了,然后用户扫码支付,在这我就不展示了,直接拿链接去草料二维码直接生成个二维码试试。
四、扫码支付回调地址
支付成功后支付宝会回调前边设置的回调地址,由后端的的 return_url 参数控制。
再看看支付成功后的回调接口,由后端的 notify_url 参数控制「没有使用开源的SDK演示」:
public String alipaynotify(Model model, HttpServletRequest request) {
log.info("支付宝异步回调 ------------beg-----------"); String result = "fail"; /**获取支付宝POST过来反馈信息**/ /* * * 功能:支付宝服务器异步通知页面 * 说明: * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 */ Map<String, String> params=this.getAlipayRequest(request); if(params == null || params.size()==0){ BufferedReader bufferReader = null; StringBuilder sb = new StringBuilder(); try { bufferReader = new BufferedReader(request.getReader());
String line = null; while ((line = bufferReader.readLine()) != null) { sb.append(new String(line.getBytes("ISO-8859-1"), "utf-8")); } } catch (IOException e) { e.printStackTrace(); } String body= null; try { body = URLDecoder.decode(sb.toString(),"UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } params=UriComponentsBuilder.newInstance().query(body).build().getQueryParams().toSingleValueMap(); } boolean signVerified =false; try { signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); } catch (AlipayApiException e1) { log.error("由于"+e1.getErrMsg()+"返回给支付宝系统的结果result:fail"); model.addAttribute("result", "fail"); return result; }
/**——请在这里编写您的程序(以下代码仅作参考)——**/
/* 实际验证过程建议商户务必添加以下校验: 1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号, 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额), 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email) 4、验证app_id是否为该商户本身。 */ log.error("支付宝验证签名:---------------------------------"+signVerified); if(signVerified) {/**验证成功**/ /**商户订单号**/ /**交易状态**/ log.info("支付宝异步回调验签成功!"); String trade_status = params.get("trade_status");
if("TRADE_FINISHED".equals(trade_status)){ /**判断该笔订单是否在商户网站中已经做过处理**/ /**如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序**/ /**如果有做过处理,不执行商户的业务程序**/
/**注意:**/ /**退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知**/ try { /** 在这里处理支付成功后的操作,比如修改订单状态等等**/ coding... result = "success"; } catch (Exception e) { log.error(e.getMessage()); result = "fail"; } }else if ("TRADE_SUCCESS".equals(trade_status)){ /**判断该笔订单是否在商户网站中已经做过处理**/ /**如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序**/ /**如果有做过处理,不执行商户的业务程序**/
/**注意:**/ /**付款完成后,支付宝系统发送该交易状态通知**/ try { /** 在这里处理支付成功后的操作,比如修改订单状态等等**/ coding... result = "success"; } catch (Exception e) { log.error(e.getMessage()); result = "fail"; } }else{ result = "fail"; } }else {/**验证失败**/ result = "fail"; /**调试用,写文本函数记录程序运行情况是否正常**/ /**String sWord = AlipaySignature.getSignCheckContentV1(params);**/ /**AlipayConfig.logResult(sWord);**/ log.debug("支付宝异步回调验签失败"); } log.debug("异步回调返回给支付宝系统的结果result:"+result);
model.addAttribute("result", result); log.info("支付宝异步回调 -------------end ------------"); return result;}
该方法返回给支付宝的 result 就 success、fail 两个结果。
从以上看来,其实不难发现支付宝支付是非常简单的,尽管我上边贴了大量的代码,其实采用开源SDK的话可以更加缩减、美化一些。
ok,这篇文章就到这结束了,上边并没有详细介绍接口调用、参数说明等,详细介绍请查看官方文档:
https://opendocs.alipay.com/open/194/106078/
https://opendocs.alipay.com/open/194/103296
文章最后
博客地址:https://www.cgblog.com/niceyoo
如果觉得这篇文章有丶东西,不妨关注一下我,关注是对我最大的鼓励~
支付宝支付-当面付之扫码支付「扫码支付」相关推荐
- 支付宝支付-当面付和App支付
公司最近在做个视频桩的项目,需要在桩上用到支付宝支付功能. 去年项目当中有应用过支付宝,当时前端是用react,后台返回qcode到前端后,前端通过react的插件(其实就是支付宝的sdk),拼接qc ...
- 对接支付宝服务商当面付手机网页支付
一.前期准备: SpringBoot对接支付宝当面付和手机网站支付_springboot 支付宝当面付_Biubiubiuexo的博客-CSDN博客 配置成功后获得到我们开发需要的:支付宝公钥.商户私 ...
- 支付宝当面付实现跳转到指定网页唤起支付
前言 最近在做一个人影视项目,需要用到会员充值功能,但是奈何个人没有办法开通支付宝的网页支付需要一些资质,微信的h5支付更不用提了,难度更大,因此一直想的是有没有办法实现个人账号来做支付呢,哪怕是测试 ...
- 支付宝支付——当面付
开发当面付首先需要成为服务商,然后创建app.配置你.密钥,相应流程参考官网 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0. ...
- 通联支付“当面付”有哪些优势?
如今的互联网发展非常迅速,给人们的生活方式带来了极大的便捷,就比如说购物.逛街时会经常使用的移动支付APP,更是如雨后春笋一般,纷纷出现在人们的生活中.谈起移动支付类型的APP,大家首先会想到的就是支 ...
- 支付宝的当面付扫一扫功能
首先需要一个沙箱环境,专门为开发者提供的.里面给你提供了卖家账号,和买家账号.具体的自行百度. 需要下载沙箱版的支付宝,然后登陆提供的买卖家账号即可操作.因为在沙箱环境中支付宝给出的二维码只能在沙箱版 ...
- 两把王者荣耀的时间学会Python图片打码技能——「实验一小时」今晚开启!
关注「实验楼」,每天分享一个项目教程 「 实验一小时 」今晚开启,实验楼技术天团带你一小时做一个项目. 今晚 7:30 ,曾任职于腾讯.盛大等一线互联网公司的天火老师,将在B站带来免费直播,带大家学习 ...
- 支付宝商家当面付接入java-web
一.支付宝网站资料准备 1.创建应用 登录支付宝蚂蚁金服开放平台,点击(网页&移动应用列表),查看自己的移动或网页程序. 地址:支付宝蚂蚁金服开放平台 2.开始签约 在(网页&移动应用 ...
- 派工单系统 源码_「青鸟报修云」酒店设备报修管理系统
近几年随着信息化的快速发展,酒店方面也越来越重视设备的报修管理,争取将酒店的服务做到极致,满足顾客的需求.但是酒店内部设备的报修问题,一直困扰着许多酒店管理者,而一旦酒店的设备设施出现故障,就会直接影 ...
最新文章
- PHP中file_exists与is_file,is_dir的区别介绍
- auto make System.map to C header file
- wxWidgets:wxCmdLineParser类用法
- 关于ibatis.net 和 Nhibernate的选择
- eclipse/myeclipse中如何开启断言调试代码
- 算法训练 K好数(dp+动态规划)
- c++ sendmessage 鼠标 坐标是相对自身吗_【科普】你真的足够了解五轴加工吗?看完豁然开朗!...
- Python实现红黑树的插入操作
- 毕业答辩之毕业设计答辩问题有哪些?
- 活动目录操作主机(FSMO)角色详解
- ftp 上传下载整个目录
- 防盗链及图片加密系统
- Raspberry Pi 树莓派查看CPU温度
- 基于深度信念网络的事件识别
- 5.10 数据的升序和降序排序 [原创Excel教程]
- 用LoopBack接口配置EBGP邻居
- 小米组织架构再调整,王川调职,雷军自任中国区总裁
- 3.4.8nbsp;拉里·佩奇和谢尔盖·布林
- android 4.4 flac,如何在Android中将音频原始转换为FLAC
- 计算机协会发言稿范文,科技节的发言稿范文(精选5篇)
热门文章
- [html] 如何给input的右上角加个清除的按钮?
- 前端学习(1879)vue之电商管理系统电商系统之通过axios拦截器添加token认证
- 前端学习(1372):构建模块化路由
- spring学习(47):bean的作用域
- 实例64:python
- java单例模式的实现方法_JAVA单例模式的几种实现方法
- cefsharp System.IO.FileNotFoundException: 未能加载文件或程序集“CefSharp.Core.dll”或它的某一个依赖项。...
- go语言基础之格式化输出
- 油田 (Oil Deposits UVA - 572)
- 牛客网挑战赛24 青蛙(BFS)