一.界面展示
当用户点击'去支付'时,请求支付界面,并 展示对应订单相关数据,以及 支付方式相关操作,点击对应的支付方式,进行支付操作
该界面对应的功能:
1.进入该界面,后台逻辑判断: 是否存在该订单,如果不存在,则跳转到购物车页面;如果存在,则获取对应订单相关数据,并 渲染到页面
2.选择支付方式,根据不同支付方式进行支付操作
支付宝支付: 点击 '支付宝'支付方式,会请求后台,通过支付宝相关配置以及方法,生成一个 支付url,重定向到对应的支付url,用户扫描支付,支付完成后,跳转到服务端设置的 返回页面,然后支付宝服务器会请求配置的服务端 回调地址,进行订单校验以及对应的 订单逻辑处理
微信支付: 点击'微信支付'支付方式,也会请求后台,通过微信相关配置以及方法,生成一个支付 二维码,展示到界面,用户扫描支付完成后,微信服务器会请求配置的服务端 回调地址,进行订单校验以及对应的 订单逻辑处理(修改订单支付状态等),然后前端在这个支付页面会每个几秒(一般方法是定时 ajax轮询,或者 web_socket请求)请求一个接口,判断该订单是否支付,如果支付了,就跳转到支付成功页面
去支付页面
微信支付页面
点击'微信支付'支付方式,也会请求后台,通过微信相关配置以及方法,生成一个支付二维码,展示到界面,用户扫描支付完成后,微信服务器会请求配置的服务端回调地址,进行订单校验以及对应的订单逻辑处理(修改订单支付状态等),然后前端在这个支付页面会每个几秒(一般方法是定时ajax轮询,或者web_socket请求)请求一个接口,判断该订单是否支付,如果支付了,就跳转到支付成功页面
微信支付页面
点击 '支付宝'支付方式,会请求后台,通过支付宝相关配置以及方法,生成一个支付url,重定向到对应的支付url,用户扫描支付,支付完成后,跳转到服务端设置的返回页面,然后支付宝服务器会请求配置的服务端回调地址,进行订单校验以及对应的订单逻辑处理
二.代码展示
集成支付宝支付控制器代码
要使用 github.com/smartwalle/alipay/v3需要先引入:
直接在import中引入 github.com/smartwalle/alipay/v3,然后go mod tidy就可以了
package frontend
import (
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/smartwalle/alipay/v3"
)
type AlipayController struct{}
//支付宝支付请求接口
func (con AlipayController) Alipay(c *gin.Context) {
//1、获取订单号 判断此订单号是否值当前用户的
//2、获取订单里面的支付信息
var privateKey = "xxx" // 必须,上一步中使用 RSA签名验签工具 生成的私钥
var client, err = alipay.New("2021xxx588", privateKey, true)
client.LoadAppPublicCertFromFile("crt/appCertPublicKey_2021xxx588.crt") // 加载应用公钥证书
client.LoadAliPayRootCertFromFile("crt/alipayRootCert.crt") // 加载支付宝根证书
client.LoadAliPayPublicCertFromFile("crt/alipayCertPublicKey_RSA2.crt") // 加载支付宝公钥证书
// 将 key 的验证调整到初始化阶段
if err != nil {
fmt.Println(err)
return
}
//支付宝PC扫描方式支付
var p = alipay.TradePagePay{}
p.NotifyURL = "http://xxx/v3/alipayNotify" // 回调地址
p.ReturnURL = "http://xxx5/v3/alipayReturn" //支付后跳转地址
p.Subject = "测试 公钥证书模式-这是一个gin订单"
template := "2006-01-02 15:04:05"
p.OutTradeNo = time.Now().Format(template)
p.TotalAmount = "0.1" //支付金额(元)
p.ProductCode = "FAST_INSTANT_TRADE_PAY" //根据支付方式调整
var url, err4 = client.TradePagePay(p)
if err4 != nil {
fmt.Println(err4)
}
//支付url
var payURL = url.String()
//重定向到支付url
c.Redirect(http.StatusFound, payURL)
}
//支付回调
func (con AlipayController) AlipayNotify(c *gin.Context) {
var privateKey = "xxx" // 必须,上一步中使用 RSA签名验签工具 生成的私钥
var client, err = alipay.New("202xxx588", privateKey, true)
client.LoadAppPublicCertFromFile("crt/appCertPublicKey_202xxx588.crt") // 加载应用公钥证书
client.LoadAliPayRootCertFromFile("crt/alipayRootCert.crt") // 加载支付宝根证书
client.LoadAliPayPublicCertFromFile("crt/alipayCertPublicKey_RSA2.crt") // 加载支付宝公钥证书
if err != nil {
fmt.Println(err)
return
}
req := c.Request
req.ParseForm()
//支付校验
ok, _ := client.VerifySign(req.Form)
fmt.Println(ok)
fmt.Println(req.Form)
//订单逻辑处理...
c.String(200, "ok")
}
//支付后跳转页面
func (con AlipayController) AlipayReturn(c *gin.Context) {
c.String(200, "支付成功")
}
集成微信支付控制器代码
要使用 github.com/objcoding/wxpay需要先引入:
直接在import中引入github.com/objcoding/wxpay,然后go mod tidy就可以了, qrcode的引入方式也是一样的
package frontend
import (
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/objcoding/wxpay"
qrcode "github.com/skip2/go-qrcode"
)
type WxpayController struct{}
//微信支付
func (con WxpayController) Wxpay(c *gin.Context) {
//1、获取订单号 判断此订单号是否值当前用户的
//2、获取订单里面的支付信息
//1、配置基本信息
account := wxpay.NewAccount(
"wx7xxx6e4", // appId
"150xxx", //商户id
"zhongyxxx66", //密钥
false,
)
client := wxpay.NewClient(account)
//2、获取ip地址,订单号等信息
ip := c.ClientIP()
template := "200601021504"
tradeNo := time.Now().Format(template)
//3、调用统一下单
params := make(wxpay.Params)
params.SetString("body", "Gin微信支付").
SetString("out_trade_no", tradeNo).
SetInt64("total_fee", 1). //1分
SetString("spbill_create_ip", ip).
SetString("notify_url", "http://xxx/wxpay/notify"). //必须在商户平台的Native支付回调链接里面配置
// SetString("trade_type", "APP")
SetString("trade_type", "NATIVE") //网站支付需要改为NATIVE
p, err1 := client.UnifiedOrder(params)
if err1 != nil {
c.String(http.StatusOK, "生成二维码失败")
return
}
//4、获取code_url 生成支付二维码
png, err := qrcode.Encode(p["code_url"], qrcode.Medium, 256)
if err != nil {
c.String(http.StatusOK, "生成二维码失败")
return
}
c.String(http.StatusOK, string(png))
}
/*
支付回调:
1、发布到服务器测试
2、必须在商户平台的Native支付回调链接里面配置
3、如何接收XML的数据 c.GetRawData()
4、如何获取数据
5、如何验证数据
6、更新数据
*/
func (con WxpayController) WxpayNotify(c *gin.Context) {
//1、获取表单传过来的xml数据
xmlByte, _ := c.GetRawData()
xmlStr := string(xmlByte)
postParams := wxpay.XmlToMap(xmlStr)
//2、校验签名
account := wxpay.NewAccount(
"wx7xxxe4",
"150xxx1",
"zhongxxx66",
false,
)
client := wxpay.NewClient(account)
isValidate := client.ValidSign(postParams)
fmt.Println(isValidate)
fmt.Println("-----更新订单-----")
fmt.Println(postParams)
//3、更新订单
c.String(200, "ok")
}
查看订单支付状态方法
在controllers/frontend/BuyController.go下增加查看订单支付状态方法:前端支付页面,微信支付会每个几秒请求该接口,根据返回结果,判断是否跳转到订单支付成功页面
//查看订单支付状态
func (con BuyController) OrderPayStatus(c *gin.Context) {
id, err := models.Int(c.Query("id"))
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "传入参数错误",
})
return
}
//获取用户信息
user := models.User{}
models.Cookie.Get(c, "user", &user)
//获取主订单信息
order := models.Order{}
models.DB.Where("id = ?", id).Find(&order)
//判断当前数据是否合法
if user.Id != order.Uid {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "非法请求",
})
return
}
//判断是否支付
if order.PayStatus == 1 && order.OrderStatus == 1 {
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "支付成功",
})
return
} else {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "支付成功",
})
return
}
}
路由
把微信支付,支付宝支付相关路由写入routers/frontendRouters.go中
//查看订单支付状态
defaultRouters.GET("/buy/orderPayStatus", middlewares.InitUserAuthMiddleware, frontend.BuyController{}.OrderPayStatus)
//支付宝支付
defaultRouters.GET("/alipay", middlewares.InitUserAuthMiddleware, frontend.AlipayController{}.Alipay)
//支付宝支付回调
defaultRouters.POST("/alipayNotify", frontend.AlipayController{}.AlipayNotify)
//支付宝支付完成后跳转
defaultRouters.GET("/alipayReturn", middlewares.InitUserAuthMiddleware, frontend.AlipayController{}.AlipayReturn)
//微信支付
defaultRouters.GET("/wxpay", middlewares.InitUserAuthMiddleware, frontend.WxpayController{}.Wxpay)
//微信支付回调
defaultRouters.POST("/wxpay/notify", frontend.WxpayController{}.WxpayNotify)
html
微信,支付宝支付操作处理
{{ define "frontend/buy/pay.html" }}
{{ template "frontend/public/page_header.html" .}}
<!--end header -->
<link rel="stylesheet" href="/static/frontend/css/pay.css" />
<script src="/static/frontend/js/bootstrap.js"></script>
<link rel="stylesheet" href="/static/frontend/css/bootstrap.css">
<!-- start banner_x -->
<div class="banner_x center clearfix">
<a href="/" target="_blank">
<div class="logo fl"></div>
</a>
<div class="wdgwc fl ml40">支付页面 </div>
</div>
<div class="page-main">
<div class="checkout-box">
<div class="section section-order">
<div class="order-info clearfix">
<div class="fl">
<h2 class="title">订单提交成功!去付款咯~</h2>
<p class="order-time" id="J_deliverDesc"></p>
<p class="order-time">请在<span class="pay-time-tip">47小时59分</span>内完成支付, 超时后将取消订单</p>
<p class="post-info" id="J_postInfo">
收货信息: {{.order.Name}} {{.order.Phone}} {{.order.Address}} </p>
</div>
<div class="fr">
<p class="total">
应付总额:<span class="money"><em>1000元</em>元</span>
</p>
<br>
<br>
<a href="javascript:void(0);" class="show-detail" id="J_showDetail"
data-stat-id="db85b2885a2fdc53">订单详情</a>
</div>
</div>
<i class="iconfont icon-right">√</i>
<div class="order-detail">
<ul>
<li class="clearfix">
<div class="label">订单号:</div>
<div class="content">
<span class="order-num">{{.order.OrderId}}</span>
</div>
</li>
<li class="clearfix">
<div class="label">收货信息:</div>
<div class="content">
收货信息: {{.order.Name}} {{.order.Phone}} {{.order.Address}} </div>
</li>
<li class="clearfix">
<div class="label">商品:</div>
<div class="content">
{{range $key,$value:=.orderItems}}
<p>{{$value.ProductTitle}} {{$value.GoodsVersion}} {{$value.GoodsColor}}
数量:{{$value.ProductNum}} 价格:{{$value.ProductPrice}}</p>
{{end}}
</div>
</li>
<li class="clearfix hide">
<div class="label">配送时间:</div>
<div class="content">
不限送货时间 </div>
</li>
<li class="clearfix">
<div class="label">发票信息:</div>
<div class="content">
电子发票 个人 </div>
</li>
</ul>
</div>
</div>
<div class="section section-payment">
<div class="cash-title" id="J_cashTitle">
选择以下支付方式付款
</div>
<div class="payment-box ">
<div class="payment-body">
<ul class="clearfix payment-list J_paymentList J_linksign-customize">
<ul class="clearfix payment-list J_paymentList J_linksign-customize">
<li id="weixinPay">
<img src="/static/frontend/image/weixinpay0701.png" alt="微信支付" />
</li>
<li id="alipay">
<a href="/alipay?id={{.order.Id}}" target="_blank">
<img src="/static/frontend/image/payOnline_zfb.png" alt="支付宝" /></a>
</li>
</ul>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- 微信支付 Dialog -->
<div class="modal fade" id="weixinPayModel" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">微信支付</h4>
</div>
<div class="modal-body">
<img class="lcode" src="/wxpay?id={{.order.Id}}" />
<img class="rphone" src="/static/frontend/image/phone.png" />
</div>
</div>
</div>
</div>
<!-- 支付宝支付Dialog -->
<div class="modal fade" id="alipayModel" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">在线支付提醒</h4>
</div>
<div class="modal-body">
感谢您的支持,支付完成后,页面会自动跳转到订单页面,若需要重新支付请点击“继续支付”按钮,若已完成支付请点击“已完成支付”
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">继续支付</button>
<button type="button" class="btn btn-primary" id="alipayDone">已完成支付</button>
</div>
</div>
</div>
</div>
</div>
<script>
$(function () {
$(".show-detail").click(function () {
$(".order-detail").slideToggle();
})
$("#weixinPay").click(function () {
$('#weixinPayModel').modal('show');
})
$("#alipay").click(function () {
$('#alipayModel').modal('show');
})
$("#alipayDone").click(function () {
location.href = "/user/order"
})
//微信支付:弹出二维码模态框后,每个3秒定时定期支付状态,根据状态,判断逻辑
setInterval(function () {
$.get('/buy/orderPayStatus?id={{.order.Id}}', function (response) {
if (response.success) { //跳转到支付成功订单页面
location.href = '/user/order'
}
})
}, 3000);
})
</script>
<!-- footer -->
{{ template "frontend/public/page_footer.html" .}}
</body>
</html>
{{end}}
[上一节][golang gin框架] 33.Gin 商城项目- 微信支付操作相关功能讲解