Stripe 国外银行卡支付功能指南(Java)

简介

编写这篇文章的目的就是~~没有什么目的。网上关于stripe银行卡支付代码很多,有写得很好的,但是太多太杂了,不系统。所以我就结合项目中实际应用,总结了一些比较常用的方法,希望能给予各位一些帮助。
        当然我的这个指南也不是很完全,以后如果有机会还会继续补充。

Stripe支付步骤

开通stripe账号

这是最最重要的一步,没有账号后面的内容就不用看啦~~

账号开通之后就是要获得密钥了,stripe密钥分为线上环境密钥和测试环境密钥,我们因为只是做测试就申请测试密钥即可,下面所有讨论的东西都是以测试环境为主

密钥有两种:
可发布密钥(pk_test):前端实现stripe接口时用
密钥(sk_test):后端实现stripe方法时用

因为是测试并且所有的支付都是我后台这边操作的,我这边只需要用sk_test的即可,线上环境同理

至此所有准备工作都已经准备好了,我们开始实现银行卡支付功能。

Stripe Api 核心功能

下面是官方文档提供的一些资料,因为官方文档是纯英文版,找的比较麻烦,就把一些使用的文档记录下

StripeApi文档
Stripe接口返回错误码文档
Stripe测试银行卡号

测试账号不想看上面文档的可以用下面这个即可
通用付款成功 4242 4242 4242 4242

stripe支付核心功能很多,包括但不限于Token、Card、Customers、PaymentIntent、PaymentMethod、Source、Charge

我这边因为业务逻辑并不那么广泛,并没有全部涉及到,所有下面只解释我所用到的核心功能

Customers

顾名思义customber就是用户,凡是需要使用银行卡支付的用户都需要在stripe上创建自己的独立账户,并且最好是需要与你业务上的用户保持唯一,当然这是根据实际情况来的,你不唯一也是可以的,如果你想这么做的话。

创建Customers

Stripe.apiKey =  your key;//创建客户时的参数,方便后面识别,具体参数详见api,这里的话推荐description参数必传,这里的值会展示在stripe平台上方便后面观察
Map<String, Object> params = new HashMap<>();
params.put("description","My First Test Customer (created for API docs)"
);Customer customer = Customer.create(params);
//stripe平台Customers的唯一标识
String customerId = customer.getId();

Tokens

Token是Stripe用来客户收集敏感卡或者银行账户信息的过程,当用户填写了银行卡的卡号、过期年月、CVC等信息后,Stripe会生成过一个包含这些信息的Token,这样在传输过程中,确保没有敏感的卡数据和我们自己的服务器交互,降低客户真实信息丢失率。我们自身的服务器,取到token,进行支付即可 。

Token不能多次存储和使用,要存储卡的信息供以后使用,可以创建用户。将卡的信息添加给用户。

创建银行卡号相关Token

Stripe.apiKey =  your key;Map<String, Object> card = new HashMap<>();
card.put("number", "4242424242424242");
card.put("exp_month", 2);
card.put("exp_year", 2022);
card.put("cvc", "314");
Map<String, Object> params = new HashMap<>();
params.put("card", card);Token token = Token.create(params);
//在后面创建银行卡时可以使用,传参过程无需再填写银行卡相关信息
String tokenId = token.getId();

Cards

可以在一个客户上存储多张卡,向该客户收费。您还可以在收件人上存储多个借记卡,以便以后转移到这些借记卡上。

创建Card并与Customers绑定

Customers初次绑定Card时,如果绑定成功,此Card将成为支付时的默认Card。

Stripe.apiKey =  your key;Map<String, Object> retrieveParams = new HashMap<>();
List<String> expandList = new ArrayList<>();
expandList.add("sources");
retrieveParams.put("expand", expandList);
Customer customer =Customer.retrieve("Customers对应id",retrieveParams,null);Map<String, Object> params = new HashMap<>();
params.put("source", "银行卡的tokenId");Card card =(Card) customer.getSources().create(params);
//建议将卡号保存下来
String cardId = card.getId();

修改Customers的支付默认Card

如果Customers有多张Card,需要更改支付时的默认卡片。

Stripe.apiKey =  your key;Map<String, Object> retrieveParams = new HashMap<>();
List<String> expandList = new ArrayList<>();
expandList.add("sources");
retrieveParams.put("expand", expandList);
Customer customer = Customer.retrieve("Customers对应id", retrieveParams,null);Map<String, Object> params = new HashMap<>();
params.put("default_source", "需要设置为默认Card的Id");
customer.update(params);

