26支付宝支付
Posted 无休止符
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了26支付宝支付相关的知识,希望对你有一定的参考价值。
目录
一、支付宝流程
1 - 正式上线流程
- 支付宝开放平台:https://open.alipay.com/
- ①.登录 -> 控制台 -> 入驻填写信息
- ②.创建网页/移动应用
2 - 沙箱环境
- 沙箱环境:沙箱环境是协助开发者进行接口开发及主要功能联调的模拟环境,目前仅支持网页/移动应用和小程序两种应用类型。在沙箱完成接口调试后,请务必在正式环境进行完整的功能验收测试。
二、支付宝公钥私钥
1 - 对称加密与非对称加密
2 - 公钥私钥在支付中的应用
3 - 公钥私钥配置生成
- 支付宝密钥生成器:沙箱应用 -> 自定义密钥 -> 公钥模式 -> 设置并查看 -> 支付宝密钥生成器
- 生成保存的本地默认路径:
C:\\Users\\Administrator\\Documents\\支付宝开放平台开发助手\\RSA密钥
- 使用工具生成公钥私钥
- 私钥我们自己保存
- 公钥配置到支付宝中
- 配置支付宝公钥:沙箱应用 -> 自定义密钥 -> 公钥模式 -> 设置并查看
4 - 授权回调地址
注意这里的授权回调,我们在内网测试的时候,这里需要使用到内网穿透技术,否则是无法接收到回调的
三、生成支付url并支付
1 - 生成url
- 使用第三方库生成:https://github.com/smartwalle/alipay
- 测试代码
package main
import (
"fmt"
"github.com/smartwalle/alipay/v3"
)
func main()
appID := "开放平台的appID"
privateKey := "应用私钥"
aliPublicKey := "支付宝公钥"
var client, err = alipay.New(appID, privateKey, false)
if err != nil
panic(err)
err = client.LoadAliPayPublicKey(aliPublicKey)
if err != nil
panic(err)
var p = alipay.TradePagePay // page支付方式使用
p.NotifyURL = "http://xxx" // 支付结果回调的url,注意内网穿透问题
p.ReturnURL = "http://127.0.0.1:8089" // 支付成功后倒计时结束跳转的页面
p.Subject = "标题"
p.OutTradeNo = "sn12389342479" //传递一个唯一单号
p.TotalAmount = "10.00"
p.ProductCode = "FAST_INSTANT_TRADE_PAY" // page支付必须使用这个配置
url, err := client.TradePagePay(p)
if err != nil
panic(err)
fmt.Println(url.String())
- 访问生成的支付url地址
2 - 测试支付
- 登录买家账号支付
四、gin集成支付宝支付
1 - nacos配置
- nacos我们需要配置什么:1、appID;2、应用私钥;3、支付宝公钥;4、notify_url;5、return_url
- order_web.json配置
"host": "192.168.124.9",
"name": "order_web",
"port": 8083,
"tags": ["mxshop","imooc","bobby","order","web"],
"goods_srv":
"name": "goods_srv"
,
"order_srv":
"name": "order_srv"
,
"inventory_srv":
"name": "inventory_srv"
,
"jwt":
"key": "VYLDYq3&hGWjWqF$K1ih"
,
"consul":
"host": "192.168.124.51",
"port": 8500
,
"alipay":
"app_id":"",
"private_key":"",
"ali_public_key":"",
"notify_url":"",
"return_url":""
2 - config添加alipay
- order_web/config/config.go
package config
type SrvConfig struct
Name string `mapstructure:"name" json:"name"`
type JWTConfig struct
SigningKey string `mapstructure:"key" json:"key"`
type ConsulConfig struct
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
type AlipayConfig struct
AppID string `mapstructure:"app_id" json:"app_id"`
PrivateKey string `mapstructure:"private_key" json:"private_key"`
AliPublicKey string `mapstructure:"ali_public_key" json:"ali_public_key"`
NotifyURL string `mapstructure:"notify_url" json:"notify_url"`
ReturnURL string `mapstructure:"return_url" json:"return_url"`
type ServerConfig struct
Name string `mapstructure:"name" json:"name"`
Host string `mapstructure:"host" json:"host"`
Tags []string `mapstructure:"tags" json:"tags"`
Port int `mapstructure:"port" json:"port"`
GoodsSrvInfo SrvConfig `mapstructure:"goods_srv" json:"goods_srv"`
OrderSrvInfo SrvConfig `mapstructure:"order_srv" json:"order_srv"`
InventorySrvInfo SrvConfig `mapstructure:"inventory_srv" json:"inventory_srv"`
JWTInfo JWTConfig `mapstructure:"jwt" json:"jwt"`
ConsulInfo ConsulConfig `mapstructure:"consul" json:"consul"`
AliPayInfo AlipayConfig `mapstructure:"alipay" json:"alipay"`
type NacosConfig struct
Host string `mapstructure:"host"`
Port uint64 `mapstructure:"port"`
Namespace string `mapstructure:"namespace"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
DataId string `mapstructure:"dataid"`
Group string `mapstructure:"group"`
3 - api_order添加支付
- order_web/api/order/api_order.go
func New(ctx *gin.Context)
orderForm := forms.CreateOrderForm
if err := ctx.ShouldBindJSON(&orderForm); err != nil
api.HandleValidatorError(ctx, err)
userId, _ := ctx.Get("userId")
rsp, err := global.OrderSrvClient.CreateOrder(context.Background(), &proto.OrderRequest
UserId: int32(userId.(uint)),
Name: orderForm.Name,
Mobile: orderForm.Mobile,
Address: orderForm.Address,
Post: orderForm.Post,
)
if err != nil
zap.S().Errorw("新建订单失败")
api.HandleGrpcErrorToHttp(err, ctx)
return
// 这里跳过了支付宝的支付的url生成和跳转,这个为了测试使用
if global.ServerConfig.AliPayInfo.AppID == "2021000121645456"
ctx.JSON(http.StatusOK, gin.H
"id": rsp.Id,
)
//生成支付宝的支付url
client, err := alipay.New(global.ServerConfig.AliPayInfo.AppID, global.ServerConfig.AliPayInfo.PrivateKey, false)
if err != nil
zap.S().Errorw("实例化支付宝失败")
ctx.JSON(http.StatusInternalServerError, gin.H
"msg": err.Error(),
)
return
err = client.LoadAliPayPublicKey(global.ServerConfig.AliPayInfo.AliPublicKey)
if err != nil
zap.S().Errorw("加载支付宝的公钥失败")
ctx.JSON(http.StatusInternalServerError, gin.H
"msg": err.Error(),
)
return
var p = alipay.TradePagePay
p.NotifyURL = global.ServerConfig.AliPayInfo.NotifyURL
p.ReturnURL = global.ServerConfig.AliPayInfo.ReturnURL
p.Subject = "订单-" + rsp.OrderSn
p.OutTradeNo = rsp.OrderSn
p.TotalAmount = strconv.FormatFloat(float64(rsp.Total), 'f', 2, 64)
p.ProductCode = "FAST_INSTANT_TRADE_PAY"
url, err := client.TradePagePay(p)
if err != nil
zap.S().Errorw("生成支付url失败")
ctx.JSON(http.StatusInternalServerError, gin.H
"msg": err.Error(),
)
return
ctx.JSON(http.StatusOK, gin.H
"id": rsp.Id,
"alipay_url": url.String(),
)
4 - 处理支付回调通知
- order_web/router/router_order.go:添加回调通知的router路由
package router
import (
"github.com/gin-gonic/gin"
"web_api/order_web/api/order"
"web_api/order_web/api/pay"
"web_api/order_web/middlewares"
)
func InitOrderRouter(Router *gin.RouterGroup)
OrderRouter := Router.Group("orders").Use(middlewares.SetUserId())
OrderRouter.GET("", order.List) // 订单列表
//BannerRouter.GET("", middlewares.JWTAuth(), middlewares.IsAdminAuth(), order.List) // 订单列表
OrderRouter.POST("", order.New) // 新建订单
OrderRouter.GET("/:id/", order.Detail) // 订单详情
PayRouter := Router.Group("pay")
PayRouter.POST("alipay/notify", pay.Notify)
- order_web/api/pay/api_alipay.go
package pay
import (
"context"
"github.com/gin-gonic/gin"
"github.com/smartwalle/alipay/v3"
"go.uber.org/zap"
"net/http"
"web_api/order_web/proto"
"web_api/order_web/global"
)
func Notify(ctx *gin.Context)
//支付宝回调通知
client, err := alipay.New(global.ServerConfig.AliPayInfo.AppID, global.ServerConfig.AliPayInfo.PrivateKey, false)
if err != nil
zap.S().Errorw("实例化支付宝失败")
ctx.JSON(http.StatusInternalServerError, gin.H
"msg": err.Error(),
)
return
err = client.LoadAliPayPublicKey(global.ServerConfig.AliPayInfo.AliPublicKey)
if err != nil
zap.S().Errorw("加载支付宝的公钥失败")
ctx.JSON(http.StatusInternalServerError, gin.H
"msg": err.Error(),
)
return
notify, err := client.GetTradeNotification(ctx.Request) //这个会自动验证签名是否正确
if err != nil
ctx.JSON(http.StatusInternalServerError, gin.H)
return
_, err = global.OrderSrvClient.UpdateOrderStatus(context.Background(), &proto.OrderStatus
OrderSn: notify.OutTradeNo, // 商户订单号,这个是我们自己生成的订单号
Status: string(notify.TradeStatus),
)
if err != nil
ctx.JSON(http.StatusInternalServerError, gin.H)
return
ctx.String(http.StatusOK, "success")
五、完整源码
- 完整源码下载:mxshop_srvsV9.0rar
- 源码说明:(nacos的ip配置自行修改,全局变量DEV_CONFIG设置:1=zsz,2=comp,3=home)
- goods_srv/model/sql/mxshop_goods.sql:包含了建表语句
- other_import/api.json:YApi的导入文件
- other_import/nacos_config_export_user.zip:nacos的user配置集导入文件
- other_import/nacos_config_export_goods.zip:nacos的goods配置集导入文件
- other_import/nacos_config_export_inventory.zip:nacos的inventory的配置导入文件
- other_import/nacos_config_export_orders.zip:nacos的orders的配置导入文件
接入支付宝支付SDK
参考技术A 接入支付宝支付SDK可以说支付宝支付接入是所有SDK最好接入的,没有之一。
客户端不用签名,也不用管包名,也不用管签名文件,就接口返回订单,把订单交给支付宝SDK调用就行,成功或者失败都在当前界面返回给你。你再去通知接口。
支付流程图
官方文档地址
!支付宝支付官方文档地址
按照文档说明接入SDK和相关配置,在这就不重复了
客户端支付关键代码===》支付接口的调用(调起支付弹框)
记住支付接口的调用必须在独立的非ui线程中执行,即需新开线程里面调用。可以想官方demo一样用new Thread方式。
下面我给出用Observable方式示例代码
在PayUtils中
/**
* desc:支付宝支付
* Created by congge on 2018/8/27 17:20
* @param orderInfo 接口返回的订单
**/
public static void aliPay(final Activity activity, final String orderInfo, final OrderListener orderListener)
Observable.just(orderInfo)
.map(new Function ()
@Override
public String apply(String orderInfo) throws Exception
//用户在商户app内部点击付款,是否需要一个loading做为在钱包唤起之前的过渡,这个值设置为true
return new PayTask(activity).pay(orderInfo, true);
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer ()
@Override
public void accept(String payResult) throws Exception
orderListener.onPayResult(payResult);
);
支付结果返回处理
返回例子:
resultStatus=9000;memo=;result="alipay_trade_app_pay_response":"code":"10000","msg":"Success","app_id":"2016091300503896","auth_app_id":"2016091300503896","charset":"utf-8","timestamp":"2018-08-28 17:51:11","out_trade_no":"nVElbd74TW6WnEyxQwvX8A","total_amount":"0.01","trade_no":"2018082821001004680500208879","seller_id":"2088102175487650","sign":"W0Hg9k4GxL8Oaxymvqk2i65WNDQxYp6HGve32ek6VjSRnymmI3GQTjpQVbZuDzvjcwQ/HIkM97PoBGAVlTmi/wiJcqDgSSDzDY7AFnNN0OcK0ehWGwKQINA4IDGh51A7yY/vYKmR0VW+2OwGhlRPPMMZtQOEqh8a9/aIijzT6ZLwy9Hl4ayG/fVKhdC1VdckF6+C25BFNp3fIxarg5tfEunm7N9iWngKCUsnP+IZz05OHdvynimgYPcBnbBERHG97GVqRT/EdBWTQyIDMc0LemScAYxJixTVgXDkRddQjzWZ7HgLdBfjs0nXY24puHudT76ERxVY+8NkoKle/QI+FA==","sign_type":"RSA2"
也可以自己打log看看
处理示例代码:
//支付宝支付
PayUtils.aliPay(this, result.getSignDataStr(), new PayUtils.OrderListener()
@Override
public void onPayResult(String payResult)
PayResult pr = new PayResult(payResult);
String rs = pr.getResultStatus();
String r = pr.getResult();
switch (rs)
case AliPayResultStatus.PAY_SUCCESS:
ToastUtils.show(R.string.pay_success);
//通知接口支付成功
break;
case AliPayResultStatus.PAY_PROCESSING:
case AliPayResultStatus.PAY_UNKNOWN:
ToastUtils.show(R.string.pay_fail);
//支付可能成功,要接口去查询
break;
default:
ToastUtils.show(R.string.pay_fail);
//通知接口支付失败,取消订单
);
上面方法中:
//通知接口支付成功 //支付可能成功,要接口去查询 //通知接口支付失败,取消订单。根据你产品需求要不要通知你服务器做的操作。正常是要的,用来改变订单状态
PayResult.class
public class PayResult
private String resultStatus;
private String result;
private String memo;
public PayResult(String rawResult)
if (TextUtils.isEmpty(rawResult))
return;
String[] resultParams = rawResult.split(";");
for (String resultParam : resultParams)
if (resultParam.startsWith("resultStatus"))
resultStatus = gatValue(resultParam, "resultStatus");
if (resultParam.startsWith("result"))
result = gatValue(resultParam, "result");
if (resultParam.startsWith("memo"))
memo = gatValue(resultParam, "memo");
@Override
public String toString()
return "resultStatus=" + resultStatus + ";memo=" + memo
+ ";result=" + result + "";
private String gatValue(String content, String key)
String prefix = key + "=";
return content.substring(content.indexOf(prefix) + prefix.length(),
content.lastIndexOf(""));
public String outOrder()
String order = ""out_trade_no"";
if (result.contains(order))
String begin = result.substring(result.indexOf(order));
String ss = begin.split(",")[0];
String newS = ss.replace(""", "")
.replace("", "")
.replace(":", "")
.replace("out_trade_no", "");
try
return newS;
catch (Exception e)
e.printStackTrace();
return "";
/**
* @return the resultStatus
*/
public String getResultStatus()
return resultStatus;
/**
* @return the memo
*/
public String getMemo()
return memo;
/**
* @return the result
*/
public String getResult()
return result;
最后给下支付返回码表
AliPayResultStatus.class
public class AliPayResultStatus
/**
* 订单支付成功,唯一肯定是支付成功的
*/
public static final String PAY_SUCCESS = "9000";
/**
* 正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
*/
public static final String PAY_PROCESSING = "8000";
/**
* 订单支付失败
*/
public static final String PAY_FAIL = "4000";
/**
* 重复请求
*/
public static final String PAY_REPEAT = "5000";
/**
* 用户中途取消
*/
public static final String PAY_PROCESS_CANCEL = "6001";
/**
* 网络连接出错
*/
public static final String PAY_NET_ERROR = "6002";
/**
* 支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
*/
public static final String PAY_UNKNOWN = "6004";
还有一个直接弃用沙箱调试模式,否则提示支付失败也有可能不知道错在那,怕金额大,和接口商量,测试服务器就用0.01测试。
以上是关于26支付宝支付的主要内容,如果未能解决你的问题,请参考以下文章