目录
- 一、支付宝流程
-
- 二、支付宝公钥私钥
-
- 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:UsersAdministratorDocuments支付宝开放平台开发助手RSA密钥
- 使用工具生成公钥私钥
- 私钥我们自己保存
- 公钥配置到支付宝中
- 配置支付宝公钥:沙箱应用 -> 自定义密钥 -> 公钥模式 -> 设置并查看
4 – 授权回调地址
注意这里的授权回调,我们在内网测试的时候,这里需要使用到内网穿透技术,否则是无法接收到回调的
三、生成支付url并支付
1 – 生成url
- 使用第三方库生成:https://github.com/smartwalle/alipay
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{} 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 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}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.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) 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的配置导入文件