修改Card

修改Card只允许修改一下参数,如果多写了其他参数方法会报错

Stripe.apiKey =  your key;Map<String, Object> retrieveParams =new HashMap<>();
List<String> expandList = new ArrayList<>();
expandList.add("sources");
retrieveParams.put("expand", expandList);
Customer customer =Customer.retrieve("Customers对应id",retrieveParams,null);Card card =customer.getSources().retrieve("需要修改Card的Id");//修改参数
Map<String, Object> params = new HashMap<>();
params.put("name", "Jenny Rosen");Card updatedCard = (Card) card.update(params);

删除Card

如果删除的是默认Card,系统会默认按时间顺序寻找到上一次最后添加的卡片并设置为默认Card。

Stripe.apiKey =  your key;Map<String, Object> retrieveParams =new HashMap<>();
List<String> expandList = new ArrayList<>();
expandList.add("sources");
retrieveParams.put("expand", expandList);
Customer customer =Customer.retrieve("Customers对应id",retrieveParams,null);Card card =customer.getSources().retrieve("需要删除Card的Id");Card deletedCard = (Card) card.delete();

Charges

要收取信用卡或借记卡的费用,请创建一个Charge对象。您可以检索并退还单个费用以及列出所有费用。费用由唯一的随机ID标识。

PS:stripe的支付有很多种方式,直接从默认卡扣费,或者回调监听扣费等等方式,我这边因为扣费操作都在后台,与前端没有交互,所以就直接用默认卡扣费的方式操作了

