【什么是回调机制?理解回调机制及微信支付回调】

ops/2024/10/9 9:10:55/

文章目录

    • 一.什么是回调机制?
    • 二.Java中的回调机制实现方式
      • 1.接口回调
      • 2.通过匿名类或Lambda表达式实现回调
      • 3.异步回调
    • 三.看下微信开发平台,了解支付微信的支付回调实现
      • 1.小程序下单:
      • 2.小程序调起支付
      • 3.支付通知(异步回调)
      • 4. 结合微信开放平台理解支付回调
      • 5.简单了解下微信支付 APIv3吧
    • 四.小结

一.什么是回调机制?

在Java编程中,回调机制(Callback)是一种允许程序将某些任务的执行控制权交给其他代码的编程模式。具体来说,回调机制是通过将一个方法或函数的引用作为参数传递给另一个方法,当特定条件满足时,由这个被调用的方法在某个时刻回调该函数。这种机制常用于处理异步操作或事件驱动编程。
回调机制的核心思想是解耦,也就是将任务的调用方和执行方分离。调用方只需要知道某个任务什么时候需要执行,而不关心具体如何执行。

之前一直听到过什么微信支付回调等等,虽然我也没对接过微信支付,但看了下微信开放平台,等下直接结合微信支付回调来理解回调思想。

回调的作用:回调函数允许我们把控制权转移给任务的调用方。在不同的场景下,回调函数有很多作用:

  • 事件驱动编程:当事件发生时(如按钮点击、页面加载完成等),触发回调函数。
  • 异步处理:任务完成后,回调函数可以处理返回结果或错误,避免阻塞程序。
  • 模块化:回调使得代码更加解耦、模块化,不同的任务可以通过不同的回调函数来处理结果。

二.Java中的回调机制实现方式

1.接口回调

Java中常用接口来实现回调。调用者定义一个接口,并在需要回调的地方传递一个实现了该接口的对象。当触发条件满足时,系统调用接口中的方法。

java">// 定义回调接口
interface Callback {void onCallback();
}// 回调接口的实现类
class CallbackImpl implements Callback {@Overridepublic void onCallback() {System.out.println("回调方法被调用");}
}// 支付逻辑处理...
private void syncPayCallBack(Callback callback) {log.info("支付逻辑处理完成...同步执行支付回调");callback.onCallback();
}public static void main(String[] args) {TestCaseServiceImpl tc = new TestCaseServiceImpl();Callback callback = new CallbackImpl();tc.syncPayCallBack(callback);
});

测试结果:
支付逻辑处理完成…同步执行支付回调
回调方法被调用

2.通过匿名类或Lambda表达式实现回调

Lambda表达式传递回调。

java">   public static void main(String[] args) {TestCaseServiceImpl tc = new TestCaseServiceImpl();tc.syncPayCallBack(()->log.info("支付回调处理完成"));}    

测试结果:
支付逻辑处理完成…同步执行支付回调
支付回调处理完成

3.异步回调

在同步回调中,回调函数会立即执行。而在异步回调中,任务执行完成后回调函数是在另一个线程中被调用的,常用于网络请求、数据库查询等耗时操作。在Java中,异步回调通常使用 CompletableFuture 来实现。(项目里面使用CompletableFuture 记得要传入自定义线程池)

java">   public static void main(String[] args) {// 异步任务CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000); // 模拟耗时操作} catch (InterruptedException e) {e.printStackTrace();}return "异步任务完成";}).thenAccept(result -> log.info(("回调收到结果: " + result)); // 回调处理结果log.info(("主线程继续运行");// 等待异步任务完成future.join(); // 使用 join() 阻塞主线程,直到异步任务完成}

测试结果:
主线程继续运行
回调收到结果: 异步任务完成

三.看下微信开发平台,了解支付微信的支付回调实现

官方链接:https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/payment-notice.html

1.小程序下单:

有个必填参数notify_url【通知地址】 异步接收微信支付结果通知的回调地址
在这里插入图片描述

2.小程序调起支付

这块还没到回调,我们暂不关注

3.支付通知(异步回调)

用户发起微信支付请求之后,微信服务端一般不会阻塞等待支付结果返回给商户。而是通过回调我们下单填的回调地址,把相关支付信息及支付状态等发送给商户,商户需要在回调地址里面接收处理该消息,并返回应答。支付平台通过回调通知接口告知调用方支付成功与否,这种方式也是回调思想的体现。
在这里插入图片描述

4. 结合微信开放平台理解支付回调

