java微信支付V3 退款 demo

package com.sunvitek.application.creditdata.controller;

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import com.github.wxpay.sdk.WXPayUtil;
import okhttp3.HttpUrl;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import com.fasterxml.jackson.databind.ObjectMapper;

public class WeChatRefund {

    private static final String API_URL = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
    private static final String MCH_ID = ""; // 商户号
    private static final String PRIVATE_KEY_PATH = "F:\\项目文件\\配置文件\\001\\apiclient_key.pem"; // 私钥路径
    private static final String CERT_SERIAL_NO = ""; // 证书序列号

    public static String refund(String transactionId, String outTradeNo, String outRefundNo, String reason, String notifyUrl, int refundAmount, int totalAmount, String currency) throws Exception {
        // 创建退款请求参数
        Map<String, Object> data = new HashMap<>();
        data.put("out_trade_no", "");
        data.put("out_refund_no", ""); // 这里需要的是字符串

        // 构建 amount 字段
        Map<String, Object> amount = new HashMap<>();
        amount.put("refund", 2); // 应为整数
        amount.put("total", 2);  // 应为整数
        amount.put("currency", "CNY");
        data.put("amount", amount);

        // 将参数转换为JSON
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonParams = objectMapper.writeValueAsString(data);

        // 创建HTTP客户端
        CloseableHttpClient httpClient = HttpClients.createDefault();

        try {
            HttpPost httpPost = new HttpPost(API_URL);
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 " + generateAuthorizationHeader("POST", API_URL, jsonParams));

            StringEntity entity = new StringEntity(jsonParams, "UTF-8");
            httpPost.setEntity(entity);

            // 执行请求
            HttpResponse response = httpClient.execute(httpPost);
            String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");

            return responseString;
        } finally {
            httpClient.close();
        }
    }

    private static String generateAuthorizationHeader(String method, String url, String body) throws Exception {
        HttpUrl httpUrl = HttpUrl.parse(url);
        String nonceStr = WXPayUtil.generateNonceStr();
        long timestamp = System.currentTimeMillis() / 1000;
        String message = buildMessage(method, httpUrl, timestamp, nonceStr, body);
        String signature = sign(message.getBytes("utf-8"));

        return "mchid=\"" + MCH_ID + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + CERT_SERIAL_NO + "\","
                + "signature=\"" + signature + "\"";
    }

    private static String sign(byte[] message) throws Exception {
        PrivateKey privateKey = loadPrivateKey(PRIVATE_KEY_PATH);
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(message);

        return Base64.getEncoder().encodeToString(sign.sign());
    }

    private static PrivateKey loadPrivateKey(String privateKeyPath) throws Exception {
        // 加载私钥文件
        try (FileInputStream fis = new FileInputStream(privateKeyPath)) {
            byte[] keyBytes = new byte[fis.available()];
            fis.read(keyBytes);

            String privateKeyPem = new String(keyBytes)
                    .replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s", "");

            byte[] decoded = Base64.getDecoder().decode(privateKeyPem);
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePrivate(spec);
        }
    }

    private static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
        String canonicalUrl = url.encodedPath();
        if (url.encodedQuery() != null) {
            canonicalUrl += "?" + url.encodedQuery();
        }

        return method + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }

    public static void main(String[] args) {
        try {
            String result = refund("your_transaction_id", null, "your_out_refund_no", "Refund Reason", "your_notify_url", 2, 2, "CNY");
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java微信支付v3退款的示例代码: ```java import com.github.wxpay.sdk.WXPay; import com.github.wxpay.sdk.WXPayConstants; import com.github.wxpay.sdk.WXPayUtil; import java.util.HashMap; import java.util.Map; public class WeChatPayRefund { public static void main(String[] args) throws Exception { // 商户号 String mchId = "YOUR_MCH_ID"; // 商户密钥 String mchKey = "YOUR_MCH_KEY"; // 应用ID String appId = "YOUR_APP_ID"; // 退款证书路径 String certPath = "YOUR_CERT_PATH"; // 订单号 String orderId = "YOUR_ORDER_ID"; // 退款金额,单位为分 int refundAmount = 100; // 退款描述 String refundDesc = "退款测试"; // 初始化WXPay配置 WXPayConfigImpl config = new WXPayConfigImpl(); config.setAppID(appId); config.setMchID(mchId); config.setKey(mchKey); config.setCertPath(certPath); WXPay wxPay = new WXPay(config, WXPayConstants.SignType.HMACSHA256); // 构造退款请求参数 Map<String, String> data = new HashMap<>(); data.put("out_trade_no", orderId); data.put("out_refund_no", WXPayUtil.generateUUID()); data.put("total_fee", String.valueOf(refundAmount)); data.put("refund_fee", String.valueOf(refundAmount)); data.put("refund_desc", refundDesc); // 发起退款请求 Map<String, String> result = wxPay.refund(data); // 处理退款结果 if ("SUCCESS".equals(result.get("return_code")) && "SUCCESS".equals(result.get("result_code"))) { System.out.println("退款成功!"); } else { System.out.println("退款失败:" + result.get("return_msg")); } } } ``` 需要注意的是,退款证书需要从微信商户平台下载,并且退款金额不能大于原订单金额。另外,如果使用的是证书,需要在初始化WXPay时传入WXPayConstants.SignType.MD5或WXPayConstants.SignType.HMACSHA256。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值