Java对接微信支付V3流程及示例代码

微信支付V3对接流程如下:

  1. 创建商户平台账号:在微信支付商户平台(pay.weixin.qq.com)上注册并创建商户平台账号。

  2. 开通微信支付功能:在商户平台上完成实名认证,并申请开通微信支付功能。

  3. 获取API证书:在商户平台上下载API证书,并将证书保存在安全的地方。

  4. 配置回调接口:在商户自己的服务器上配置一个用于接收微信支付结果通知的回调接口,并确保能够正确处理通知。

  5. 获取接口调用凭证:在商户平台上获取接口调用凭证(API秘钥),用于后续API的调用。

  6. 调用API接口:使用接口调用凭证,调用相应的API接口,完成支付相关的操作,如生成支付订单、查询订单状态等。

  7. 处理支付结果:在接收到微信支付结果通知后,根据通知内容进行相应的处理,如更新订单状态、发货等。

  8. 进行退款操作:根据需要,可以调用退款接口进行退款操作。

  9. 审核接入资质:在支付成功后,根据微信支付的规定,需要将商户的接入资质进行审核。

  10. 上线测试:完成以上步骤后,可以进行上线测试,确保支付功能正常。

以上是微信支付V3对接的基本流程,具体流程可能还会根据具体需求有所差异。建议在对接前仔细阅读微信支付官方文档,参考下面的接口调用示例进行对接。

微信支付 V3 对接流程简要如下:

  1. 注册微信支付商户号,并获取到商户号和商户密钥。
  2. 在微信商户平台生成 API v3 密钥,并下载证书。
  3. 配置证书,并设置商户号和商户密钥。
  4. 构建请求参数,包括接口地址、请求方法、请求头、请求体等。
  5. 生成签名,将签名添加到请求头中。
  6. 发送请求,获取响应。
  7. 解析响应,获取支付结果等相关信息。

下面是一个示例代码,基于 Java 实现微信支付 V3 对接:

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*;
import org.apache.commons.codec.binary.Base64;
import com.google.gson.Gson;
import com.google.gson.JsonObject;


public class WechatPayV3Demo {

    private static final String MCH_ID = "your_mch_id";
    private static final String MCH_KEY = "your_mch_key";
    private static final String API_V3_KEY_PATH = "your_api_v3_key_path";
    private static final String CERT_PATH = "your_cert_path";
    private static final String CERT_PASSWORD = "your_cert_password";
    private static final String API_BASE_URL = "https://api.mch.weixin.qq.com/v3";
    private static final String PAY_URL = API_BASE_URL + "/pay/transactions/native";

    public static void main(String[] args) throws Exception {
        String amount = "100";
        String description = "test payment";
        String outTradeNo = "your_out_trade_no";

        // 构建请求参数
        JsonObject request = new JsonObject();
        request.addProperty("mchid", MCH_ID);
        request.addProperty("out_trade_no", outTradeNo);
        request.addProperty("description", description);
        request.addProperty("amount", amount);
        request.addProperty("notify_url", "your_notify_url");

        // 发送请求
        String response = sendPostRequest(PAY_URL, request.toString());

        // 解析响应
        JsonObject jsonResponse = new Gson().fromJson(response, JsonObject.class);
        String codeUrl = jsonResponse.get("code_url").getAsString();
        System.out.println("Payment QR Code URL: " + codeUrl);
    }

    private static String sendPostRequest(String url, String requestBody) throws Exception {
        // 加载证书
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new FileInputStream(CERT_PATH), CERT_PASSWORD.toCharArray());

        // 创建 SSL 上下文
        SSLContext sslContext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, CERT_PASSWORD.toCharArray())
                .build();

        // 创建 SSL 连接工厂
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
                new String[]{"TLSv1.2"}, null, new DefaultHostnameVerifier());

        // 创建默认的请求配置
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(5000)
                .setConnectTimeout(5000)
                .build();

        // 创建 HttpClient
        CloseableHttpClient httpClient = HttpClientBuilder.create()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .setDefaultRequestConfig(requestConfig)
                .build();

        // 构造请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Accept", "application/json");
        httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
        httpPost.setHeader("User-Agent", "Mozilla/5.0");
        httpPost.setHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 " + generateAuthorizationHeader(httpPost, requestBody));

        // 设置请求体
        httpPost.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));

        // 发送请求
        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        int statusCode = httpResponse.getStatusLine().getStatusCode();
        String response = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);

        // 关闭连接
        httpClient.close();
        httpResponse.close();

        // 检查响应状态码
        if (statusCode != HttpURLConnection.HTTP_OK) {
            throw new Exception("HTTPPOST Failed with Error Code: " + statusCode + ", Response Body: " + response);
        }

        return response;
    }

    private static String generateAuthorizationHeader(HttpPost httpPost, String requestBody) throws Exception {
        String method = httpPost.getMethod();
        String url = httpPost.getURI().getPath();
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);

        // 生成签名
        String signature = generateSignature(method, url, timestamp, requestBody);

        // 生成 Authorization header
        return "mchid=\"" + MCH_ID + "\","
                + "nonce_str=\"" + getRandomString(32) + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + getCertificateSerialNumber() + "\","
                + "signature=\"" + signature + "\"";
    }

    private static String generateSignature(String method, String url, String timestamp, String requestBody) throws Exception {
        String message = method + "\n"
                + url + "\n"
                + timestamp + "\n"
                + getCanonicalRequestHeaders() + "\n"
                + getSHA256Hash(requestBody) + "\n";
        
        // 从 API V3 密钥中加载私钥
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(readFile(API_V3_KEY_PATH)));

        // 使用私钥对消息进行签名
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(message.getBytes(StandardCharsets.UTF_8));
        byte[] signatureBytes = signature.sign();
        
        // 返回 Base64 编码的签名值
        return Base64.encodeBase64String(signatureBytes);
    }

    private static String getCanonicalRequestHeaders() {
        return "accept:application/json\n"
                + "content-type:application/json; charset=utf-8\n"
                + "user-agent:Mozilla/5.0\n";
    }

    private static String getSHA256Hash(String input) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = digest.digest(input.getBytes(StandardCharsets.UTF_8));
        StringBuilder hexString = new StringBuilder();
        for (byte hashByte : hashBytes) {
            String hex = Integer.toHexString(0xFF & hashByte);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    private static String getRandomString(int length) {
        String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder randomString = new StringBuilder();
        SecureRandom secureRandom = new SecureRandom();
        for (int i = 0; i < length; i++) {
            randomString.append(characters.charAt(secureRandom.nextInt(characters.length())));
        }
        return randomString.toString();
    }

    private static String getCertificateSerialNumber() throws Exception {
        X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance("X509")
                .generateCertificate(new FileInputStream(CERT_PATH));
        return certificate.getSerialNumber().toString(16).toUpperCase();
    }

    private static byte[] readFile(String filePath) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try (InputStream inputStream = new FileInputStream(filePath)) {
            byte[] buffer = new byte[2048];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
        }
        return outputStream.toByteArray();
    }
}

以上就是微信支付 V3 对接流程及代码的示例,你可以根据自己的实际情况进行修改和扩展。请注意,示例中的 your_mch_idyour_mch_keyyour_api_v3_key_pathyour_cert_pathyour_cert_passwordyour_out_trade_noyour_notify_url 都需要替换为真实的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值