我没对接过微信支付,上家公司小程序有对接过微信支付,仅了解一点点。我们了解回调机制之后,是不是对微信支付后的回调流程很容易就理解了呢。微信支付服务端处理完支付业务返回支付成功,然后异步处理支付回调(请求我们的回调地址,把支付数据、支付状态等等一些信息传给回调地址),等待商户去处理完订单状态再应答,如果微信收到应答不是成功或超时,微信认为通知失败,再通过一定的策略定期重新发起通知(回调)。了解回调机制后理解微信支付的回调就简单多了。

5.简单了解下微信支付 APIv3吧

APIv3支付回调的安全机制
APIv3回调与APIv2相比,最大的改进是敏感数据加密和回调签名验证。它确保了回调过程中数据的安全性,防止数据被篡改或泄露。

  1. 回调数据加密(AES-GCM加密)
    APIv3的异步通知数据中的敏感字段(如订单号、支付金额等)是使用微信支付平台的公钥进行AES-GCM加密。商户接收到回调数据后,需要使用自己的API密钥进行解密。

  2. 回调签名验证
    APIv3要求商户对接收到的回调请求进行签名验证,确保通知来自微信支付平台,防止伪造通知。签名验证需要使用微信支付提供的公钥来验证回调请求的完整性。

APIv3回调的处理流程代码示例
以下是一个处理微信支付APIv3回调的流程示例,基于Java Spring框架。

java">import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Base64;@RestController
public class WeChatPayV3CallbackController {// 微信支付APIv3密钥private static final String API_V3_KEY = "your-api-v3-key-here";@PostMapping("/wechat/pay/callback")public String handleWeChatPayCallback(@RequestBody String requestBody) {try {// Step 1: 解析微信支付回调通知的JSONObjectMapper objectMapper = new ObjectMapper();JsonNode rootNode = objectMapper.readTree(requestBody);// 获取加密数据String ciphertext = rootNode.get("resource").get("ciphertext").asText();String associatedData = rootNode.get("resource").get("associated_data").asText();String nonce = rootNode.get("resource").get("nonce").asText();// Step 2: 解密加密数据,使用AES-GCM解密String decryptedData = decrypt(ciphertext, associatedData, nonce);// Step 3: 处理解密后的数据JsonNode resultData = objectMapper.readTree(decryptedData);String transactionId = resultData.get("transaction_id").asText(); // 微信支付订单号String outTradeNo = resultData.get("out_trade_no").asText();      // 商户订单号String tradeState = resultData.get("trade_state").asText();       // 支付状态// 根据支付结果处理商户业务逻辑if ("SUCCESS".equals(tradeState)) {// 支付成功的逻辑,更新订单状态updateOrderStatus(outTradeNo, transactionId);}// Step 4: 返回处理结果,通知微信支付停止回调return "{\"code\":\"SUCCESS\",\"message\":\"OK\"}";} catch (Exception e) {e.printStackTrace();// 如果处理失败,返回错误信息return "{\"code\":\"FAIL\",\"message\":\"Server Error\"}";}}// AES-GCM解密方法private String decrypt(String ciphertext, String associatedData, String nonce) throws Exception {// 将APIv3密钥转为字节数组byte[] key = API_V3_KEY.getBytes(StandardCharsets.UTF_8);Key secretKey = new SecretKeySpec(key, "AES");// 使用AES-GCM解密Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));byte[] decodedCiphertext = Base64.getDecoder().decode(ciphertext);byte[] decryptedData = cipher.doFinal(decodedCiphertext);return new String(decryptedData, StandardCharsets.UTF_8);}private void updateOrderStatus(String outTradeNo, String transactionId) {// 这里是更新商户订单状态的逻辑,例如标记订单已支付System.out.println("订单 " + outTradeNo + " 已支付,交易号:" + transactionId);}
}

回调通知的关键字段

  1. 微信支付APIv3的回调通知是以JSON格式发送,主要包含以下几个关键字段:
  • id: 回调通知的唯一标识
  • event_type: 事件类型(如支付成功:TRANSACTION.SUCCESS)
  • resource:包含加密的支付数据的对象
    1. ciphertext: 加密后的支付数据
    2. nonce: 加密使用的随机串
    3. associated_data: 加密的附加数据
    4. summary: 支付的简单描述
  1. 解密后的数据通常包含以下信息:
  • transaction_id: 微信支付订单号
  • out_trade_no: 商户订单号
  • trade_state: 支付状态(SUCCESS表示支付成功)
  • total: 支付金额等信息

安全要求

  1. 签名验证:商户必须使用微信支付提供的公钥对回调通知的签名进行验证,以确保通知的真实性。具体的签名验证步骤可以使用微信支付官方SDK或者商户自行实现。
  2. 数据解密:商户需要使用APIv3的密钥对加密的数据进行解密,确保支付结果数据的隐私性。