Map<String, Object> params = new HashMap<>();
//金额,实际金额*100,最小支付金额是0.5
params.put("amount", 2000);
//货币单位,小写,银行卡扣费货币换算stripe内部自行转换,我们不需要关心
params.put("currency", "aud");
params.put("customer", "Customers对应id");
params.put("description","My First Test Charge (created for API docs)"
);
//是否立即捕获费用。默认为true。如果为false,则费用会发出授权(或预授权),以后需要捕获。未捕获的费用将在7天内到期。
params.put("capture", true);Charge charge = Charge.create(params);
//可以实时获取支付状态
if ("succeeded".equals(charge.getStatus())) {//交易成功后,需要更新我们的订单表,修改业务参数,此处省略return true;} else {return false;}

Webhook Endpoints

通过API配置Webhook端点,以通知您的Stripe帐户或关联帐户中发生的事件。

自用Java工具类

本工具类只是根据实际业务做的操作,可能与各位支付场景不同,可以根据api文档理解进行改造,以下仅供参考。

<dependency><groupId>com.stripe</groupId><artifactId>stripe-java</artifactId><version>${stripe.version}</version>
</dependency>
/*** stripe 支付工具类** @author zhouquan* @date 2021-01-26 13:44:00*/
@Component
public class StripePayUtils {private static final String key = "your key";/*** 创建初始用户* @param description 描述-用户编号* @return* @throws StripeException*/public String createStripeCustomNoCard(String description) throws StripeException {Stripe.apiKey = key;Map<String, Object> params = new HashMap<>();params.put( "description", description);Customer customer = Customer.create(params);return customer.getId();}/*** 更新用户绑定银行卡* @param stripeMemberId 客户stripeId* @param cardParam 银行卡参数* @return* @throws StripeException*/public String updateStripeCustomWithCard(String stripeMemberId, Map<String, Object> cardParam) throws StripeException {Stripe.apiKey = key;//创建银行卡Token,顺便借用stripe内部验证校验银行卡信息是否正确String cardTokenId = createCardToken(cardParam);Map<String, Object> retrieveParams = new HashMap<>();List<String> expandList = new ArrayList<>();expandList.add("sources");retrieveParams.put("expand", expandList);Customer customer = Customer.retrieve(stripeMemberId, retrieveParams,null);Map<String, Object> params = new HashMap<>();params.put("source", cardTokenId);Card card = (Card) customer.getSources().create(params);return card.getId();}/*** 修改默认支付银行卡* @param stripeMemberId 客户stripeId* @param stripeCardId 银行卡stripeId* @throws StripeException*/public void updateStripeDefaultCard(String stripeMemberId, String stripeCardId) throws StripeException {Stripe.apiKey = key;Map<String, Object> retrieveParams = new HashMap<>();List<String> expandList = new ArrayList<>();expandList.add("sources");retrieveParams.put("expand", expandList);Customer customer = Customer.retrieve(stripeMemberId, retrieveParams,null);Map<String, Object> params = new HashMap<>();params.put("default_source", stripeCardId);customer.update(params);}/*** 删除用户绑定银行卡* @param stripeMemberId 客户stripeId* @param cardId 银行卡stripeId* @return* @throws StripeException*/public void deleteCard(String stripeMemberId, String cardId) throws StripeException {Stripe.apiKey = key;Map<String, Object> retrieveParams = new HashMap<>();List<String> expandList = new ArrayList<>();expandList.add("sources");retrieveParams.put("expand", expandList);Customer customer = Customer.retrieve( stripeMemberId, retrieveParams, null );Card card = (Card) customer.getSources().retrieve(cardId);Card deletedCard = (Card) card.delete();}/*** 生成卡token(鉴定卡对不对)* @param cardParam  number 卡号  exp_month 有效期月份 exp_year 有效期年份  cvc 安全码* @return* @throws StripeException*/public String createCardToken(Map<String, Object> cardParam) throws StripeException {Stripe.apiKey = key;//生成卡片tokenMap<String, Object> params = new HashMap<>();params.put("card", cardParam);Token token = Token.create(params);return token.getId();}/*** 修改银行卡信息* @param stripeMemberId 客户stripeId* @param stripeCardId 银行卡stripeId* @param params 需要修改的参数* @throws StripeException*/public void updateCard(String stripeMemberId, String stripeCardId,Map<String, Object> params) throws StripeException {Stripe.apiKey = key;Map<String, Object> retrieveParams = new HashMap<>();List<String> expandList = new ArrayList<>();expandList.add("sources");retrieveParams.put("expand", expandList);Customer customer = Customer.retrieve(stripeMemberId, retrieveParams,null);Card card =  (Card) customer.getSources().retrieve(stripeCardId);card.update(params);}/*** 同步支付* @param stripeMemberId 客户stripeId* @param money 实际支付金额* @param moneyType 货币单位* @param description 订单描述* @return* @throws StripeException*/public boolean charge(String stripeMemberId, BigDecimal money, String moneyType, String description) throws StripeException {Stripe.apiKey = key;//发起支付Map<String, Object> payParams = new HashMap<>();//1元=100payParams.put("amount", money.multiply(new BigDecimal(100)).longValue());payParams.put("currency", moneyType);payParams.put("description", description);payParams.put("customer", stripeMemberId);payParams.put("capture", true);Charge charge = Charge.create(payParams);System.err.println(charge.toString());//charge  支付是同步通知if ("succeeded".equals(charge.getStatus())) {//交易成功后,需要更新我们的订单表,修改业务参数,此处省略return true;} else {return false;}}/*** 捕获stripe平台返回的错误状态码* @param code*/public void catchError(String code){switch (code){case "account_number_invalid"://银行卡号不正确throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_account_number_invalid.getValue());case "balance_insufficient"://账户余额不足throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_balance_insufficient.getValue());case "bank_account_declined"://所提供的银行帐户尚未通过验证或不受支持,因此无法用于收费throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_bank_account_declined.getValue());case "bank_account_exists"://账户已存在throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_bank_account_exists.getValue());case "bank_account_unusable"://提供的银行帐户不能用于付款。必须使用其他银行帐户。throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_bank_account_unusable.getValue());case "expired_card"://卡已过期throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_expired_card.getValue());case "incorrect_cvc"://卡的安全码不正确throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_incorrect_cvc.getValue());case "incorrect_number"://卡号不正确throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_incorrect_number.getValue());case "incorrect_zip"://卡的邮政编码不正确throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_incorrect_zip.getValue());case "instant_payouts_unsupported"://此卡不支持即时付款throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_instant_payouts_unsupported.getValue());case "invalid_cvc"://卡的安全码无效throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_invalid_cvc.getValue());case "invalid_expiry_month"://卡的有效期限不正确throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_invalid_expiry_month.getValue());case "invalid_expiry_year"://卡的有效期不正确throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_invalid_expiry_year.getValue());case "invalid_number"://卡号无效throw new RRException(null, ErrorPromptEnum.BANK_STRIPE_invalid_number.getValue());default://系统异常throw new RRException(code, ErrorPromptEnum.BANK_STRIPE_error.getValue());}}
}

结尾

以上就是对stripeApi的一个初步探索,不是很全面,很多功能都没用到,要彻底摸透这个支付,任重而道远~~~

Stripe 银行卡支付功能初步指南(Java)相关推荐

  1. Stripe 银行卡支付(Java)

    Stripe 银行卡支付(Java) 一:概述 参考博客:https://blog.csdn.net/Sunshine_Moon/article/details/113867159?utm_mediu ...

  2. 微信扫码支付功能详细教程————Java

    前言  首先声明 我并非原创 原创是 http://blog.csdn.net/wangqiuyun/article/details/51241064 我只是在前辈的基础 加以解释说明 还有自己的一些 ...

  3. 如何快速对接Stripe国际支付系统

    Stripe国际支付介绍 Stripe是由20多岁的两兄弟Patrick Collison和John Collison创办的Stripe为公司提供网上支付的解决方案.Stripe向服务的公司收取每笔交 ...

  4. Java开发对接招行一网通支付功能的总结

    招商银行一网通支付JAVA开发 最近对接了招行一网通的支付功能,记录一下. 一.一网通支付方式主要分为6种:APP支付,H5支付,PC扫码支付,二维码支付,小程序支付,Apple Pay支付.本次开发 ...

  5. java 银行卡支付_Java学习:用接口简单实现银行卡系统

    用前面所知案例,简单实现一个银行卡系统.涉及的Java知识有: interface(接口),abstract(抽象修饰符),extends(继承),implements(接口的实现),@Overrid ...

  6. 非智能手机斗破苍穹Java_支付宝推JAVA版 非智能手机增支付功能

    泡泡网手机频道6月16日 日前,支付宝与曜硕科技联合发布国内首个非智能手机支付方案--嵌入式安全支付系统解决方案.通过该方案,非智能型手机将拥有手机支付功能,从而可以让用户的手机新增网购.游戏及话费充 ...

  7. 哈哈!没想到吧!Java也可以 实现微信和支付宝支付功能(附代码)

    一.前期准备 1.申请好微信商户号appid,拿到商户id和商户秘钥,退款的话需要商户证书 2.申请好支付宝商户号appid,商户公钥和秘钥(需要用支付宝工具自己生成),支付宝退款不需要证书 二.数据 ...

  8. java在线支付---01_在线支付功能的演示与概述

    2013/5/30 ----------------- 01_在线支付功能的演示与概述 Java技术qq交流群:JavaDream:251572072 ------------------------ ...

  9. 聊一聊Java如何接入招行一网通支付功能

    1.前提条件 相比较于支付宝和微信的支付功能接入这一块,银行相对来说更加严格,比如说支付宝,在你签约之前可以进行一些测试.但是银行来说就不是这样了,如果您现在要进行招行的支付功能开发的话,请务必先让相 ...

最新文章

  1. Adobe源码泄漏?3行代码搞定,Flash动画无缝导入Android/iOS/cocos2dx(二)
  2. switchyomega插件_CTF|你所关注的CTFer都在用的插件合集【附:XXE补给+CTF训练集】...
  3. mysql更新linux_MySQL更新语句UPDATE深入探索
  4. IntelliJ IDEA 的 project 和 module 区别与关系
  5. CSS 文字处理总结
  6. 外部排序---置换选择+败者树
  7. eclipse adt for linux,Eclipse IDE,ADT对于Android SDk错误
  8. Java基础学习总结(175)——分布式ID的9种生成方式总结
  9. matlab啁啾信号,啁啾信号chirp(扫频余弦信号)
  10. 手机最好的html5浏览器,哪款浏览器最好用:六款主流手机浏览器横评
  11. 那些想上天的亿万富翁,开启了新的“太空竞赛”
  12. MSU转Uniprot转Entrez ID
  13. vector容器操作导致访问vector subscript out of range
  14. Vulkan教程(官方教程翻译版)
  15. c语言第五章答案许合利,C语言习题答案贾宗璞许合利较全-.doc
  16. 展示正在活动时间内的活动,过期活动不显示
  17. MyHDL中文手册(十)——转换成Verilog和VHDL
  18. BurpSuite爆破(Intruder)模块四种模式介绍
  19. f2fs系列文章fsck(五)
  20. radis安装和使用

热门文章

  1. 文明与征服阵容搭配,文明与征服阵容推荐
  2. JQuery 判断浏览器及其版本
  3. WindwosAndroid浏览器内核版本检测
  4. QQ邮箱开通exchange的方法
  5. Java(SpringCloud) 使用Thymeleaf渲染模板,通过Mailgun发送邮件
  6. 项目目标的SMART原则
  7. 大数据案例--电信日志分析系统
  8. 对populate()方法的理解
  9. java zoneid 中国_关于时区:Java 8 Time API – ZonedDateTime – 在解析时指定默认的ZoneId...
  10. 求大神帮帮我,万分感谢,源码运行需要时间段,帮帮忙哈……