简介
由于开通支付宝支付需要提交各种各样的资料,这里使用的是沙箱环境,不过跟真正的支付宝都是一样的
代码
config.yaml
app_id: '你的appID'
private_key: '你的私钥'
ali_public_key: '你的阿里公钥'
notify_url: '支付成功回调地址'
return_url: '支付成功跳转地址'
product_code: 'FAST_INSTANT_TRADE_PAY' # 销售产品码,与支付宝签约的产品码名称
sub_ject: '番茄炒蛋' # 订单标题
config
type AliConfig struct {
AppID string `mapstructure:"app_id"`
PrivateKey string `mapstructure:"private_key"`
AliPublicKey string `mapstructure:"ali_public_key"`
NotifyURL string `mapstructure:"notify_url"`
ReturnURL string `mapstructure:"return_url"`
ProductCode string `mapstructure:"product_code"`
Subject string `mapstructure:"sub_ject"`
}
server
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/satori/go.uuid"
"github.com/smartwalle/alipay/v3"
"github.com/spf13/viper"
"go-alipay/config"
"log"
"net/http"
"strings"
)
var (
AliPayClient *alipay.Client
AliPayConfig config.AliConfig
)
func main() {
r := gin.Default()
InitAliConfig()
InitAlipayClient()
r.GET("/ping", Pong)
r.GET("/get/pay", GetPay)
r.POST("/alipay/notify", Notify)
_ = r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
// InitAliConfig 初始化配置文件
func InitAliConfig() {
v := viper.New()
// 路径必须要写相对路径,相对于项目的路径
v.SetConfigFile("config.yaml")
if err := v.ReadInConfig(); err != nil {
log.Fatalf("读取配置文件失败: %s", err.Error())
}
// 映射到结构体
if err := v.Unmarshal(&AliPayConfig); err != nil {
log.Fatalf("映射结构体失败: %s", err.Error())
}
}
// InitAlipayClient 初始化*alipay.Client
// 生成支付url和回调都需要用,只初始化一次就可以了
func InitAlipayClient() {
var err error
// isProduction - 是否为生产环境,传 false 的时候为沙箱环境,用于开发测试,正式上线的时候需要改为 true
AliPayClient, err = alipay.New(AliPayConfig.AppID, AliPayConfig.PrivateKey, false)
if err != nil {
log.Fatalf("加载alipay.Client失败: %s", err.Error())
}
// 加载支付宝公钥
err = AliPayClient.LoadAliPayPublicKey(AliPayConfig.AliPublicKey)
if err != nil {
log.Fatalf("加载支付宝公钥失败: %s", err.Error())
}
}
// Pong ReturnURL:支付成功后会请求一次这个
func Pong(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{
"message": "pong",
})
}
// Notify 回调地址: 支付成功后会回调这里;我们可以用来修改订单状态等等
func Notify(ctx *gin.Context) {
noti, err := AliPayClient.GetTradeNotification(ctx.Request)
if err != nil {
log.Println("获取回调信息失败", err.Error())
ctx.Status(http.StatusInternalServerError)
return
}
fmt.Printf("订单号:%s;状态:%s\n", noti.OutTradeNo, noti.TradeStatus)
ctx.String(http.StatusOK, "success")
}
// GetPay 获取支付url
func GetPay(ctx *gin.Context) {
OutTradeNo := fmt.Sprintf("%s", strings.ReplaceAll(uuid.NewV4().String(), "-", ""))
var p = alipay.TradePagePay{}
p.NotifyURL = AliPayConfig.NotifyURL // 回调地址;用来通知我们支付结果的,好去修改状态
p.ReturnURL = AliPayConfig.ReturnURL // 返回地址;支付成功后,浏览器内跳转地址
p.Subject = AliPayConfig.Subject
p.OutTradeNo = OutTradeNo
p.TotalAmount = "10.00"
p.ProductCode = AliPayConfig.ProductCode
url, err := AliPayClient.TradePagePay(p)
if err != nil {
log.Fatalf("生成支付url失败: %s", err.Error())
}
var payURL = url.String()
log.Printf("订单号:%s创建支付url成功;", OutTradeNo)
ctx.JSON(http.StatusOK, gin.H{
"url": payURL,
})
}
测试
获取支付url
复制返回的url进行支付