1.1 官网


沙箱官网:

https://open.alipay.com/develop/sandbox/app

秘钥用具下载:

https://opendocs.alipay.com/common/02kipk?pathHash=0d20b438

image-20231027214014588

1.2 秘钥生成(系统默认)

image-20231027214829962

1.3 秘钥生成(软件生成)


  • 点击生成密钥

image-20231027214209352

  • 生成成功

image-20231027214306694

  • 自定义密钥

image-20231027214456066****

  • 复制粘贴之前生成的公钥并点击保存

image-20231027214551413

  • 继续点击确认

image-20231027214642751

1.4 golan 安装 SDK


go get -u github.com/smartwalle/alipay/v3

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.5 GoLand 代码


  • app
    • utils
      • abfPay.go
package utils

import (
	"fmt"
	"github.com/smartwalle/alipay/v3"
	"net/url"
)

func ZfbPay(orderID string, totalPrice string) string {
	appID := "9021000131612134" // 你的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.TradeWapPay{}
	var p = alipay.TradePagePay{}
	p.NotifyURL = "http://192.168.137.188:5173/#/pages/pay-success/pay-success" //支付宝回调
	p.ReturnURL = "http://192.168.137.188:5173/#/pages/pay-success/pay-success" //支付后调转页面
	p.Subject = "云尚校园-订单支付"                                                     //标题
	p.OutTradeNo = orderID                                                      //传递一个唯一单号
	p.TotalAmount = totalPrice                                                  //金额
	//p.ProductCode = "QUICK_WAP_WAY"
	p.ProductCode = "FAST_INSTANT_TRADE_PAY" //网页支付
	var url2 *url.URL
	url2, err = client.TradePagePay(p)
	if err != nil {
		fmt.Println(err)
	}

	var payURL = url2.String()
	println(payURL)
	return payURL
}

  • app
    • dto
      • Pay.go
package dto

type ShopPay struct {
	ByCode          string `json:"byCode"`
	ShopID          string `json:"id"`
	OrderTips       string `json:"tips"`
	OrderTotalPrice string `json:"totalPrice"`
	OrderStatus     string `json:"status"`
	OrderID         string `json:"order_id"`
}
  • app
    • model
      • Pay.go
package models

import "gorm.io/gorm"

//
//  ShopPay
//  @Description: 生成订单号
//

type ShopPay struct {
	gorm.Model
	ByCode          string `gorm:"type:varchar(100)"`
	OrderId         string `gorm:"type:varchar(100); unique;not null"` // 订单ID
	OrderStatus     string `gorm:"type:varchar(100); not null"`        // 订单状态
	OrderTips       string `gorm:"type:varchar(200); not null"`        // 订单备注
	OrderTotalPrice string `gorm:"type:varchar(100); not null"`
	ShopID          string `gorm:"type:varchar(100); not null"`
}
  • app
    • common
      • databaseMySQL.go
package common

