One IT Thing

IT業界で飯を食う為の学習系雑記

android iOS java javascript 決済

Stripe+Java+Payment Request APIでApple Pay、Google Payを使ったテストWeb決済をしてみる

投稿日:2020年2月9日 更新日:

自分で作ったサービスを運用してチャリンチャリンしたい・・・
エンジニアならこんな夢、一度は見たことがあるんじゃないでしょうか。

夢を実現する為、以前Stripeのcheckout.jsを使ったテストWeb決済をしてみました。

この時こんな課題を挙げました。

  • FORM送信だとページ遷移してしまったりトークン取得とサーバへの決済依頼が同時に発生して使いづらいのでJSON送信するAjax送信にしたい。
  • サーバ側もそれに合わせてJSON受信するRESTにしたい。
  • 課金画面はW3C標準APIのPayment Request APIにしたい。
  • Google Pay、Apple Payを使ってクレジットカード選択を楽にしたい。

今回はこれらの課題を解決出来るか検証して行きたいと思います。

前提準備

サンドボックステスターを作っておく

Apple Payでテスト課金する為にサンドボックステスターを作り、テスターのApple IDでiPhoneにログインしておきます。

Appleにドメイン登録をしておく(Stripeを使えば例外も有り)

Apple Payは基本的に(次項参照)登録したドメインでしか課金確認画面を出してくれません。事前にApple Develper Programで設定をしておきます。

要HTTPS環境

W3C標準の課金APIであるPayment Request APIはlocalhostならHTTPでも動作してくれます。しかしApple Payは登録したドメインでかつHTTPSでないと動きません。

この為、インターネット外部からアクセスが可能なHTTPSサーバを開発環境にする必要があり、私の場合は自宅に以下のような環境を構築して検証しました。

検証するだけでここまでする必要あるのか・・・って話ですが、有難いことにstripe側で救済策を用意してくれていて、Appleにドメイン登録しなくても開発は出来るようになっています。 (以下サイトの「Verify your domain with Apple Pay」の項参照)

Appleに登録した単一のドメインでしか動作確認が出来ない、といった状況は免れられるので、制約の厳しい職場などでは試してみる価値があると思います。

実装開始

冒頭のcheckout.jsを使ったStripe決済記事で作成したSpringBootプロジェクトを使って実装していきます。

フロントエンドHTML、JSの実装

/src/main/resource/static/stripe-pra.htmlを作成して以下を記述。Stripeサーバから課金トークンを貰い、fetchでサーバに課金トークンを含んだJSONを送信。

W3C標準課金APIのPayment Request APIをStripe経由で使うには、

  • https://js.stripe.com/v3/をロード。
  • new PaymentRequest()の替わりにstripe.paymentRequest()を使用。

概ねこれだけで各ブラウザでのPayment Request画面表示、カード番号をstripeへ送信、課金トークンの受領までやってくれます。便利。

<html>
<head>
<script src="https://js.stripe.com/v3/"></script>
</head>

<body>
    <div id="payment-request-button">
        <!-- Payment Request APIのボタンが配置される場所 -->
    </div>

    <script>
        // Apple Payが使えるようになっているか一応チェック
        if (window.ApplePaySession) {
            console.log("window.ApplePaySession", window.ApplePaySession);
            console.log("ApplePaySession.canMakePayments()", ApplePaySession.canMakePayments());
            console.log("window.PaymentRequest", window.PaymentRequest);
            console.log("ApplePaySession.canMakePaymentsWithActiveCard()",
                    ApplePaySession.canMakePaymentsWithActiveCard('pirhana.dix.asia'));
        }

        // 自分のStripeのパブリックキーを使用
        var stripe = Stripe('pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');

        // Stripe API経由でPaymentRequestオブジェクト生成、ボタンを配置
        var paymentRequest = stripe.paymentRequest({
            country : 'JP',
            currency : 'jpy',
            total : {
                label : 'Tシャツ',
                amount : 500,
            },
            requestPayerName : false,
            requestPayerEmail : false,
            requestPayerPhone: false,
            requestShipping : false
        });
        var elements = stripe.elements();
        var prButton = elements.create('paymentRequestButton', {
            paymentRequest : paymentRequest,
        });

        // Stripe経由でPayment Request APIが使えるかチェック
        paymentRequest
            .canMakePayment()
            .then(function(result) {
                    // Payment Request API使用可能
                    if (result) {
                        // Payボタンを配置
                        prButton.mount('#payment-request-button');
                    } else {
                        document.getElementById('payment-request-button').style.display = 'none';
                    }
                });

        // 支払いボタンクリック後、stripeサーバからトークンを受信
        paymentRequest.on('token', function(ev) {
            let token = ev.token;

            // バックエンドJavaに送信するJSON
            let chargeRequest = {
                "stripeToken" : token.id,
                "stripeTokenType" : token.type,
                "stripeEmail" : token.email
            };

            // バックエンドJavaのRESTに課金トークンを送信
            // 「stripetest」パスで宅内PCのSpringBootにリバプロされるようにApacheを設定
            fetch('/stripetest/charge', {
                method : 'POST',
                body : JSON.stringify(chargeRequest),
                headers : {
                    'content-type' : 'application/json'
                },
            }).then(function(response) {
                if (response.ok) {
                    ev.complete('success');
                } else {
                    ev.complete('fail');
                }
            });
        });
    </script>
