Golang を使用して Web アプリケーションに WeChat 支払いを実装する方法

PHPz
リリース: 2023-06-24 09:12:05
オリジナル
2676 人が閲覧しました

WeChat Pay は非常に一般的なオンライン支払い方法であり、多くの Web サイト/アプリケーションはこの機能を統合する必要があります。この記事では、Golangを使ってWeChatの決済機能を実装する方法を紹介します。この記事では、Gin フレームワークを使用して単純な Web アプリケーションを構築し、go-wechat WeChat SDK を使用して WeChat 支払いを迅速に実装します。

要件

このチュートリアルでは、単純な電子商取引 Web サイトを構築します。 Web サイトには次の機能を実装する必要があります。

  1. ユーザーは WeChat を通じて Web サイトにログインします。
  2. ユーザーはアイテムを参照し、ショッピング カートにアイテムを追加します。
  3. ユーザーは WeChat 支払いを使用して商品を購入できます。

準備

開始する前に、次の要件を満たしていることを確認してください:

  • WeChat 支払いアカウントを登録し、appid を持っていることmch_idkey およびその他のパラメーター。
  • Golang および Gin フレームワークがインストールされています。

go-wechat SDK のインストール

次に進む前に、go-wechat の Github リポジトリから WeChat SDK をインストールしてください。

go get github.com/silenceper/wechat/v2
ログイン後にコピー

環境変数の構成

WeChat 支払いアカウントから次のパラメーターを取得し、システム環境変数に追加します:

  • APP_ID : WeChat APP_ID
  • MCH_ID: マーチャント ID
  • API_KEY: マーチャント API キー
export APP_ID=your_appid
export MCH_ID=your_mchid
export API_KEY=your_api_key
ログイン後にコピー

ビルド アプリケーション

Gin の初期化

ファイル main.go で、gin パッケージを使用してアプリケーションを初期化します。

package main

import (
    "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")
}
ログイン後にコピー

WeChat ログインをアプリケーションに追加する

前のページで、基本的な Jin アプリケーションをセットアップしました。ここで、WeChat ログイン機能を追加します。

  1. 構成ファイルの追加

JSON、YAML、または TOML 形式で構成を定義することを選択できます。ここでは、構成を定義するための config.json ファイルを作成します。

{
    "wechat": {
        "appid": "your_appid",
        "secret": "your_app_secret"
    }
}
ログイン後にコピー
  1. 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 を定義します。また、リダイレクト URL を設定し、WeChatClientoauth2 リクエストを使用してアクセス トークンを取得する Jin ハンドラーも定義します。

  1. WeChat 承認の処理

ユーザーが自分のアカウントでアプリケーションを実行することを承認すると、リダイレクト URL で /wechat/callback# が呼び出されます。 # ハンドラー。このハンドラーは、ユーザーの WeChat 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, "/")
}
ログイン後にコピー

    WeChat ログインの統合
WeChat ログインをアプリケーションに統合する必要があります。プロセスは比較的簡単です。ハンドラーを Jin ルーターに追加するだけです。

func main() {
    ...
    router.GET("/wechat/login", weChatLoginHandler)
    router.GET("/wechat/callback", callbackHandler)
    ...
}
ログイン後にコピー

ショッピング カートの実装

基本的なショッピング カートの状態をアプリケーションに追加します。ユーザーセッションにショッピングカート情報を追加するだけです。

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,数量 int)Remove(productID int)Total() float64# を含む関数を実装しました。 ##カート構造体のいくつかのメソッド。セッション (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>
ログイン後にコピー

WeChat 支払い

WeChat 支払いを実装するには、注文構造を定義し、注文して WeChat 支払いに送信し、支払い通知を処理します。以下は簡単な実装です。

注文構造を定義します
  1. type Order struct {
        OrderNumber string
        Amount      float64
    }
    ログイン後にコピー
注文を生成し、WeChat に送信します
  1. このステップでは、注文を生成し、WeChat 支払いを通じて注文番号を作成します。詳細については、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
}
ログイン後にコピー

WeChat 支払い通知の処理
  1. WeChat がユーザーの支払いを受け取ったことを通知した後、コールバックで、後のクエリのために注文ステータスを保存します。
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.
            }
        }
    }()
}
ログイン後にコピー

クエリ関数を呼び出して、WeChat が注文ステータスを強制的に変更するトランザクションを確認する必要があります。 WeChat SDK は次のいずれかのステータスを返します。

TradeStateSuccess: ユーザーの支払いは成功しました。
  • TradeStateClosed: 注文はクローズされました。
  • TradeStateRefund: 取引は返金されました。
  • 概要

この記事では、Golang と Jin フレームワークを使用して e コマース Web サイトを構築する方法と、go-wechat SDK を使用して WeChat ログインと支払いを迅速に実装する方法を学びました。関数。 WeChatClient を通じてユーザーの認証と認可を処理する方法と、WeChat ユーザー データをユーザーのセッションに保存する方法を学びました。また、簡単なショッピング カートと注文を定義し、go-wechat SDK を使用して WeChat Pay と統合する方法も学びました。

以上がGolang を使用して Web アプリケーションに WeChat 支払いを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート