Stripe 银行卡支付功能初步指南(Java)

2024-02-20 22:58

本文主要是介绍Stripe 银行卡支付功能初步指南(Java),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/729800

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听