重试机制
与APIv2类似,如果商户没有正确返回处理结果,微信支付APIv3也会按一定的策略对回调通知进行重试。因此,商户应在处理完回调后,返回{“code”:“SUCCESS”, “message”:“OK”},以确保不再接收到重复通知。

总结:微信支付APIv3相较于APIv2,增强了回调通知的安全性,特别是对敏感信息的加密和签名验证。商户在接收到回调通知后,需要先验证通知的签名,再解密支付数据,并根据支付结果进行相应的业务处理。回调的处理逻辑必须保证幂等性,以避免重复处理

四.小结

  1. 主要介绍了什么是回调机制及同步回调异步回调使用及回调机制在微信支付里面的应用。Java中的回调机制提供了一种灵活的方式来解耦逻辑,使得代码模块可以更独立地开发和维护。
  2. 回调机制的常见应用场景包括:
  • 事件驱动编程(如GUI开发)
  • 异步操作(如网络请求、文件处理)
  • 设计模式(如观察者模式、策略模式)
  • I/O操作 任务调度与定时操作
  • 通过回调机制,可以使代码更加灵活,响应性更好,尤其是在处理异步任务和事件驱动应用时,回调机制显得尤为重要。

http://www.ppmy.cn/ops/123102.html

相关文章

flutter_鸿蒙next_Dart基础③函数

目录 说在前面 1. 函数的基本定义 例子 代码解释 2. 函数的调用 代码解释 3. 可选参数与命名参数 可选参数 代码解释 调用示例 命名参数 代码解释 调用示例 4. 匿名函数与高阶函数 例子 代码解释 说在最后 说在前面 在 Dart 编程语言中&#xff0c;函数是构建…

容器化技术:Docker的基本概念和使用

在现代软件开发和运维中&#xff0c;容器化技术已经成为一种不可或缺的工具。Docker作为容器化技术的代表&#xff0c;以其轻量级、可移植性和隔离性等特点&#xff0c;赢得了广泛的关注和应用。本文将详细介绍Docker的基本概念和使用方法&#xff0c;帮助读者快速上手Docker容…

代码随想录day22:回溯part4

491.递增子序列 class Solution {List<List<Integer>> result new ArrayList<>();List<Integer> path new ArrayList<>();public List<List<Integer>> findSubsequences(int[] nums) {backTracking(nums, 0);return result;}priv…

vue快速上手

文章目录 vue快速上手vue简述框架介绍mvvm vue使用1.npm2.vue cli1.打开 vue 官网2.快速上手3.切换目录到我们创建的应用位置&#xff0c;安装依赖3.运行vue项目 vue快速上手 vue简述 框架介绍 mvvm vue使用 1.npm 包管理器 安装nodejs就好了 2.vue cli 1.打开 vue 官网…

OJ在线评测系统 思考如何进行微服务的划分 业务功能 占用端口 公共服务 依赖服务 路由

思考 微服务是一种架构风格 微服务就是把一个项目拆分成多个独立的不封 而且多个服务都是可以运行的 每个服务都会占用线程 传统的IT行业软件都是独立系统的堆砌 这些系统总结来说就是可拓展性不高 可靠性不高 维护成本广告 微服务的每个模块都是独立的 而且可以用有多重存…

【中间件】fastDFS的相关知识

一、分布式文件系统 1.1 传统的文件系统 我们在Linux中学习的文件系统就是传统的文件系统&#xff1a; 传统的文件系统格式&#xff1a; ntfs/fat32/ext3/ext4 可以被挂载和卸载&#xff0c;就是一般一个盘可以分成多个盘&#xff0c;每一盘都可以挂载到不同的目录路径中。…

鸿蒙 Next 实战: 电子木鱼

前言 正所谓&#xff1a;Hello Word 是程序员学任何一门语言的第一个程序实践。这其实也是一个不错的正反馈&#xff0c;那如何让学习鸿蒙 Next 更有成就感呢&#xff1f;下面就演示一下从零开发一个鸿蒙 Next 版的电子木鱼&#xff0c;主打就是一个抽象&#xff01; 实现要点…

使用docker搭建zk集群

使用zk搭建一个3节点的zk集群&#xff0c;网络方式为host。 配置节点1 # 创建一个目录 /root/lyl/zookeeper/zk1创建文件myid&#xff0c;文件内容如下&#xff1a; 1 创建文件zoo.cfg&#xff0c;文件内容如下&#xff1a; # The number of milliseconds of each tick ti…