目录
- 一、支付宝流程
-
- 二、支付宝公钥私钥
-
- 1 - 对称加密与非对称加密
- 2 - 公钥私钥在支付中的应用
- 3 - 公钥私钥配置生成
- 4 - 授权回调地址
- 三、生成支付url并支付
-
- 四、gin集成支付宝支付
-
- 1 - nacos配置
- 2 - config添加alipay
- 3 - api_order添加支付
- 4 - 处理支付回调通知
- 五、完整源码
一、支付宝流程
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{}
p.NotifyURL = "http://xxx"
p.ReturnURL = "http://127.0.0.1:8089"
p.Subject = "标题"
p.OutTradeNo = "sn12389342479"
p.TotalAmount = "10.00"
p.ProductCode = "FAST_INSTANT_TRADE_PAY"
url, err := client.TradePagePay(p)
if err != nil {
panic(err)
}
fmt.Println(url.String())
}
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
}
if global.ServerConfig.AliPayInfo.AppID == "2021000121645456" {
ctx.JSON(http.StatusOK, gin.H{
"id": rsp.Id,
})
}
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)
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的配置导入文件