😹 作者: gh-xiaohe
😻 gh-xiaohe的博客
😽 觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!!
官网链接:https://opendocs.alipay.com/common/02fwvj
支付宝开放平台将强⼤的支付、营销、数据能力,通过接口等形式开放给自研商家与服务商(ISV),帮助商家创建更具竞争力的应用。还可协助商家进行推⼴营销。
商家接入开放平台后,基于支付宝海量用户,可以获得更多的流量、用户和收益,同时用户通过商家提供的服务获得了更丰富的体验,平台生态更加繁荣,最终实现多方共赢。
开发者是开放生态的主要组成部分,通过与商家、消费者的合作,提升商家的服务效率和营收,降低运营成本,使消费者的体验更便捷、更愉悦、更完美。无论是服务商开发者还是商家,都能基于开放平台找到适合自己的角色和方向。
通过平台能做什么?
开发者是开放生态的主要组成部分,通过与商家、消费者的合作,提升商家的服务
效率和营收,降低运营成本,使消费者的体验更便捷、更愉悦、更完美。无论是服务商开发者还是商家,都能基于开放平台找到适合自己的角色和方向。
1、自研商家
拥有研发能力的商家,可通过开放能力接口,将支付宝提供的各项功能集成至自身系统中。定制化开发,丰富服务范围,提升用户体验及自身竞争力。
2、服务商(ISV)
ISV 不仅可以进行自研开发,还能为用户提供小程序、生活号、网页、移动等应用,接入平台提供的支付、营销、数据等开放能力,为用户提供系统服务。
插件提供商
通过支付宝提供的丰富的 API 接口,开发者可以开发并在应用市场上线各类插件,
解决⻔店管理、支付核销、会员营销、数据分析等方面的问题。开放平台还为各种应用提供了清晰的盈利模式,通过应用市场的销售获得回报。
服务提供商
在应用市场之外,ISV 还可以通过服务市场为商家提供店铺装修、拍摄修图、地面推⼴、⻔店代运营等服务。实现线上订购,线下服务。
场景分销商
第三方APP 或媒介可以借助支付宝开放平台的分销能力为商家提供基于⻔店、卡
券、内容的分销服务,为商家的流量导入、品牌推⼴提供平台。分销商可以通过所
提供的服务获取收入。
开放平台:https://open.alipay.com/
沙箱环境:https://openhome.alipay.com/platform/appDaily.htm?tab=info
文档中心:https://openhome.alipay.com/docCenter/docCenter.htm
API中心:https://opendocs.alipay.com/apis
当面付帮助商家在线下消费场景中实现快速收款,支持 条码支付 和 扫码支付 两种付款方式。商家可通过以下两种任⼀方式进行收款,提升收银效率,实现资金实时到账。
条码支付:买家出示支付宝钱包中的条码、二维码,商家扫描用户条码即可完成 条码支付收款
扫码支付:买家通过使用支付宝 扫⼀扫 功能,扫描商家收款二维码即可完成扫码支付 付款。
产品特色
使用流程:
使用说明:
1、收银员在商家收银系统操作生成订单,输入收款金额;
2、用户登录支付宝,点击⾸页付钱/收钱,进入付款码界面,出示给商家;
3、收银员通过扫码设备来扫描用户手机上的条码/二维码后,商家收银系统提交
支付;
4、支付后商家收银系统会拿到支付成功或者失败的结果,用户支付宝 App 显示
收单支付引导或成功结果。
适用于单件商品单独定价、无⼈值守、自助售货机等商家。用户打开支付宝中的扫⼀扫 功能,扫描商家展示的二维码进行支付。该模式适用于线下实体店支付、面对面支付、自助售货机等场景。
使用流程:
使用说明:
App 支付适用于商家在 App 应用中集成支付宝支付功能。商家 App 调用支付宝提
供的 SDK,SDK 再调用支付宝 App 内的支付模块。
应用案例:
⽬前已上线支付案例,商家可进行实际体验:饿了么 App、优酷 App、携程 App。
为方便商家在移动端网页应用中集成支付宝支付功能,支付宝提供了手机网站支付
能力。
说明:手机网站支付产品不建议在 App 端使用;如果需要在 App 端中使用支付,
请接入 App 支付产品,接入文档详见App 支付 开发文档。
业务逻辑:
适用于商家在移动端网页应用中集成支付宝支付功能。 商家在网页中调用支付宝提供的网页支付接口调起支付宝客户端内的支付模块,商家网页会跳转到支付宝中完成支付,支付完后跳回到商家网页内,最后展示支付结果。若无法唤起支付宝客户端,则在⼀定的时间后会自动进入网页支付流程。
为方便网页应用商家接入支付宝支付功能,支付宝提供了电脑网站支付能力,商家可通过开放接口快速集成接入支付宝支付功能。电脑网站为即时到账升级而来的能力。
用户在 PC 端访问商家网站进行消费,通过电脑网站支付,可直接跳转到支付宝 PC网站收银台完成付款。 交易资金直接打入商家支付宝账户,实时到账。 用户交易款项即时到账,交易订单三个月内可退款,提供退款、清结算、对账等配套服务。
基本流程:双十一购物流程
①首先登录支付宝平台
②选入接入类型
③填写接入信息
如果是第一次,需要注册,具体按照下面要求进行填写
④注册成功
⑤编写对接的应用名称
⑥进入控制台
注意:
APPID是自动帮我们创建了,网关也不用管。我们要做的就是设置那个密钥, 这里RSA2需要设置公钥。推荐使用RSA2
安装阿里支付助手AlipayDevelopmentAssistant工具。生成秘钥
点击进入在支付页面点击付款,完成沙箱支付操作
org.springframework.boot spring-boot-starter-parent 2.3.3.RELEASE org.springframework.boot spring-boot-starter-web com.alipay.sdk alipay-sdk-java 4.10.124.ALL org.apache.tomcat.embed tomcat-embed-jasper provided
# 应用名称
spring.application.name=ALiPayDemo1# 页面的默认前缀
spring.mvc.view.prefix=/
# 响应页面默认的后缀
spring.mvc.view.suffix=.jsp
# 端口号
server.port=8080
# 项目访问路径
server.servlet.context-path=/
utils - AppUtils
public class AppUtils {// 定义应用的id ,AppId 就是对应的支付宝账号public static String app_id = "2021000121695303";// 定义商户的私钥public static String merchant_private_key ="xxx";// 定义商户的公钥 PKCS8格式RSA2私钥public static String align_public_key= "xxx";// 服务器异步通知页面路径// 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问public static String notify_url= "";// 页面跳转同步通知页面路径// 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问public static String return_url= "";// 签名方式public static String sign_type = "RSA2";// 字符的编码格式public static String charset = "utf-8";// 支付宝网关,注意这些使用的是沙箱的支付宝网关,与正常网关的区别是多了devpublic static String gatewayUrl= "https://openapi.alipaydev.com/gateway.do";// 日志地址public static String log_path = "F:\\桌面\\";/*** 写⽇志,方便测试(看网站需求,也可以改成把记录存入数据库)* @param sWord 要写入⽇志⾥的文本内容*/public static void logResult(String sWord){// 创建一个文件流FileWriter fieldWriter = null;try {fieldWriter = new FileWriter(log_path + "alipay_log" + System.currentTimeMillis() + ".text");fieldWriter.write(sWord);} catch (Exception e) {e.printStackTrace();} finally {if (fieldWriter != null) {try {fieldWriter.close();} catch (IOException e) {e.printStackTrace();}}}}
}
utils - BeanUtils
/*** 提供支付宝相关的一些对象*/
@Configuration
public class BeanUtils {// 创建支付宝需要的客户端对象@Beanpublic AlipayClient alipayClient(){return new DefaultAlipayClient(AppUtils.gatewayUrl, // 网关AppUtils.app_id, // appidAppUtils.merchant_private_key, // 私钥"json", // 数据格式AppUtils.charset, // 编码方式AppUtils.align_public_key, // 公钥AppUtils.sign_type // 签名类型);}// 创建一个支付宝的请求对象@Beanpublic AlipayTradePagePayRequest alipayTradePagePayRequest() {return new AlipayTradePagePayRequest();}
}
/*** 支付的控制器*/
@Controller
public class PayController {@Autowiredprivate AlipayClient alipayClient;@Autowiredprivate AlipayTradePagePayRequest alipayTradePagePayRequest;/*** 接收页面传递传递过来的参数** @param WIdOut_trade_no 订单号* @param WIdSubject 金额* @param WIdTotal_amount 名称* @param WIdBody 商品描述* @param response 表单中的其他参数信息 name值 = 参数名* @throws Exception*/@RequestMapping("/pay")public void pay(String WIdOut_trade_no, String WIdSubject,String WIdTotal_amount, String WIdBody, HttpServletResponse response)throws Exception {// 1、设置参数// 设置响应的地址(支付宝返回给商户的响应地址)alipayTradePagePayRequest.setNotifyUrl(AppUtils.notify_url); // 内网穿透 支付宝像我们的应用发送一个消息,支付成功还是失败的消息alipayTradePagePayRequest.setReturnUrl(AppUtils.return_url); // 通知页面// 设置其他参数 (传递给支付宝的数据)alipayTradePagePayRequest.setBizContent("{\"out_trade_no\":\""+ WIdOut_trade_no +"\","+ "\"total_amount\":\""+ WIdTotal_amount +"\","+ "\"subject\":\""+ WIdSubject +"\","+ "\"body\":\""+ WIdBody +"\","+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); // 产品的编码// 2、发送请求 调用 pageExecute 传递 请求 getBody 将结果以字符串的方式返回回来String result = alipayClient.pageExecute(alipayTradePagePayRequest).getBody();// 3、将响应结果返回给前端response.setContentType("text/html;charset=utf-8");response.getWriter().println(result);}/*** 流程:* * 1、封装参数,封装到alipayTradePagePayRequest参数中, * 2、封装好之后发送请求,调用pageExecute()方法,调用getBody()返回信息* 3、可以把支付宝返回的信息,通过流的方式发送给页面*/
}
异步通知: 其实是双保险机制,如果同步通知后没有跳转到你的网址,可能用户关了,可能网速慢,即无法触发你更新订单状态为已支付的controller,这时候异步通知就有作用了,不过你要判断一下,如果订单已经变为已支付,则不必再更新一次了,只返回给支付宝success即可,否则他会一直异步通知你
异步通知参数说明文档: https://opendocs.alipay.com/open/203/105286
/*** 异步通知控制器*/
@Controller
public class NotifyController {/*** 接收支付宝返回的异步通知信息** @param request* @param response*/@RequestMapping("/getNotify")public void getNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {// 获取⽀付宝POST过来反馈信息Map params = new HashMap<>();Map parameterMap = request.getParameterMap(); // 获取参数/**keySet()和entrySet(),是Map集合中的两种取值方法。与get(Object key)相比,get(Object key)只能返回到指定键所映射的值,不能一次全部取出keySet()和entrySet()可以。Map集合中没有迭代器,Map集合取出键值的原理:将map集合转成set集合,再通过迭代器取出。*/Iterator iterator = parameterMap.keySet().iterator();// iterator 迭代器while (iterator.hasNext()) {String name = iterator.next();String[] values = parameterMap.get(name);String valueStr = "";for (int i = 0; i < values.length; i++) {// 拼接 values信息 如果是最后一个值, 不拼接 ,号valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";}// 乱码解决,这段代码在出现乱码时使⽤// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");params.put(name, valueStr);}// 调用支付宝的SDK验证签名boolean signVerified = AlipaySignature.rsaCheckV1(params, // 参数AppUtils.align_public_key, // 公钥AppUtils.charset, // 编码方式AppUtils.sign_type); // 签名类型/*** 主要用途:* 判断信息有没有被篡改* 1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,* 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额)* 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作⽅(有的时候,⼀个商户可能有多个seller_id/seller_email)* 4、验证app_id是否为该商户本身。*/response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();if (signVerified) {//验证成功String out_trade_no = request.getParameter("out_trade_no"); // 商户订单号String trade_no = request.getParameter("trade_no"); // ⽀付宝交易号String trade_status = request.getParameter("trade_status"); // 交易状态/*** 支付宝Api 交易状态说明* 枚举名称 枚举说明* WAIT_BUYER_PAY 创建交易,等待买家付款* TRADE_CLOSED 未付款交易超时关闭* TRADE_SUCCESS 交易支付成功* TRADE_FINISHED 交易结束,不可退款*/if (trade_status.equals("TRADE_FINISHED")) {System.out.println("交易结束,不可退款");out.println("finished");} else if (trade_status.equals("TRADE_SUCCESS")) {System.out.println("交易支付成功");out.println("success");}} else {//验证失败System.out.println("验证失败");out.println("fail");}}
}
由于我们的项目是内网,支付宝通知不能通知支付信息,因此我们需要是用内网穿透技术将ip映射为一个支付宝可以通知到的外网地址。
自行配置:
命令:natapp -authtoken=404390a06dca8d75
添加异步通知地址
# AppUtils 异步通知的地址
public class AppUtils {public static String notify_url= "http://cwgmzt.natappfree.cc/getNotify";
}
同步返回页面控制器
# AppUtils 同步通知的地址
public class AppUtils {public static String notify_url= "http://cwgmzt.natappfree.cc/getReturn";
} /*** 同步返回页面控制器*/
@Controller
public class ReturnController {/*** 接收支付宝返回的同步通知信息** @param request* @param response*/@RequestMapping("/getReturn")public void getReturn(HttpServletRequest request, HttpServletResponse response) throws Exception {// 获取⽀付宝POST过来反馈信息Map params = new HashMap<>();Map parameterMap = request.getParameterMap(); // 获取参数/**keySet()和entrySet(),是Map集合中的两种取值方法。与get(Object key)相比,get(Object key)只能返回到指定键所映射的值,不能一次全部取出keySet()和entrySet()可以。Map集合中没有迭代器,Map集合取出键值的原理:将map集合转成set集合,再通过迭代器取出。*/Iterator iterator = parameterMap.keySet().iterator();// iterator 迭代器while (iterator.hasNext()) {String name = iterator.next();String[] values = parameterMap.get(name);String valueStr = "";for (int i = 0; i < values.length; i++) {// 拼接 values信息 如果是最后一个值, 不拼接 ,号valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";}// 乱码解决,这段代码在出现乱码时使⽤// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");params.put(name, valueStr);}// 调用支付宝的SDK验证签名boolean signVerified = AlipaySignature.rsaCheckV1(params, // 参数AppUtils.align_public_key, // 公钥AppUtils.charset, // 编码方式AppUtils.sign_type); // 签名类型response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();if (signVerified) {//验证成功String out_trade_no = request.getParameter("out_trade_no"); // 商户订单号String trade_no = request.getParameter("trade_no"); // ⽀付宝交易号String trade_amount = request.getParameter("trade_amount"); // 交易状态// 金额out.println("out_trade_no" + out_trade_no + "trade_no" + trade_no + "trade_amount" + trade_amount);// 返回到浏览器} else {//验证失败System.out.println("验证失败");out.println("fail");}}
}
编写登录控制器方法
# PayController /*** 跳转到index.html页面** @return*/@RequestMapping("/index")public String index() {return "index";}
成功