One IT Thing

IT業界を楽しむ為の学習系雑記

java javascript 決済

StripeとJavaで単発Web決済を一通り流してみる

投稿日:2019年10月27日 更新日:

会社仕事でも個人ビジネスでも、商品やサービスの対価として利用者に課金方法を提供したい時があるかと思います。

最もメジャーな決済方法であるクレジットカードで課金してもらう仕組みを導入したいところですが、開発システム側でクレジットカード番号を保持したり、通過させたりしてしまうと「PCI-DSS」という高難度のセキュリティ基準に従う必要が出てきます。

PCI-DSSに準拠するには堅牢なシステム構築の他、サーバ配置施設への入退館を記録、サーバルームへの入退室を記録、監視カメラの設置、他様々な要件をクリアしないと認可が下りません。

人様のカード番号を預かる訳ですから当然と言えば当然ですが、コストが掛かり過ぎて中小や個人レベルでは実現が難しいですよね。

こんな時に助け船になってくれるのが自分達の開発システムの替わりにクレジット決済をしてくれる「決済代行サービス」です。

PayPal、SPIKE、Pay.jpなど数ある決済代行サービスの中、今回はデファクトスタンダードになりつつある「Stripe」で決済までの流れを実装していきたいと思います。

Stripeとは

  • 単発課金やサブスクリプションが可能。
  • 決済手数料3.6%。
  • アプリに組み込みやすい(決済画面に遷移しなくてよい、Payment Request APIと連携可)
  • 様々な言語のライブラリが用意されている。
  • 公式ドキュメントが豊富。

手っ取り早くスマホ、PCブラウザで動作を見たい場合は以下のデモが便利です。

上記デモ開き、ブラウザのデベロッパーツールでHTMLエレメントを確認すると、カード番号入力欄はstripeサーバから提供されるHTMLソースをiframeで読み込んでいて、こちらが開発するHTMLソースとは分離されていることが確認できます。フロントエンド側でも非保持が出来ていそうです。

検証構成

色んな構成形態をとることが出来るStripeですが今回はこんな感じで単純な実装をしてみます。

カード番号に対する「トークン」を発行してもらうことでPCI-DSS準拠を回避します。開発するシステムではユーザの選択したカード番号を知ることは出来ません。

商品が渡せなかった場合は決済をしないような処理も出来るので、GooglePlayやAppStoreのアプリ内課金より柔軟でいいですね。

検証環境

  • Windows 10
  • Eclipse 2019-03
  • Java8

localhostで動作確認する分にはHTTP環境でOKです。スマホなど外部ホストから接続する時はHTTPS環境が必要になります。

HTTPS環境がない場合はngrokで代替すればOKです。

シンプルに実装して決済まで確認してみる

Stripeのクレジットカード入力画面をJavascriptで表示する場合、主に3つの方法があります。

  1. クレジット入力画面をカスタマイズ出来るStripe Element
  2. 出来合いのダイアログを表示出来るcheckout.js
  3. W3C標準のPayment Request APIと連携するPayment Request Button

今回は決済完了までの動作確認をするだけなので、最も簡単な2で決済までやってみます。

実戦に導入するなら、以前ブラウザに入力したことがあるカードが候補に出る3にするか、ダイアログではなくページに溶け込ませることが出来る1も検討に入れます。

1.stripe.comでアカウントを作る

stripe.comで「今すぐ始める」ボタンをクリックするとアカウントが作れます。テスト環境を使うだけなら数分で終わります。このあたりの簡単さもStripeのシェア拡大に一役買ってそうですね。

ログインしてダッシュボードに入り、「テストAPIキー」の公開可能キーとシークレットキーを確認しておきます。後でプログラムから指定する為です。

2.SpringBootプロジェクトを作成

フロントエンドのHTML、バックエンドHTTPサーバを作る為のプロジェクトをSpringBootで適当に作っておきます。(作成したことがなければ以下参照)

3.フロントエンドHTMLを作成

公式ドキュメントを参考にしながら実装していきます。

/src/main/resource/static/stripe-checkout.htmlを作成して以下を記述します。data-keyには先程作ったアカウントの「公開可能キー」を指定します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Stripe checkout.jsの動作確認</title>
</head>
<body>
<form action="/pay" method="POST">
  <script
    src="https://checkout.stripe.com/checkout.js"
    class="stripe-button"
    data-key="pk_test_xxxxxxxxxxxxxxxxxxxxxxxxx"
    data-name="Tシャツ"
    data-description="コットンTシャツ"
    data-amount="500"
    data-currency="jpy">
  </script>
