【支付】Stripe支付通道Java对接(产品 价格 支付 查询 退款 回调)
Stripe是一家美国科技公司,成立于2010年,由爱尔兰兄弟Patrick Collison和John Collison共同创立。该公司致力于提供高效、简洁的互联网支付收款服务,为开发者或商家提供支付API接口或代码,使商家的网站、移动APP支持信用卡付款。Stripe被誉为“移动时代的PayPal”,因其简便的支付方式而受到广泛欢迎。
Stripe 总共有三种支付方式:
1、Stripe Checkout,pay links 创建支付链接,
2、payment intent,后端预下单,返回秘钥,前端确定订单
3、前端创建支付token ,后端创建Charge,返回支付结果链接
Stripe接口调用时序图
0、初始化客户端
StripeClient client = StripeClient.builder().setConnectTimeout(30 * 1000).setReadTimeout(80 * 1000).setApiKey("sk_test_51PtO7DC6XhwanSnNvGezNPc4hsL2F****").build();
1、产品
查询或创建新产品。
每次交易传入产品名称或描述,自动查询是否已经存在,如果存在则直接使用,如果不存在则新建产品。
private Product getProduct(StripeOrder stripeOrder) throws StripeException {ProductSearchParams searchParams =ProductSearchParams.builder().setQuery("active:'true' AND name:'" + stripeOrder.getSubject()+ "' AND description:'" + stripeOrder.getBody() + "'").setLimit(1L).build();StripeSearchResult<Product> result = client.products().search(searchParams);Product product;if (result != null && !result.getData().isEmpty()) {product = result.getData().stream().findFirst().get();} else {//创建产品 https://stripe.com/docs/api/products/createProductCreateParams params = ProductCreateParams.builder().setDescription(stripeOrder.getBody()).setName(stripeOrder.getSubject()).build();product = client.products().create(params);}return product;}
2、价格
根据产品ID创建对应币种的价格,指定 lookupKey = 价格+币种+产品ID,作为价格关键字,用于查询是否已经存在。如果价格存在则直接使用,如果不存在则新增新的价格。
private Price getPrice(StripeOrder stripeOrder, String productId) throws StripeException {Long unitAmount = Util.conversionCentAmount(stripeOrder.getPrice());String lookupKey = unitAmount + stripeOrder.getCurrencyCode() + productId;PriceSearchParams params =PriceSearchParams.builder().setQuery("active:'true' AND product:'" + productId+ "' AND currency:'" + stripeOrder.getCurrencyCode()+ "' AND lookup_key:'" + lookupKey + "'").build();StripeSearchResult<Price> result = client.prices().search(params);Price price;if (result != null && !result.getData().isEmpty()) {price = result.getData().stream().findFirst().get();} else {//创建价格 https://stripe.com/docs/api/prices/create
// PriceCreateParams.Recurring recurring = PriceCreateParams.Recurring.builder()
// .setInterval(PriceCreateParams.Recurring.Interval.MONTH).build();PriceCreateParams priceCreateParams = PriceCreateParams.builder().setCurrency(stripeOrder.getCurrencyCode()).setProduct(productId).setLookupKey(lookupKey).setUnitAmount(unitAmount)
// .setRecurring(recurring).build();price = client.prices().create(priceCreateParams);}return price;
}
3、创建支付
根据上次返回的价格信息,创建新的支付对象,这里指定银行卡支付,也可以指定别的支付方式;Stripe支持几十种支付方式,可以根据不同国家选择,具体可以在这里查看
下面通过 client.checkout().sessions().create() 创建支付,取得支付链接,在浏览器直接打开即可支付。
public Map<String, Object> orderInfo(PayOrder order) {StripeOrder stripeOrder = (StripeOrder) order;try {Product product = getProduct(stripeOrder);Price price = getPrice(stripeOrder, product.getId());//创建支付信息 得到urlSessionCreateParams sessionCreateParams = SessionCreateParams.builder().setMode(SessionCreateParams.Mode.PAYMENT).addPaymentMethodType(SessionCreateParams.PaymentMethodType.CARD)
// .addPaymentMethodType(SessionCreateParams.PaymentMethodType.ALIPAY).setSuccessUrl(payConfigStorage.getReturnUrl()).setCancelUrl(payConfigStorage.getCancelUrl()).setCustomer(stripeOrder.getCustomer()).setClientReferenceId(stripeOrder.getClientReferenceId()).setCustomerEmail(stripeOrder.getCustomerEmail()).addLineItem(SessionCreateParams.LineItem.builder().setQuantity(1L).setPrice(price.getId()).build()).putMetadata("outTradeNo", stripeOrder.getOutTradeNo()).build();Session session = client.checkout().sessions().create(sessionCreateParams);LOG.info("session:{}", JSON.toJSONString(session));return preOrderHandler(Collections.singletonMap("paymentLink", session.getUrl()), order);} catch (StripeException e) {throw new RuntimeException(e);}
}
4、打开支付链接,完成支付
输入Stripe平台提供的测试卡信息,完成支付
test@example.com
4242 4242 4242 4242
12/34
567
Zhang San
United States
12345

5、支付订单查询
传入回调信息中得到的chargeId,查询订单状态。在返回的json数据了包含支付平台receiptUrl
public Map<String, Object> query(AssistOrder assistOrder) {try {Charge charge = client.charges().retrieve(assistOrder.getTradeNo());// 使用Hutool的BeanUtil将User对象转换为Mapreturn BeanUtil.beanToMap(charge);} catch (Exception e) {throw new RuntimeException(e);}
}
支付凭证

6、退款
传入回调信息中得到的chargeId,提交退款请求;返回退款订单信息,包含退款订单Id(可用于查询退款订单)
public RefundResult refund(RefundOrder refundOrder) {RefundCreateParams params = RefundCreateParams.builder().setCharge(refundOrder.getTradeNo()).build();try {Refund refund = client.refunds().create(params);LOG.info("refund:{}", JSON.toJSONString(refund));StripeRefundResult refundResult = new StripeRefundResult(refund, refundOrder.getTradeNo());refundOrder.setRefundNo(refundResult.getRefundNo());return refundResult;} catch (StripeException e) {throw new RuntimeException(e);}
}
7、退款查询
传入回调信息中得到的chargeId,查询退款订单;也可以通过退款订单Id查询。
public Map<String, Object> refundquery(RefundOrder refundOrder) {RefundListParams params = RefundListParams.builder().setCharge(refundOrder.getTradeNo()).build();try {StripeCollection<Refund> result = client.refunds().list(params);if (!result.getData().isEmpty()) {Refund refund = result.getData().stream().findFirst().get();// 使用Hutool的BeanUtil将User对象转换为Mapreturn BeanUtil.beanToMap(refund);}} catch (StripeException e) {throw new RuntimeException(e);}return null;
}
8、回调通知
登录Stripe平台,在https://dashboard.stripe.com/workbench/webhooks中配置Webhook;菜单地址“开发人员-Webhook”。

Webhook回调代码示例
public class StripePayMessageHandler implements PayMessageHandler<PayMessage, StripePayService> {private final Logger LOG = LoggerFactory.getLogger(getClass());private final String endpointSecret = "whsec_HlzC2omyh4V4X3BCgMx5PScTCmwZpvAC";//webhook秘钥签名@Overridepublic PayOutMessage handle(PayMessage payMessage, Map<String, Object> context, StripePayService payService) throws PayErrorException {Map<String, Object> message = payMessage.getPayMessage();NoticeParams noticeParams = (NoticeParams) context.get("noticeParams");try {String sigHeader = noticeParams.getHeader("Stripe-Signature");Event event = Webhook.constructEvent(noticeParams.getBodyStr(), sigHeader, endpointSecret);//验签,并获取事件StripeObject eventObj = event.getDataObjectDeserializer().getObject().get();LOG.info("EventType:{}, Event:{}", event.getType(), JSON.toJSONString(eventObj));PaymentIntent intent;Charge charge;String outTradeNo;String chargeId;String receiptUrl;switch (event.getType()) {case "charge.succeeded"://支付成功//TODO 支付成功,处理业务逻辑charge = (Charge) eventObj;// 取得 chargeId ,在退款时使用chargeId = charge.getId();receiptUrl = charge.getReceiptUrl();message.put("trade_no", chargeId);LOG.info("支付成功 Charge, chargeId:{}, receiptUrl:{}", chargeId, receiptUrl);break;case "checkout.session.completed":// 通过支付链接 支付完成//TODO 支付完成,处理业务逻辑Session session = (Session) eventObj;outTradeNo = session.getMetadata().get("outTradeNo");//自定义订单号LOG.info("支付完成 Session, 订单号为:{}", outTradeNo);message.put("out_trade_no", outTradeNo);break;case "charge.refunded"://退款成功charge = (Charge) eventObj;if (charge.getStatus().equals("succeeded")) {//TODO 退款成功,处理业务逻辑chargeId = charge.getId();receiptUrl = charge.getReceiptUrl();message.put("trade_no", chargeId);LOG.info("退款成功, chargeId:{}, receiptUrl:{}", chargeId, receiptUrl);}break;case "checkout.session.expired"://过期break;case "payment_intent.created"://创建订单 这里事件就是图二选着的事件break;case "payment_intent.canceled"://取消订单break;case "payment_intent.succeeded"://支付成功intent = (PaymentIntent) eventObj;Map<String, String> metaData = intent.getMetadata();//自定义传入的参数outTradeNo = metaData.get("outTradeNo");//自定义订单号message.put("out_trade_no", outTradeNo);LOG.info("支付成功 payment_intent, 订单号为:{}", outTradeNo);//*********** 根据订单号从数据库中找到订单,并将状态置为成功 *********//*break;case "payment_intent.payment_failed"://支付失败intent = (PaymentIntent) eventObj;LOG.info("Failed: " + intent.getId());break;default:break;}} catch (Exception e) {LOG.error("stripe异步通知(webhook事件)", e);}// TODO 支付确认逻辑处理return payService.successPayOutMessage(payMessage);}
}
参考
- https://docs.stripe.com/api
- https://docs.stripe.com/js
- https://docs.stripe.com/webhooks
- https://docs.stripe.com/search#query-fields-for-products
相关文章:
【支付】Stripe支付通道Java对接(产品 价格 支付 查询 退款 回调)
Stripe是一家美国科技公司,成立于2010年,由爱尔兰兄弟Patrick Collison和John Collison共同创立。该公司致力于提供高效、简洁的互联网支付收款服务,为开发者或商家提供支付API接口或代码,使商家的网站、移动APP支持信用卡付款。S…...
Unity3D 小案例 像素贪吃蛇 01 蛇的移动
Unity3D 小案例 像素贪吃蛇 第一期 蛇的移动 像素贪吃蛇 今天来简单制作一个小案例,经典的像素贪吃蛇。 准备 首先调整一下相机的设置,这里使用灰色的纯色背景,正交视图。 接着,创建一个正方形,保存为预制体&#…...
【STM32 MCU】stm32MCUs 32-bit Arm Cortex-M
stm32MCUs 32-bit Arm Cortex-M...
html+css网页设计 旅游 雪花旅行社5个页面
htmlcss网页设计 旅游 雪花旅行社5个页面 网页作品代码简单,可使用任意HTML辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作)。 获取源码 1&#…...
vue3中的实例
实例类型 Vue2:每个Vue应用都是new Vue创建的一个新实例,创建的时候将data作为property添加到响应式系统中 vue3:createApp创建一个Application Instance、应用实例用来注册全局内容,大多数方法支持链式调用,返回实例…...
9.测试计划(包含笔试/面试题)
一、软件测试计划介绍 1.测试计划就是一份测试文档,一份描述测试工作计划的文档,对测试计划进行统筹安排。 2.测试计划的编写者就是测试组长,测试主管。 3.测试计划的查阅者:测试人员,测试主管,产品&#x…...
这 7 款AI应用将让你全新的iPhone 16成为电影制作的强大工具
苹果公司在周一的Glowtime发布会上揭晓了新款的iPhone 16 Pro系列。除了新加入的苹果智能功能和令人印象深刻的硬件升级外,它还获得了一套视频制作工具,让用户能够在一个几乎可以放进口袋的设备上制作整部电影。 这些升级中有一个48MP融合相机。它具有2…...
自注意力机制(self-attention)
自注意力机制(self-attention) 之前听过吴恩达老师的课,吴恩达老师CNN那一块讲的特别好,但是后面RNN这一部分我听的不是很明白,今天有看了李宏毅老师attention这部分的课,总结一下笔记。 self-attention …...
Nuxt3入门:过渡效果(第5节)
你好同学,我是沐爸,欢迎点赞、收藏、评论和关注。 Nuxt 利用 Vue 的 <Transition> 组件在页面和布局之间应用过渡效果。 一、页面过渡效果 你可以启用页面过渡效果,以便对所有页面应用自动过渡效果。 nuxt.config.js export defaul…...
【开发工具】IntelliJ IDEA插件推荐:Json Helper——让JSON处理更高效
导语:在Java开发过程中,JSON作为一种轻量级的数据交换格式,被广泛应用于前后端数据交互。今天,我要为大家介绍一款IntelliJ IDEA插件——Json Helper,帮助开发者更高效地处理JSON数据。 一、什么是Json Helper&#x…...
Lua垃圾回收机制
Lua垃圾回收机制 在 Lua 中,一共只有8种数据类型,分别为 nil 、boolean 、userdata 、number 、string 、 table 、 function 、 userdata 和 thread 。其中,只有 string table function thread 四种是以引用方式共享,是需要被 G…...
Java学习路线:详细指引
Java学习路线可以分为几个阶段,每个阶段都有其重点和推荐学习的内容。下面我将按照初学者、进阶和高级三个阶段来举例说明: 初学者阶段 目标: 熟悉Java基础语法理解面向对象编程掌握基本数据类型和数据结构学会使用IDE(如Intel…...
商家转账到零钱如何开通-微信支付
商家转账到零钱是微信支付的一项实用功能,允许商户将资金从商户号余额直接转账到用户的微信零钱。我们以上万次成功申请的经验整理了本文的详细的步骤和建议以帮助商户可以快速开通该功能。 1. 准备工作 - 确认申请资格:只有公司性质的商户可以申请此功能…...
自研商家如何快速接入电商平台订单数据?
随着电子商务行业的快速发展,越来越多的商家开始寻求高效的订单管理和数据整合方案。对于那些自研系统的商家来说,如何实现与各大电商平台之间的无缝对接,成为了一项重要挑战。点三电商API正是为此类需求量身打造,为商家提供了一站…...
Win10下借助CMake编译OpenMVS
笔者在编译OpenMVS的过程十分曲折。刚开始借助CMake编译,能够把与库生成相关的工程编译出来,但是与可执行文件相关的工程会报错;后来参考官方教程借助VCPKG编译,发现VCPKG并没有想中强大、好用,最终也是遇到了各种问题没有编译成功。但是,笔者在解决问题的过程发现了问题…...
04_定时器与数码管基础
通过上节课的实验,大家会发现,我们逐渐进入比较实质性的学习了,需要记住的内容也更多了,个别地方可能会感觉吃力。但是大家不要担心,要有信心。这个跟小孩学走路一样,刚开始走得不太稳,没关系&a…...
Python 数学建模——方差分析
文章目录 前言单因素方差分析原理核心代码 双因素方差分析数学模型分析依据典型代码 前言 方差分析也是概率论中非常重要的内容,有时数学建模需要用到。方差分析是干什么的?如果说假设检验用于分析两个总体之间的均值 μ 1 , μ 2 \mu_1,\mu_2 μ1,μ…...
计算机视觉中,什么是上下文信息(contextual information)?
在计算机视觉中,上下文信息(contextual information)是指一个像素或一个小区域周围的环境或背景信息,它帮助模型理解图像中对象的相对位置、大小、形状,以及与其他对象的关系。上下文信息在图像中提供了全局的语义和结…...
YOLOv5改进 | 模块缝合 | C3 融合RVB + EMA注意力机制【二次融合】
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv5入门 改…...
mysql 更改默认端口号 新增用户密码 赋予权限
默认情况下,mysql的端口是3306,超级用户是root,很多情况下会被黑客扫描到,成为肉鸡(作者以前就有过经理),数据库表直接丢失,勒索我。 所以我这里介绍下,更改默认端口&am…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
