当前位置: 首页 > article >正文

【什么是回调机制?一篇文章掌握回调机制及思想】

文章目录

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

一.什么是回调机制?

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

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

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

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

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

1.接口回调

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

// 定义回调接口
interface Callback {
    void onCallback();
}

// 回调接口的实现类
class CallbackImpl implements Callback {
    @Override
    public 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表达式传递回调。

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

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

3.异步回调

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

   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框架。

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: 解析微信支付回调通知的JSON
            ObjectMapper 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.kler.cn/news/339394.html

相关文章:

  • 在虚拟机里试用了几个linux操作系统
  • 网络编程(14)——基于单例模板实现的逻辑层
  • 收银台实现iframe跨页面调用函数的方法——未来之窗行业应用跨平台架构
  • 《系统架构设计师教程(第2版)》第17章-通信系统架构设计理论与实践-07-通信网络构建案例分析
  • 毕设 深度学习语义分割实现弹幕防遮(源码分享)
  • 容器管理工具Docker
  • List子接口
  • C语言 | 第十一章 | static 日期函数 数学函数
  • 活动邀请 | SonarQube×创实信息即将亮相2024 GOPS全球运维大会-上海站,分享代码质量与安全提升策略
  • JavaScript函数基础(通俗易懂篇)
  • 【iOS】计算器仿写
  • 面试(十)
  • 三级等保对postgresql的安全要求配置
  • 《重庆师范大学学报(自然科学版)》
  • Django学习笔记十一:部署程序
  • 快速学习开源 Docker 镜像仓库 Harbor
  • HUAWEI_HCIA_实验指南_Lib1.4_配置通过Telnet登录系统
  • 04_23 种设计模式之《单例模式》
  • pg if条件语句
  • Robot Operating System——诊断状态信息