</form>
</body>
</html>

http://localhost:8080/stripe-checkout.htmlにアクセスするとカード番号入力ダイアログが表示されます。「TEST MODE」ボタンを押してテスト用ダミーカード番号を確認、指定してみましょう。

ただこの状態でPayボタンをクリックしても、formアクションのPOST先「/pay」が無いのでエラーになってしまいます。Javaでサーバ側を実装していきましょう。

4.バックエンドJavaを実装

mvnrepositoryで「stripe-java」の最新バージョンを探してpom.xmlに依存を追加します。

このjarを使うとStripeサーバに対して決済依頼やトークンのチェックをリクエストすることが出来るようになります。

		<dependency>
		    <groupId>com.stripe</groupId>
		    <artifactId>stripe-java</artifactId>
		    <version>14.3.0</version>
		</dependency>

Spring MVCで/payを実装します。Stripe.apiKeyにはご自分のアカウントの「シークレットキー」を指定してください。

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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

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

@Controller
public class DemoServer {

	@RequestMapping(path = "/pay", method = { RequestMethod.POST })
    public ResponseEntity charge(
            @RequestParam("stripeToken") String stripeToken,
            @RequestParam("stripeTokenType") String stripeTokenType,
            @RequestParam("stripeEmail") String stripeEmail)
    {

        Stripe.apiKey = "sk_test_xxxxxxxxxxxxxxxxxxxxxxxx";

        Map<String, Object> chargeMap = new HashMap<String, Object>();
        chargeMap.put("amount", 500);
        chargeMap.put("description", "コットンTシャツ");
        chargeMap.put("currency", "jpy");
        chargeMap.put("source", stripeToken);

        try {
            Charge charge = Charge.create(chargeMap);
            System.out.println(charge);
        } catch (StripeException e) {
            e.printStackTrace();
        }

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

        return response;
    }

実装完了です。

動作確認

再度 http://localhost:8080/stripe-checkout.html にアクセスしてPayボタンをクリックしてみると今度は正常に終了し、EclipseのコンソールにはStripeサーバから決済が完了した旨のJSONが返却されているはずです。

<com.stripe.model.Charge@1751915628 id=ch_1FYCH3HZxxxxxxxxxxyY1NS> JSON: {
  "alternate_statement_descriptors": null,
  "amount": 500,
  "amount_refunded": 0,
  "application": null,
  "application_fee": null,
  "application_fee_amount": null,

(snip)

ブラウザでStripeのダッシュボードを開いて決済が完了しているか見てみましょう。左メニュー「残高」→「取引」で確認できます。

決済されていました。手数料3.6%なので500円の内18円がStripeに渡っていますね。
(テスト環境なので実際に入金はされていません)

Stripeダッシュボードで決済が完了していることが確認できました。

まとめと課題

テスト環境とはいえ少ない労力でクレジットカード課金を実装することが出来ました。

本番に移行する際はサイトURLの登録や審査を通し、発行された本番APIキーに切り替えるだけです。ほんとにシンプルで便利ですね。

ただ今回の動作確認は最も簡単な実装なので色々課題や要望が残ります。

  • FORM送信だとページ遷移してしまったりトークン取得とサーバへの決済依頼が同時に発生して使いづらいのでAjax送信にしたい。
  • サーバ側もそれに合わせてJSON受信するRESTにしたい。
  • トークン取得と課金依頼リクエストが分かれると不正トークンが送られてくるかも知れないので抑止したい。
  • 課金ダイアログはW3C標準APIのPayment Request APIにしたい。

次回はこれらをやってみたいと思います。

-java, javascript, 決済
-

執筆者:

関連記事

プロパティ値変更を監視できるJavaScript、TypeScriptオブジェクトを作る

let taro= new Person(“yamada taro”, 25, “teacher”);taro.age = 26; こんなコードが有った …

Maven環境別ビルド時、プロファイルの違いでdependencyを変える

MavenのResourceFilteringを使い、production、staging、developmentとかで環境別ビルドしている時、ある環境ビルドの時だけ特定のライブラリを追加する、をmv …

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

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

Maven依存ライブラリのライセンスサマリを出す

Mavenで依存しているライブラリのライセンス累計を作成します。下記のように「ライセンス名 ライブラリ個数」の行がライセンス種別数分作られるイメージ。 BSD 4ASL2 43MIT 5 開発中のクロ …

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

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


shingo nakanishi。東京で消耗中の職歴20年越え中年ITエンジニアです。「生涯現役プログラマを楽しむ」ことができる働き方探しをライフワークにしています。

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