26、支付宝支付

目录

  • 一、支付宝流程
    • 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、支付宝支付_第1张图片
26、支付宝支付_第2张图片

2 - 沙箱环境

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

二、支付宝公钥私钥

1 - 对称加密与非对称加密

26、支付宝支付_第4张图片

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

26、支付宝支付_第5张图片

3 - 公钥私钥配置生成

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

26、支付宝支付_第9张图片
26、支付宝支付_第10张图片

4 - 授权回调地址

注意这里的授权回调,我们在内网测试的时候,这里需要使用到内网穿透技术,否则是无法接收到回调的
26、支付宝支付_第11张图片


三、生成支付url并支付

1 - 生成url

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

26、支付宝支付_第12张图片

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

26、支付宝支付_第13张图片

  • 访问生成的支付url地址

26、支付宝支付_第14张图片

2 - 测试支付

26、支付宝支付_第15张图片

  • 登录买家账号支付
    26、支付宝支付_第16张图片
    26、支付宝支付_第17张图片
    26、支付宝支付_第18张图片
    26、支付宝支付_第19张图片

四、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的配置导入文件

你可能感兴趣的:(Go微服务实战-电商系统,golang,微服务,架构,分布式,consul)