在 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)和可变数组&…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...