Java 微信支付验签实现教程

微信支付作为一种方便快捷的支付方式,广泛应用于各类电商平台中。而在支付完成后,我们需要对支付结果进行验签,以确保数据的完整性和真实性。本文将指导你如何在Java项目中实现微信支付的验签流程。

一、整体流程概述

验签的整体流程分为以下几个步骤:

步骤 描述
1 商户向微信发起支付请求,获得支付结果
2 微信异步通知商户支付结果
3 商户对接收到的通知进行验签
4 根据验签结果进行后续处理

二、详细步骤及代码实现

接下来,我们将逐步实现上述流程中的每一步。

1. 商户向微信请求支付

在请求支付时,你会得到一个预支付交易单号,这个步骤主要是为了处理正常的支付请求,并不包含验签。

2. 微信异步通知商户支付结果

当支付完成后,微信会向你配置的通知地址发送支付结果。这个通知是一个XML格式的数据,商户需要解析这个XML。

import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

// 假设xmlString是从微信服务器接收到的支付结果通知
String xmlString = "..."; // 微信异步通知的XML数据

// 将XML字符串转换为Document对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document document = factory.newDocumentBuilder().parse(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));

3. 商户对接收到的通知进行验签

3.1 提取签名数据

从解析后的XML中提取出需要验签的数据,包括支付结果的所有参数和签名。

import org.w3c.dom.Element;

Element root = document.getDocumentElement();
String totalFee = root.getElementsByTagName("total_fee").item(0).getTextContent();
String transactionId = root.getElementsByTagName("transaction_id").item(0).getTextContent();
String sign = root.getElementsByTagName("sign").item(0).getTextContent();

// TODO: 提取其他需要验签的参数
3.2 字典排序并拼接参数

对提取到的参数进行按字典排序,然后拼接成字符串,为签名验证做准备。

import java.util.*;

Map<String, String> params = new HashMap<>();
params.put("total_fee", totalFee);
params.put("transaction_id", transactionId);
// TODO: 加入其他参数

List<String> paramList = new ArrayList<>();
for (Map.Entry<String, String> entry: params.entrySet()) {
    paramList.add(entry.getKey() + "=" + entry.getValue());
}
Collections.sort(paramList);
StringBuilder sb = new StringBuilder();
for (String param : paramList) {
    sb.append(param).append("&");
}
// 去掉最后一个&
sb.setLength(sb.length() - 1);
String signContent = sb.toString();
3.3 生成待签名字符串

将待签名的内容进行加密,并与接收到的签名进行比较。

import java.security.MessageDigest;

String key = "你的秘钥"; // 商户秘钥
String finalSignContent = signContent + "&key=" + key;
String generatedSign = generateMD5(finalSignContent);

// MD5生成方法
private String generateMD5(String input) throws Exception {
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte[] digest = md.digest(input.getBytes("UTF-8"));
    
    StringBuilder hexString = new StringBuilder();
    for (byte b : digest) {
        String hex = Integer.toHexString(0xFF & b);
        if (hex.length() == 1) hexString.append('0');
        hexString.append(hex);
    }
    return hexString.toString().toUpperCase();
}

4. 根据验签结果进行后续处理

最后,根据验签的结果决定后续处理。

if (sign.equals(generatedSign)) {
    // 验签通过,进行业务处理
    System.out.println("验签成功,交易ID: " + transactionId);
} else {
    // 验签失败,记录日志
    System.out.println("验签失败,交易ID: " + transactionId);
}

三、序列图

下面的序列图展示了微信支付验签的整个过程:

sequenceDiagram
    participant Merchant
    participant WeChat
    Merchant->>WeChat: 发起支付请求
    WeChat-->>Merchant: 返回支付结果
    Merchant->>Merchant: 解析支付结果
    Merchant->>Merchant: 提取参数
    Merchant->>Merchant: 生成待签名字符串
    Merchant->>Merchant: 进行MD5签名
    Merchant->>Merchant: 验证签名
    alt 签名验证成功
        Merchant->>Merchant: 处理业务逻辑
    else 签名验证失败
        Merchant->>Merchant: 记录错误日志
    end

四、饼状图

下面的饼状图展示了验签过程中每个步骤的耗时比例,便于优化。

pie
    title 验签过程步骤耗时比例
    "解析支付结果": 30
    "提取参数": 10
    "生成待签名字符串": 20
    "进行MD5签名": 25
    "验证签名": 15

结尾

通过本文的介绍,我们详细讲解了微信支付验签的流程及代码实现。尽管过程看似繁琐,但只要按照步骤进行,你也能够轻松实现验签功能。希望这篇文章能对你在学习和开发中有所帮助。如有疑问,欢迎随时交流!