</body>
</html>

バックエンドJavaの実装

クライアントJSからはJSONでトークンを送信するようにしたので、JSONを受信出来るようにSpringMVCのアノテーションを変更しておきます。

package com.example.demo;

import java.util.HashMap;
import java.util.Map;

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.stripe.Stripe;
import com.stripe.exception.StripeException;
import com.stripe.model.Charge;

@Controller
public class DemoServer {

    @RequestMapping(path = "/charge", produces = "application/json", method = { RequestMethod.POST })
    public ResponseEntity charge(@RequestBody ChargeRequest request) {

        System.out.println("stripeToken = " + request.stripeToken);

        // 自分のStripeシークレットキーを使用
        Stripe.apiKey = "sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

        // Stripeサーバに決済依頼する内容
        Map<String, Object> chargeMap = new HashMap<String, Object>();
        chargeMap.put("amount", 500);
        chargeMap.put("description", "Tシャツ");
        chargeMap.put("currency", "jpy");
        chargeMap.put("source", request.stripeToken);

        try {
            // 決済依頼
            Charge charge = Charge.create(chargeMap);
            System.out.println(charge);
        } catch (StripeException e) {
            e.printStackTrace();
        }

        ResponseEntity response = ResponseEntity.ok().build();
        return response;
    }
}

JSON受信する為のマッパーPOJO。

package com.example.demo;

public class ChargeRequest {
    public String stripeToken;
    public String stripeTokenType;
    public String stripeEmail;
}

Eclipse上でプロジェクトを右クリック → 実行 → SpringBootアプリケーションでHTTPサーバを起動して動作確認準備完了です。

動作確認

https://[Appleに登録したドメイン]/stripetest/stripe-pra.html

にiPhone(Safari)とAndroid(Chrome)でアクセスしてみます。

Apple Pay

サンドボックステスターでログイン、Walletにテストカードを登録したiPhone実機です。

PayボタンをクリックしてTouchIDで認証すると、正常に処理が終了しました。

Google Pay

Google Payはテスト課金なら、Googleにドメイン登録申請などが不要でした。
(本番環境で実際に使えるようにするには以下の手順に従って登録を行います)
https://developers.google.com/pay/api/web/overview

お支払いボタンをクリックすると、

「アプリを認識出来ません。続行する前に、信頼できるアプリかどうか確認してください。」

という画面が新規に表示されますが、「続行」をクリックすることで課金通信出来ます。

Stripeダッシュボード

stripe.comにアクセスして支払いを見てみると、Apple Pay、Google Payとも決済が成功していました。

テスト環境でここまで動作確認出来ていれば本番切り替えも後少しですね。何より決済を実装する為のコーディング環境が手に入ったのが収穫です。

まとめ

Stripeを使うとiPhone、Androidでも同一コードでWeb上の課金処理を実装することが出来ました。

決済代行料3.6%は掛かるけど、PCI-DSS準拠の厳しと比較すれば魅力的な割合と判断出来るのではないでしょうか。

スマホを財布替わりに使って決済する機会が増える中、ニーズのあるサービスを作ることが出来ればチャリンチャリンも夢ではありませんね。

-android, iOS, java, javascript, 決済
-, ,

執筆者:

関連記事

Doxygenでspring-frameworkをドキュメント化

以前にspring-frameworkのソースリーディングが出来る環境をOpenGrokで作りました。 One IT ThingOpenGrokをインストールしてソースリーディング環境を作る …

JUnitコードの自動生成も出来る古の神Eclipseプラグイン「CodeProAnalytix」は今でも使える

デスマーチPM「各社のPG進捗が遅れていてユニットテストを書く暇が全く無いんですよ、なにかいい手は有りませんかね・・・? 因みに本プロジェクトはカバレッジ100%で請け負っています!(キリッ)」 何故 …

JavaコアAPI数の遷移をChart.jsでグラフ化

Javaはデフォルトで多数のAPIクラスを持っていてコーディングを楽にしてくれます。その数は増え続けているんでしょうか。 バージョンが上がるごとにどう変化しているか調べてchart.jsでグラフ化しま …

Android版ChromiumをVirtualBoxにインストールしたUbuntuでビルドしてみる

「Chromium」はChromeの開発ソースが公開されたプロジェクトです。  www.chromium.org  1 userGet the Code: Checkou …

Apple PayのWeb決済を開発する為にSandboxテスターを作ってiPhoneに設定

Web上でApple Pay支払いが出来るサービスが増えていますね。 決済にApple Payが使えるシステムにしておけば、PayPalよりもエンゲージ率は高くなるはずです。 自分が開発しているWeb …

 

shingo.7k24
 

東京在勤、職歴20年越え中年ITエンジニアです。まだ開発現場で頑張っています。

19歳(1996年)から書き始めた個人日記が5,000日を超え、残りの人生は発信をして行きたいと思い、令和元日からこのサイトを開始しました。勉強と試行錯誤をしながら、自分が経験したIT関連情報を投稿しています。

私と同じく、今後IT業界で生計を立てて行きたいと考えている方や、技術共有したいけどフリーランスで孤独、といった方と一緒に成長、知識共有して行けたら楽しいな、と思っています。