微信支付是一种非常普遍的在线支付方式,许多网站/应用都需要集成这个功能。本文将介绍如何使用 golang 实现微信支付功能。在本文中,我们将使用 gin 框架来构建一个简单的 web 应用程序,并使用 go-wechat 微信 sdk 来快速实现微信支付。
需求在本教程中,我们将构建一个简单的电商网站。该网站需要实现以下功能:
用户通过微信登录网站。用户浏览商品并将商品添加到购物车。用户可以使用微信支付购买商品。准备工作在开始之前,请确保您有以下要求:
已经注册了微信支付账号, 拥有 appid、mch_id、key 等参数。安装了 golang 和 gin 框架。安装 go-wechat sdk在继续之前,请从 go-wechat 的 github 存储库中安装微信 sdk。
go get github.com/silenceper/wechat/v2
配置环境变量从微信支付账户中获得以下参数并将其添加到系统环境变量中:
app_id : 微信 app_idmch_id: 商户号api_key: 商户 api 密钥export app_id=your_appidexport mch_id=your_mchidexport api_key=your_api_key
构建应用程序初始化 gin在文件 main.go 中,我们将使用 gin 包来初始化应用程序。
package mainimport ( "net/http" "github.com/gin-gonic/gin")func main() { router := gin.default() router.get("/", func(c *gin.context) { c.string(http.statusok, "hello world!") }) router.run(":8080")}
将微信登录添加到应用程序中在上一页中,我们设置了基本的 gin 应用程序。我们现在将添加微信登录功能。
添加配置文件您可以选择通过 json 、yaml 或 toml 格式定义配置。这里,我们将 创建一个 config.json 文件来定义配置。
{ "wechat": { "appid": "your_appid", "secret": "your_app_secret" }}
初始化 wechat下一步是初始化 wechatclient 并使用 oauth2 请求代码来获取访问令牌。
import ( "encoding/json" "io/ioutil" "net/http" "os" "github.com/silenceper/wechat/v2")func loadconfig() map[string]string { file, err := os.open("config.json") if err != nil { panic("failed to load config file.") } defer file.close() data, err := ioutil.readall(file) if err != nil { panic("failed to read config file.") } var config map[string]map[string]string err = json.unmarshal(data, &config) if err != nil { panic("failed to parse config file.") } return config["wechat"]}func initializewechat() *wechat.wechat { config := loadconfig() client := wechat.newwechat(&wechat.config{ appid: config["appid"], appsecret: config["secret"], token: "", encodingaeskey: "", }) return client}func wechatloginhandler(c *gin.context) { client := initializewechat() redirecturl := "<your_redirect_url>" url := client.oauth2.getredirecturl(redirecturl, "snsapi_userinfo", "") c.redirect(http.statustemporaryredirect, url)}
从本质上讲,我们定义了一个包含应用程序的身份验证的 wechatclient。我们还定义了一个 gin 处理程序,该处理程序设置了重定向 url 并使用 wechatclient 中的 oauth2 请求获取访问令牌。
处理微信授权在重定向 url 中,用户授权我们的应用程序在其账户下运行时,将调用 /wechat/callback 处理程序。该处理程序将用户的微信 id、昵称和其他公开数据存储在用户会话中。
func callbackhandler(c *gin.context) { code := c.request.url.query().get("code") client := initializewechat() accesstoken, err := client.oauth2.getuseraccesstoken(code) if err != nil { panic("failed to get access token from wechat.") } userinfo, err := client.oauth2.getuserinfo(accesstoken.accesstoken, accesstoken.openid) if err != nil { panic("failed to get user info from wechat.") } session := sessions.default(c) session.set("wechat_openid", userinfo.openid) session.set("wechat_nickname", userinfo.nickname) session.save() c.redirect(http.statustemporaryredirect, "/")}
集成微信登录我们应该将微信登录集成到我们的应用程序中。这个过程相对简单。仅需将处理程序添加到 gin 路由器即可。
func main() { ... router.get("/wechat/login", wechatloginhandler) router.get("/wechat/callback", callbackhandler) ...}
实现购物车我们将为应用程序添加 basic 的购物车状态。只需在用户会话中添加购物车信息即可。
type cartitem struct { productid int quantity int}func (c *cartitem) subtotal() float64 { // todo: implement.}type cart struct { contents []*cartitem}func (c *cart) add(productid, quantity int) { item := &cartitem{ productid: productid, quantity: quantity, } found := false for _, existingitem := range c.contents { if existingitem.productid == productid { existingitem.quantity += quantity found = true break } } if !found { c.contents = append(c.contents, item) }}func (c *cart) remove(productid int) { for i, item := range c.contents { if item.productid == productid { c.contents = append(c.contents[:i], c.contents[i+1:]...) break } }}func (c *cart) total() float64 { total := 0.0 for _, item := range c.contents { total += item.subtotal() } return total}func cartfromsession(session sessions.session) *cart { value := session.get("cart") if value == nil { return &cart{} } cartbytes := []byte(value.(string)) var cart cart json.unmarshal(cartbytes, &cart) return &cart}func synccarttosession(session sessions.session, cart *cart) { cartbytes, err := json.marshal(cart) if err != nil { panic("failed to sync cart with session data store.") } session.set("cart", string(cartbytes)) session.save()}
如上所示,我们实现了一个包含 add(productid, quantity int),remove(productid int), total() float64几个方法的 cart struct。我们从会话中存储和加载 cart 数据 (cartfromsession() 和 synccarttosession()),并通过 cartitem.subtotal() 方法计算项目的小计。
在页面底部展示购物车状态:
<footer> <div class="container"> <div class="row"> <div class="col-sm-4"> <a href="/">back to home</a> </div> <div class="col-sm-4"> <p id="cart-count"></p> </div> <div class="col-sm-4"> <p id="cart-total"></p> </div> </div> </div></footer><script> document.getelementbyid("cart-count").innertext = "{{.cartitemcount}} items in cart"; document.getelementbyid("cart-total").innertext = "total: ${{.carttotal}}";</script>
微信支付为了实现微信支付,我们需要定义一个订单 struct、生成订单并将其发送给微信支付、处理支付通知。以下是一个简单的实现。
定义订单 structtype order struct { ordernumber string amount float64}
生成订单并向微信发送订单在此步骤中,我们将生成订单并通过微信支付创建订单号。阅读 go-wechat 的支付文档以了解有关更多信息。
func generateouttradeno() string { // todo: implement.}func createorder(cart *cart) *order { order := &order{ ordernumber: generateouttradeno(), amount: cart.total(), } client := initializewechat() payment := &wechat.payment{ appid: app_id, mchid: mch_id, notifyurl: "<your_notify_url>", tradetype: "jsapi", body: "购物车结算", outtradeno: order.ordernumber, totalfee: int(order.amount * 100), spbillcreateip: "127.0.0.1", openid: "<user_wechat_openid>", key: api_key, } result, err := client.pay.submitpayment(payment) if err != nil { panic("failed to submit payment.") } // save order state and return it. return order}
处理微信的支付通知在微信通知我们已经收到用户的支付后,在回调中,我们将存储订单状态,供以后查询。
func setupcheckorderstatus() { go func() { for { // wait 10 seconds before checking (or less if you want to check more frequently). time.sleep(10 * time.second) client := initializewechat() // todo: retrieve orders that need to be checked. for _, order := range orderstocheck { queryorderresult, err := client.pay.queryorder(&wechat.queryorderparams{ outtradeno: order.ordernumber, }) if err != nil { panic("failed to query order.") } switch queryorderresult.tradestate { case wechat.tradestatesuccess: // handle order payment in your app. order.paid = true // todo: update order state in database. case wechat.tradestateclosed: // handle order payment in your app. order.paid = false // todo: update order state in database. case wechat.tradestaterefund: // handle order payment in your app. order.paid = false // todo: update order state in database. default: break } // todo: remove checked order from cache. } } }()}
我们需要调用查询功能以检查微信强制更改订单状态的交易。微信 sdk 会返回以下状态之一。
tradestatesuccess:用户付款成功。tradestateclosed:已关闭订单。tradestaterefund:交易已退款。总结在这篇文章中,我们学习了如何使用 golang 和 gin 框架来构建一个电商网站,并使用 go-wechat sdk 快速实现了微信登录和支付功能。我们了解到如何通过 wechatclient 处理用户的认证和授权,并如何将微信用户数据存储在用户的会话中。我们还学习了如何定义一个简单的购物车和订单,并使用 go-wechat sdk 与微信支付集成。
以上就是如何使用golang实现web应用程序的微信支付的详细内容。