在 Spring Boot 中使用适配器模式实现支付网关的统一接口
引言
在许多电子商务系统中,集成多个支付网关是常见的需求。不同的支付网关有着不同的接口和实现细节。适配器模式可以帮助我们以一种灵活的方式实现这些不同的支付网关接口。
适配器模式简介
适配器模式将一个类的接口转换为客户期望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
示例
假设我们有一个电商平台,需要支持多种支付网关,包括:
- PayPal支付网关
- Stripe支付网关
- Alipay支付网关
步骤
-
定义目标接口 - 首先定义一个目标接口,声明所有支持的支付网关共有的方法。
java深色版本
1public interface PaymentGateway { 2 void processPayment(PaymentRequest request); 3} -
实现具体的支付网关类 - 接下来,为每种支付网关实现适配器。
-
PayPal支付网关适配器
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class PayPalPaymentGatewayAdapter implements PaymentGateway { 5 private final PayPalApi paypalApi; 6 7 public PayPalPaymentGatewayAdapter(PayPalApi paypalApi) { 8 this.paypalApi = paypalApi; 9 } 10 11 @Override 12 public void processPayment(PaymentRequest request) { 13 PayPalPaymentRequest paypalRequest = new PayPalPaymentRequest(request); 14 paypalApi.processPayment(paypalRequest); 15 } 16} -
Stripe支付网关适配器
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class StripePaymentGatewayAdapter implements PaymentGateway { 5 private final StripeApi stripeApi; 6 7 public StripePaymentGatewayAdapter(StripeApi stripeApi) { 8 this.stripeApi = stripeApi; 9 } 10 11 @Override 12 public void processPayment(PaymentRequest request) { 13 StripePaymentRequest stripeRequest = new StripePaymentRequest(request); 14 stripeApi.processPayment(stripeRequest); 15 } 16} -
Alipay支付网关适配器
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class AlipayPaymentGatewayAdapter implements PaymentGateway { 5 private final AlipayApi alipayApi; 6 7 public AlipayPaymentGatewayAdapter(AlipayApi alipayApi) { 8 this.alipayApi = alipayApi; 9 } 10 11 @Override 12 public void processPayment(PaymentRequest request) { 13 AlipayPaymentRequest alipayRequest = new AlipayPaymentRequest(request); 14 alipayApi.processPayment(alipayRequest); 15 } 16}
-
-
定义具体的支付网关 API 接口 - 为每个支付网关定义一个具体的 API 接口。
-
PayPal API 接口
java深色版本
1public interface PayPalApi { 2 void processPayment(PayPalPaymentRequest request); 3} -
Stripe API 接口
java深色版本
1public interface StripeApi { 2 void processPayment(StripePaymentRequest request); 3} -
Alipay API 接口
java深色版本
1public interface AlipayApi { 2 void processPayment(AlipayPaymentRequest request); 3}
-
-
实现具体的支付网关 API 类 - 接下来,为每个支付网关实现具体的 API 类。
-
PayPal API 类
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class PayPalApiImpl implements PayPalApi { 5 @Override 6 public void processPayment(PayPalPaymentRequest request) { 7 System.out.println("Processing payment via PayPal: " + request.getAmount()); 8 } 9} -
Stripe API 类
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class StripeApiImpl implements StripeApi { 5 @Override 6 public void processPayment(StripePaymentRequest request) { 7 System.out.println("Processing payment via Stripe: " + request.getAmount()); 8 } 9} -
Alipay API 类
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class AlipayApiImpl implements AlipayApi { 5 @Override 6 public void processPayment(AlipayPaymentRequest request) { 7 System.out.println("Processing payment via Alipay: " + request.getAmount()); 8 } 9}
-
-
定义支付请求类 - 定义一个支付请求类,用于封装支付请求的必要信息。
java深色版本
1public class PaymentRequest { 2 private String paymentMethod; 3 private double amount; 4 5 public PaymentRequest(String paymentMethod, double amount) { 6 this.paymentMethod = paymentMethod; 7 this.amount = amount; 8 } 9 10 public String getPaymentMethod() { 11 return paymentMethod; 12 } 13 14 public double getAmount() { 15 return amount; 16 } 17} -
定义具体的支付请求类 - 为每个支付网关定义一个具体的支付请求类。
-
PayPal支付请求
java深色版本
1public class PayPalPaymentRequest { 2 private final PaymentRequest request; 3 4 public PayPalPaymentRequest(PaymentRequest request) { 5 this.request = request; 6 } 7 8 public String getPaymentMethod() { 9 return request.getPaymentMethod(); 10 } 11 12 public double getAmount() { 13 return request.getAmount(); 14 } 15} -
Stripe支付请求
java深色版本
1public class StripePaymentRequest { 2 private final PaymentRequest request; 3 4 public StripePaymentRequest(PaymentRequest request) { 5 this.request = request; 6 } 7 8 public String getPaymentMethod() { 9 return request.getPaymentMethod(); 10 } 11 12 public double getAmount() { 13 return request.getAmount(); 14 } 15} -
Alipay支付请求
java深色版本
1public class AlipayPaymentRequest { 2 private final PaymentRequest request; 3 4 public AlipayPaymentRequest(PaymentRequest request) { 5 this.request = request; 6 } 7 8 public String getPaymentMethod() { 9 return request.getPaymentMethod(); 10 } 11 12 public double getAmount() { 13 return request.getAmount(); 14 } 15}
-
-
使用适配器 - 最后,在我们的业务逻辑中,根据需要选择并使用相应的适配器。
java深色版本
1import org.springframework.beans.factory.annotation.Autowired; 2import org.springframework.stereotype.Service; 3 4@Service 5public class PaymentService { 6 7 private final Map<String, PaymentGateway> paymentGateways; 8 9 @Autowired 10 public PaymentService(Map<String, PaymentGateway> paymentGateways) { 11 this.paymentGateways = paymentGateways; 12 } 13 14 public void processPayment(PaymentRequest request) { 15 PaymentGateway paymentGateway = paymentGateways.get(request.getPaymentMethod()); 16 if (paymentGateway != null) { 17 paymentGateway.processPayment(request); 18 } else { 19 throw new IllegalArgumentException("Unsupported payment method: " + request.getPaymentMethod()); 20 } 21 } 22} -
控制器 - 我们还需要一个控制器来测试这个逻辑。
java深色版本
1import org.springframework.beans.factory.annotation.Autowired; 2import org.springframework.web.bind.annotation.GetMapping; 3import org.springframework.web.bind.annotation.RequestMapping; 4import org.springframework.web.bind.annotation.RequestParam; 5import org.springframework.web.bind.annotation.RestController; 6 7@RestController 8@RequestMapping("/payments") 9public class PaymentController { 10 11 private final PaymentService paymentService; 12 13 @Autowired 14 public PaymentController(PaymentService paymentService) { 15 this.paymentService = paymentService; 16 } 17 18 @GetMapping("/process") 19 public String processPayment(@RequestParam("method") String method, 20 @RequestParam("amount") double amount) { 21 PaymentRequest request = new PaymentRequest(method, amount); 22 paymentService.processPayment(request); 23 return "Payment processed successfully."; 24 } 25} -
测试 - 最后,我们可以通过发送 HTTP 请求来测试不同的支付网关。
bash深色版本
1curl 'http://localhost:8080/payments/process?method=paypal&amount=100' 2curl 'http://localhost:8080/payments/process?method=stripe&amount=150' 3curl 'http://localhost:8080/payments/process?method=alipay&amount=200'
结论
通过使用适配器模式,我们可以在运行时灵活地选择不同的支付网关,并使用统一的接口与之交互。这种方式不仅提高了代码的可读性和可维护性,还使得扩展新的支付网关变得非常简单。在 Spring Boot 中,依赖注入机制进一步简化了适配器模式的实现过程。
相关文章:
在 Spring Boot 中使用适配器模式实现支付网关的统一接口
引言 在许多电子商务系统中,集成多个支付网关是常见的需求。不同的支付网关有着不同的接口和实现细节。适配器模式可以帮助我们以一种灵活的方式实现这些不同的支付网关接口。 适配器模式简介 适配器模式将一个类的接口转换为客户期望的另一个接口。适配器模式使…...
【书生·浦语大模型实战营】第三期 入门岛作业
入门岛作业 Linux闯关任务:完成 SSH 连接与端口映射并运行 hello_world.py。配置vscode作业内容 可选任务1:将Linux基础命令在开发机上完成一遍作业内容 可选任务 2:使用 VSCODE 远程连接开发机并创建一个conda环境作业内容 可选任务 3&#…...
Redis的String类型常用命令总结
1. set 设置一个键的值。 set key value示例: set username "alice"2. get 获取一个键的值。 get key示例: get username3. getset 设置键的值,并返回键的旧值。 getset key value示例: getset username "…...
河南萌新联赛2024第(四)场:河南理工大学
A 思路: B 思路:有一种贪心的写法,将整个数组排序以后比较两个相邻数的同或值,取 m a x max max,不会证明 int th(int x, int y, int z) {int res 0;for (int i z - 1; i > 0; i --) {int dx (x >> i &…...
Linux中临时使用账号提权进行业务操作
普通账号提权 su:永久提权 Switching users with su sudo:临时提权 Running commands as root with sudo 1)su切换账号 需要对方的密码 示例:切换到超级管理员 su - root 建议用-这个 su root 普通用户需要执行特殊指令&…...
lwip 3. 网线拔掉后 lwip_recvfrom不能返回
当网线被拔掉后,LWIP的lwip_recvfrom函数无法返回,这通常意味着网络连接已经断开,而LWIP没有自动检测到这种断开并进行相应的处理。具体卡在这个地方: ret xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY); //具…...
Linux环境安装Docker Engine
Docker是一个开源的应用容器引擎,由Go语言开发,基于Linux内核技术。Docker通过将应用及其依赖打包到可移植的容器中,实现了应用的快速部署和高效管理。Docker容器具有轻量级、快速启动、可移植性强等特点,能够显著提升资源利用率和…...
大厂面试题分享
大厂面试题分享 Redis持久化方式AOF优缺点RDB优缺点 如何保证Redis和Myql的一致性索引下推输入url到浏览器发生了什么ReentranLock底层原理SpringBoot 的启动流程 Redis持久化方式 Redis提供了两种主要的持久化机制,分别是AOF(Append-Only File…...
FPGA面试问题整理
1. 逻辑设计中竞争与冒险概念,如何识别和消除? 竞争:在组合逻辑电路中,信号经过多条路径到达输出端,每条路径经过的逻辑门不同存在时差,在信号变化的瞬间存在先后顺序。这种现象叫竞争。 冒险:由…...
3Done学习笔记
一、基本操作 1、旋转视角 使用左下角立方体选择; 右键可以拖动视角; 中间滑轮按住拖动整个舞台界面。 2、平移和旋转 右键选择移动,有两种方式。 第一种选择起始点,按照起始点位置移动到终止点(边、角、中心点…...
AI学习指南深度学习篇-卷积层详解
AI学习指南深度学习篇-卷积层详解 一、引言 随着人工智能技术的不断发展,深度学习作为人工智能领域的热门分支之一,正在逐渐成为各个领域的核心技术。而在深度学习中,卷积神经网络(Convolutional Neural Network,CNN…...
2024年TI杯E题-三子棋游戏装置方案分享-jdk123团队-第二弹 手搓机械臂
第一弹赛题的选择与前期方案的准备 opencv调用摄像头bug的解决 机械臂的组装 采用三个舵机,组成一个三自由度的机械臂。 并且利用电磁吸盘的方式,完成对棋子的抓取工作,后面的事实证明,在预算不足的情况下,队友手搓…...
如何在Java、C、Ruby语言中使用Newscatcher API
Newscatcher 世界实时新闻聚合API 一款强大的数据服务工具,它通过先进的网络爬虫技术,实时从全球超过70,000个新闻源聚合新闻内容。这个API能够提供全面、多角度的新闻报道,包括但不限于标题、作者、发布日期、全文内容以及媒体资源链接。它使…...
集合: Collection的成员方法和相关实现类
Collection: - List(有序【指的是存储和取出的顺序是一致的】且可以发生重复,且有索引的概念) - ArrayList: 底层数据结构是数组,查询快,增删慢,线程不安全的,效率高。 - …...
过滤器与监听器:深入了解 Java Web 开发中的核心概念
在 Java Web 开发中,过滤器(Filter)和监听器(Listener)是两个重要的组件,它们帮助开发者在请求处理的各个阶段进行预处理和后处理。这篇博客将深入探讨这两个概念,并展示它们如何在实际应用中发…...
【Linux学习】动静态库从原理到制作
🍑个人主页:Jupiter. 🚀 所属专栏:Linux从入门到进阶 欢迎大家点赞收藏评论😊 目录 🍑动静态库🐟动静态库的制作与使用🚀生成静态库🔒生成动态库 🦌动态库的查…...
WPF篇(10)-Label标签+TextBlock文字块+TextBox文本框+RichTextBox富文本框
Label标签 Label控件继承于ContentControl控件,它是一个文本标签,如果您想修改它的标签内容,请设置Content属性。我们曾提过ContentControl的Content属性是object类型,意味着Label的Content也是可以设置为任意的引用类型的。 案…...
JavaFX对话框控件-ChoiceDialog
JavaFX对话框控件-ChoiceDialog 常用属性titlecontentTextinitOwnergraphicheaderTextdefaultValuechoicesdialogPane 常用事件显示事件setOnShowing显示事件setOnShown弹框按钮点击 综合案例自定义下拉框内容 与Alert大部分功能类似按钮不可以自定义多一个下拉框 常用属性 …...
一文了解BTC中的二层协议中Nervos network,CKB,RGB++,UTXO stack 之间的关系
注:该内容不构成投资建议,有些内容摘抄其他地方,如侵权,请联系删除。 Nervos network Nervos Network 是一个开源的区块链生态项目,该项目提供一套解决方案来应对区块链扩展性和互操作性的问题。 Nervos Network 成立…...
Oracle(47)如何创建和使用集合?
在PL/SQL中,集合(Collection)是一种复合数据类型,用于存储一组相关的数据项。集合主要有三种类型:关联数组(Associative Arrays)、嵌套表(Nested Tables)和可变数组&…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
