目录

  • 一、支付宝流程
    • 1 – 正式上线流程
    • 2 – 沙箱环境
  • 二、支付宝公钥私钥
    • 1 – 对称加密与非对称加密
    • 2 – 公钥私钥在支付中的应用
    • 3 – 公钥私钥配置生成
    • 4 – 授权回调地址
  • 三、生成支付url并支付
    • 1 – 生成url
    • 2 – 测试支付
  • 四、gin集成支付宝支付
    • 1 – nacos配置
    • 2 – config添加alipay
    • 3 – api_order添加支付
    • 4 – 处理支付回调通知
  • 五、完整源码

一、支付宝流程

1 – 正式上线流程

  • 支付宝开放平台:https://open.alipay.com/
    • ①.登录 -> 控制台 -> 入驻填写信息
    • ②.创建网页/移动应用

26、支付宝支付-编程知识网
26、支付宝支付-编程知识网

2 – 沙箱环境

  • 沙箱环境:沙箱环境是协助开发者进行接口开发及主要功能联调的模拟环境,目前仅支持网页/移动应用和小程序两种应用类型。在沙箱完成接口调试后,请务必在正式环境进行完整的功能验收测试。
    26、支付宝支付-编程知识网

二、支付宝公钥私钥

1 – 对称加密与非对称加密

26、支付宝支付-编程知识网

2 – 公钥私钥在支付中的应用

26、支付宝支付-编程知识网

3 – 公钥私钥配置生成

  • 支付宝密钥生成器:沙箱应用 -> 自定义密钥 -> 公钥模式 -> 设置并查看 -> 支付宝密钥生成器
  • 生成保存的本地默认路径C:\Users\Administrator\Documents\支付宝开放平台开发助手\RSA密钥
    26、支付宝支付-编程知识网
    26、支付宝支付-编程知识网
  • 使用工具生成公钥私钥
    • 私钥我们自己保存
    • 公钥配置到支付宝中
      26、支付宝支付-编程知识网
  • 配置支付宝公钥:沙箱应用 -> 自定义密钥 -> 公钥模式 -> 设置并查看

26、支付宝支付-编程知识网
26、支付宝支付-编程知识网

4 – 授权回调地址

注意这里的授权回调,我们在内网测试的时候,这里需要使用到内网穿透技术,否则是无法接收到回调的
26、支付宝支付-编程知识网


三、生成支付url并支付

1 – 生成url

  • 使用第三方库生成:https://github.com/smartwalle/alipay

26、支付宝支付-编程知识网

  • 测试代码
package mainimport ("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())
}

26、支付宝支付-编程知识网

  • 访问生成的支付url地址

26、支付宝支付-编程知识网

2 – 测试支付

26、支付宝支付-编程知识网

  • 登录买家账号支付
    26、支付宝支付-编程知识网
    26、支付宝支付-编程知识网
    26、支付宝支付-编程知识网
    26、支付宝支付-编程知识网

四、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 configtype 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,})}//生成支付宝的支付urlclient, 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.NotifyURLp.ReturnURL = global.ServerConfig.AliPayInfo.ReturnURLp.Subject = "订单-" + rsp.OrderSnp.OutTradeNo = rsp.OrderSnp.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 routerimport ("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 payimport ("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的配置导入文件