import (
	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var DB *gorm.DB

func InitDB() *gorm.DB {
	host := viper.GetString("datasource.host")
	port := viper.GetString("datasource.port")
	database := viper.GetString("datasource.database")
	username := viper.GetString("datasource.username")
	password := viper.GetString("datasource.password")
	charset := viper.GetString("datasource.charset")

	db, err := gorm.Open(mysql.Open(username+`:`+password+`@tcp(`+host+`:`+port+`)/`+database+`?charset=`+charset+`&parseTime=true&loc=Local`),
		&gorm.Config{})

	if err != nil {
		panic("failed to connect database, err: " + err.Error())
	}

	db.AutoMigrate(&model.ShopPay{})

	DB = db
	return db
}

func GetDB() *gorm.DB {
	return DB
}

  • app
    • config
      • application.yml
server:
  port: 9999

datasource:
  diverName: mysql
  host: 127.0.0.1
  port: 3306
  database: go-app
  username: root
  password: 123456
  charset: utf8
  • app
    • controller
      • PayController.go
package controller

import "github.com/gin-gonic/gin"

type PayController interface {
	AddShopPay(ctx *gin.Context)
	OrderPay(ctx *gin.Context)
}
  • app
    • controller
      • pay
        • pay.go
package pay

import (
	"github.com/gin-gonic/gin"
	"go-app/common"
	"go-app/controller"
	"go-app/dto"
	model "go-app/models"
	"go-app/response"
	"go-app/utils"
	"gorm.io/gorm"
	"strconv"
)

type PayFun interface {
	controller.PayController
}

type payDB struct {
	DB *gorm.DB
}

func PayFunction() PayFun {
	db := common.GetDB()
	db.AutoMigrate(model.User{})
	return payDB{DB: db}
}

func (db payDB) AddShopPay(ctx *gin.Context) {
	getPayData := dto.ShopPay{}
	ctx.BindJSON(&getPayData)
	getPayData.OrderStatus = "2"
	getPayData.OrderID = strconv.FormatInt(utils.GetSnowflakeId(), 10)
	if getPayData.ByCode != "" {
		db.DB.Debug().Create(&getPayData)
	}
	response.Success(ctx, gin.H{"data": getPayData}, "success")
}
func (db payDB) OrderPay(ctx *gin.Context) {
	order := model.ShopPay{}
	id, _ := strconv.Atoi(ctx.Params.ByName("orderID"))
	db.DB.Debug().Where("order_id", id).First(&order)
	pay := utils.ZfbPay(order.OrderId, order.OrderTotalPrice)
	response.Success(ctx, gin.H{"data": pay}, "success")
}
  • app
    • router.go
package main

import (
	"github.com/gin-gonic/gin"
	shopController "go-app/controller/shop"
)
func CollectRoute(r *gin.Engine) *gin.Engine {

	// 支付页面
	payGroup := r.Group("api/pay/")
	payFun := payController.PayFunction()
	payGroup.POST("/AddShopPay/", payFun.AddShopPay)
	payGroup.POST("/orderPay/:orderID", payFun.OrderPay)
	return r
}

  • app
    • main.go
package main

import (
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"go-app/common"
	"os"
)

func main() {
	InitConfig()
	common.InitDB()
	r := gin.Default()
	config := cors.DefaultConfig()
	config.AllowAllOrigins = true                            //允许所有域名
	config.AllowMethods = []string{"GET", "POST", "OPTIONS"} //允许请求的方法
	config.AllowHeaders = []string{"token", "tus-resumable", "upload-length", "upload-metadata", "cache-control", "x-requested-with", "*"}
	r.Use(cors.New(config))

	// 定义路由和处理函数
	r = CollectRoute(r)
	port := viper.GetString("server.port")
	if port != "" {
		panic(r.Run(":" + port))
	}
	r.Run()
}

func InitConfig() {
	workDir, _ := os.Getwd()
	viper.SetConfigName("application")
	viper.SetConfigType("yml")
	viper.AddConfigPath(workDir + "/config")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
}

1.6 前端代码


<template>
	<view>
		<!-- 自定义导航栏 -->
		<view class="box-bg" style="font-size: 36rpx;">
			<!-- <uni-nav-bar shadow left-icon="left" right-icon="cart" title="购物车" /> -->
			<uni-nav-bar shadow fixed="true" left-icon="left" right-text="关闭" title="支付订单" statusBar="true"
				@clickLeft="backCommitShop" @clickRight="colsePay" />
		</view>
		<!-- 支付选择模块 -->
		<view class="pay-main">
			<radio-group name="">
				<label>
					<view class="pay-item">
						<view v-for="(item,index) in payItemIamges.data" :key="index">
							<view class="pay-connect">
								<img class="pay-item-image" :src="item.imageUrl" alt="">
								<view class="pay-item-text">
									<view class="pay-item-text-top">{{item.nameFather}}</view>
									<view class="pay-item-text-foot">{{item.name}}</view>
								</view>
								<label class="pay-radio">
									<radio :checked="isChecked" color="#F33" /><text></text>
								</label>
							</view>
						</view>
					</view>
				</label>
			</radio-group>
		</view>
		<!-- 底部去支付模块 -->
		<view class="foot-pay">
			<view class="total-pay">
				<view class="total">合计:</view>
				<view class="total">¥{{payMoney}}</view>
			</view>
			<view class="go-pay" @tap="goPay">去支付</view>
		</view>
	</view>
</template>

<script setup>
	import {
		onLoad,
	} from '@dcloudio/uni-app';
	import {
		reactive,
		ref
	} from "vue"


	import {orderPay} from "@/api/shop/pay.js"

	onLoad((e) => {
		// 获取价格
		payMoney.value = e.price;
		// 获取订单号
		orderID.value = e.orderID;

	})

	// 选择支付方式
	const isChecked = ref(false);

	const payItemIamges = reactive({
		data: [{
				nameFather: "微信支付",
				name: "推荐微信用户使用",
				imageUrl: "http://s1jh1gxy3.hn-bkt.clouddn.com/shopCartCommit/wPay.png"
			},
			{
				nameFather: "支付宝支付",
				name: "推荐支付宝用户使用",
				imageUrl: "http://s1jh1gxy3.hn-bkt.clouddn.com/shopCartCommit/zPay.png"
			}
		]
	})
	// 获取金额

	const payMoney = ref(0);
	// 订单ID 
	const orderID = ref(0);

	// 去支付
	const goPay = () => {
		uni.navigateTo({
			url:"@/pages/pay-success/pay-success"
		})
		orderPay(orderID.value).then(res=>{
			//#ifdef APP-PLUS  
			plus.runtime.openURL(res.data.data, function(res){
				console.log(res);
			})
			//#endif 
			
			// #ifdef H5
			 window.open(res.data.data)
			// #endif
		})
	}

	const backCommitShop = () => {
		uni.navigateBack({
			delta: 1
		})
	}

	const colsePay = () => {
		uni.navigateTo({
			url: "../shop-commit/shop-commit"
		})
	}
</script>

<style lang="less" scoped>
	// 底部样式
	.foot-pay {
		border-top: 2rpx solid #fcc;
		line-height: 100rpx;
		height: 100rpx;
		width: 100%;
		position: fixed;
		bottom: 0;
		left: 0;
		display: flex;
		justify-content: space-between;
		align-items: center;

		.total-pay {
			display: flex;
			flex: 1;
			background-color: black;
			color: white;
			padding-left: 120rpx;

			.total {
				padding: 0rpx 7rpx;
			}
		}

		.go-pay {
			padding: 0rpx 100rpx;
			color: white;
			background-color: #49BDFB;
		}
	}

	// 支付样式
	.pay-main {
		margin-top: 15rpx;

		.pay-item {

			.pay-connect {
				display: flex;
				justify-content: space-between;
				padding: 20rpx 30rpx;
				border-bottom: 8rpx solid #F5F5F5;

				.pay-item-image {
					width: 100rpx;
					height: 100rpx;
				}

				.pay-item-text {
					flex: 1;
					padding-left: 80rpx;

					.pay-item-text-top {
						font-weight: bold;
					}

					.pay-item-text-foot {
						color: #636263;
					}
				}

				.pay-radio {
					padding-top: 20rpx;
				}
			}
		}
	}


	.box-bg {
		background-color: #F5F5F5;
		padding: 0 5px 0;
	}

	::v-deep uni-text.uni-nav-bar-text.uni-ellipsis-1 {
		font-size: 34rpx;
		font-weight: bolder;
	}

	::v-deep uni-text.uni-nav-bar-right-text {
		font-size: 32rpx;
		font-weight: bolder;
	}

	pay-item-text {
			flex: 1;
				padding-left: 80rpx;

				.pay-item-text-top {
					font-weight: bold;
				}

				.pay-item-text-foot {
					color: #636263;
				}
			}

			.pay-radio {
				padding-top: 20rpx;
			}
		}
	}
		}
	
	
		.box-bg {
			background-color: #F5F5F5;
			padding: 0 5px 0;
		}
	
		::v-deep uni-text.uni-nav-bar-text.uni-ellipsis-1 {
			font-size: 34rpx;
			font-weight: bolder;
		}
	
		::v-deep uni-text.uni-nav-bar-right-text {
			font-size: 32rpx;
			font-weight: bolder;
		}
</style>

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部