JAVA 微信APPV3支付(保姆级)

2024.05.07更新方法

更新WXPaySignatureCertificateUtil.java 工具类 详细看3.1

许多人对AutoUpdateCertificatesVerifier验证有疑问 

所以此次更新使用Verifier验证

这里有两种验证证书方式

AutoUpdateCertificatesVerifier和Verifier

两者自选使用

2024.02.05更新方法

去掉了重复代码 更新以下

更新验证签名方法

更新回调验签方法

更新随机字符串使用

小程序去下面

java微信小程序v3支付(保姆级)

java微信商户转账(保姆级)

现在Java微信支付文章五花八门 看不懂 看的懵 掺杂业务逻辑不知名的返回封装 爆红一片 不妨看看这篇

 由于微信更新了0.4.9版本 部分使用微信支付会解析报错 原因是微信内置了Jackson2.13.xxx依赖会与springboot这个Jackson产生冲突 可能会无法升级依赖 因为升级了也会使用老版本依赖

解决方法需要把微信支付解析 验签等方法分离重写 目前没时间写文章 无法自行解决的请私信

1.加入Maven依赖

        <!-- 微信支付V3 目前新版本-->
        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.4.9</version>
        </dependency>

2.更新创建WxV3PayConfig.java配置类 

/**
 * implements WXPayConfig
 */
@Data
public class WxV3PayConfig {

    //平台证书序列号
    public static String mchSerialNo = "xxxxxxxxxxxxxx";

    //appID
    public static String APP_ID = "xxxxxxxxxxxxxx";

    //商户id
    public static String Mch_ID = "xxxxxxxxxxxxxx";

    // API V3密钥
    public static String apiV3Key = "xxxxxxxxxxxxxx";

  

    }

3.创建WXPaySignatureCertificateUtil.java 工具类

使用AutoUpdateCertificatesVerifier验证

复制粘贴即可

/***
*
*包都在这
*
*
*
*/
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.SneakyThrows;
import org.apache.http.impl.client.CloseableHttpClient;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class WXPaySignatureCertificateUtil {




    /**
     * 证书验证
     * 自动更新的签名验证器
     */
    public static CloseableHttpClient checkSign() throws IOException {
        //验签
        CloseableHttpClient httpClient = null;
        PrivateKey merchantPrivateKey = WXPaySignatureCertificateUtil.getPrivateKey();
        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(WxV3PayConfig.Mch_ID, WxV3PayConfig.mchSerialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(WXPaySignatureCertificateUtil.getVerifier(WxV3PayConfig.mchSerialNo)))
                .build();

        return httpClient;
    }




    /**
     * 保存微信平台证书
     */
    private static final ConcurrentHashMap<String, AutoUpdateCertificatesVerifier> verifierMap = new ConcurrentHashMap<>();

    /**
     * 功能描述:获取平台证书,自动更新
     * 注意:这个方法内置了平台证书的获取和返回值解密
     */
    static AutoUpdateCertificatesVerifier getVerifier() {
        String mchSerialNo = WxV3PayConfig.mchSerialNo;
        AutoUpdateCertificatesVerifier verifier = null;
        if (verifierMap.isEmpty() || !verifierMap.containsKey(mchSerialNo)) {
            verifierMap.clear();
            try {
                 //传入证书
                 PrivateKey privateKey = getPrivateKey();
                //刷新
                PrivateKeySigner signer = new PrivateKeySigner(mchSerialNo, privateKey);
                WechatPay2Credentials credentials = new WechatPay2Credentials(WxV3PayConfig.Mch_ID, signer);
                verifier = new AutoUpdateCertificatesVerifier(credentials
                        , WxV3PayConfig.apiV3Key.getBytes("utf-8"));
                verifierMap.put(verifier.getValidCertificate().getSerialNumber()+"", verifier);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } else {
            verifier = verifierMap.get(mchSerialNo);
        }
        return verifier;
    }



    /**
     * app生成带签名支付信息
     *
     * @param timestamp 时间戳
     * @param nonceStr  随机数
     * @param prepayId  预付单
     * @return 支付信息
     * @throws Exception
     */
    public static String appPaySign(String timestamp, String nonceStr, String prepayId) throws Exception {
        //上传私钥
        PrivateKey privateKey = getPrivateKey();
        String signatureStr = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, prepayId)
                .collect(Collectors.joining("\n", "", "\n"));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    /**
     * 小程序及其它支付生成带签名支付信息
     *
     * @param timestamp 时间戳
     * @param nonceStr  随机数
     * @param prepayId  预付单
     * @return 支付信息
     * @throws Exception
     */
    public static String jsApiPaySign(String timestamp, String nonceStr, String prepayId) throws Exception {
        //上传私钥
        PrivateKey privateKey = getPrivateKey();
        String signatureStr = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, "prepay_id="+prepayId)
                .collect(Collectors.joining("\n", "", "\n"));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(sign.sign());
    }


    /**
     * 获取私钥。
     * 证书路径 本地使用如: D:\\微信平台证书工具\\7.9\\apiclient_key.pem
     * 证书路径 线上使用如: /usr/apiclient_key.pem
     * String filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey() throws IOException {
        String content = new String(Files.readAllBytes(Paths.get("D:\\微信平台证书工具\\7.9\\apiclient_key.pem")), "utf-8");
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }

}

3.1.更新创建WXPaySignatureCertificateUtil.java 工具类

使用Verifier验证

复制粘贴即可

/***
*
*包都在这
*
*
*
*/
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.SneakyThrows;
import org.apache.http.impl.client.CloseableHttpClient;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class WXPaySignatureCertificateUtil {




    private static final ConcurrentHashMap<String, Verifier> verifierMaps = new ConcurrentHashMap<>();


   /**
     * 证书验证
     * 自动更新的签名验证器
     */
    public static CloseableHttpClient checkSign() throws IOException {
        //验签
        CloseableHttpClient httpClient = null;
        PrivateKey merchantPrivateKey = WXPaySignatureCertificateUtil.getPrivateKey();
        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(WxV3PayConfig.Mch_ID, WxV3PayConfig.mchSerialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(WXPaySignatureCertificateUtil.getVerifier(WxV3PayConfig.mchSerialNo)))
                .build();

        return httpClient;
    }
        


    /**
     * 功能描述:获取平台证书,自动更新
     * 注意:这个方法内置了平台证书的获取和返回值解密
     */
    public static Verifier getVerifiers(String mchSerialNo) {
        Verifier verifier = null;
        if (verifierMaps.isEmpty() || !verifierMaps.containsKey(mchSerialNo)) {
            verifierMaps.clear();
            try {
                PrivateKey privateKey = getPrivateKey();
                //刷新
                PrivateKeySigner signer = new PrivateKeySigner(mchSerialNo, privateKey);
                WechatPay2Credentials credentials = new WechatPay2Credentials(WxV3PayConfig.Mch_ID, signer);
                verifier = new AutoUpdateCertificatesVerifier(credentials
                        , apiV3Key.getBytes("utf-8"));
                verifierMaps.put(verifier.getValidCertificate().getSerialNumber()+"", verifier);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            verifier = verifierMaps.get(mchSerialNo);
        }
        return verifier;
    }


    /**
     * app生成带签名支付信息
     *
     * @param timestamp 时间戳
     * @param nonceStr  随机数
     * @param prepayId  预付单
     * @return 支付信息
     * @throws Exception
     */
    public static String appPaySign(String timestamp, String nonceStr, String prepayId) throws Exception {
        //上传私钥
        PrivateKey privateKey = getPrivateKey();
        String signatureStr = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, prepayId)
                .collect(Collectors.joining("\n", "", "\n"));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    /**
     * 小程序及其它支付生成带签名支付信息
     *
     * @param timestamp 时间戳
     * @param nonceStr  随机数
     * @param prepayId  预付单
     * @return 支付信息
     * @throws Exception
     */
    public static String jsApiPaySign(String timestamp, String nonceStr, String prepayId) throws Exception {
        //上传私钥
        PrivateKey privateKey = getPrivateKey();
        String signatureStr = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, "prepay_id="+prepayId)
                .collect(Collectors.joining("\n", "", "\n"));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(sign.sign());
    }


    /**
     * 获取私钥。
     * 证书路径 本地使用如: D:\\微信平台证书工具\\7.9\\apiclient_key.pem
     * 证书路径 线上使用如: /usr/apiclient_key.pem
     * String filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey() throws IOException {
        String content = new String(Files.readAllBytes(Paths.get("D:\\微信平台证书工具\\7.9\\apiclient_key.pem")), "utf-8");
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }

}

创建WXPayConstants.java类


/**
 * 常量
 */
public class WXPayConstants {

    public static final String DOMAIN_API = "https://api.mch.weixin.qq.com/v3";

    //app下单
    public static final String PAY_TRANSACTIONS_APP = "/pay/transactions/app";
    

    //微信支付回调
    public static final String WECHAT_PAY_NOTIFY_URL =         
    "https://xxx.xxxx.com/deal/api/appPayment/weChatPayNotify";


    //申请退款
    public static final String REFUND_DOMESTIC_REFUNDS      = "/refund/domestic/refunds";

    //微信退款回调
    public static final String WECHAT_REFUNDS_NOTIFY_URL = "https://xxx.xxxx.com/api/appPayment/weChatPayRefundsNotify";

    //关闭订单
    public static final String PAY_TRANSACTIONS_OUT_TRADE_NO   = "/pay/transactions/out-trade-no/{}/close";

   


}

这里以APP支付和退款为例

创建WechatPaymentService.java

/**
 * @author 影子
 */
public interface WechatPaymentService
{


    /**
     * 微信商品支付
     * @param payParam
     * @return
     */
    public Map<String, Object>weChatDoUnifiedOrder() throws Exception;




    /**
     * 微信支付回调通知
     * @param
     * @return
     */
    public Map<String, Object> weChatNotificationHandler(HttpServletRequest request, HttpServletResponse response);

  /**
     *微信关闭订单
     * @param outTradeNo
     * @return
     */
    public Map<String, Object> closeOrder(String outTradeNo);




    /**
     * 申请退款
     * @param
     * @return
     */
    public Map<String, Object> weChatPayRefundsNotify(HttpServletRequest request);
 



    /**
     * 微信退款
     * @param outTradeNo 订单号
     * @return
     */
    public Map<String, Object> weChatRefunds(String outTradeNo);
}

创建WeChatPaymentServiceImpl.java

/*
*
*改了七八遍 照顾找包困难的朋友吧
*
*/
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.file.ByteArrayOutputStream;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.wxpay.sdk.WXPayUtil;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

public class WeChatPaymentServiceImpl implements WechatPaymentService {



 /**
     * V3微信支付统一下单
     *
     * @param payParam
     * @return
     * 
     */
    @Override
    public Map<String, Object>weChatDoUnifiedOrder() {
        Map<String,Object> map =new HashMap<>();
        //支付总金额
        BigDecimal totalPrice = BigDecimal.ZERO;
        totalPrice = totalPrice.add(BigDecimal.valueOf(600));
        //转换金额保留两位小数点
        Integer money=new BigDecimal(String.valueOf(totalPrice)).movePointRight(2).intValue();
            try {
                //验证证书
                CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign();
                //app下单
                HttpPost httpPost = new HttpPost(WXPayConstants.DOMAIN_API+WXPayConstants.PAY_TRANSACTIONS_APP);
                httpPost.addHeader("Accept", "application/json");
                httpPost.addHeader("Content-type", "application/json; charset=utf-8");
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectMapper objectMapper = new ObjectMapper();
                ObjectNode rootNode = objectMapper.createObjectNode();
                rootNode.put("mchid", "商户id")
                        .put("appid", "APPID")
                        .put("description","描述")
                        .put("notify_url", WXPayConstants.WECHAT_PAY_NOTIFY_URL)//回调
                        .put("out_trade_no", "订单号");
                rootNode.putObject("amount")
                        .put("total","总金额");
                objectMapper.writeValue(bos, rootNode);
                httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
                //完成签名并执行请求
                CloseableHttpResponse response = httpClient.execute(httpPost);
                //获取返回状态
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) { //处理成功
                    String result = EntityUtils.toString(response.getEntity(), "UTF-8");
                    JSONObject object = JSONObject.parseObject(result);
                    //获取预付单
                    String prepayId = object.getString("prepay_id");
                    //生成签名
                    Long timestamp = System.currentTimeMillis() / 1000;
                    //随机字符串 这个是微信支付maven自带的 也可以用其它的
                    //这个是v2支付依赖自带的工具包 可以去掉了
                    //String nonceStr = WXPayUtil.generateNonceStr();
                    //该方法org.apache.commons.lang3.RandomStringUtils依赖自带随机生成字符串 RandomStringUtils.randomAlphanumeric(32) 代表生成32位
                    String nonceStr = RandomStringUtils.randomAlphanumeric(32);
                    //生成带签名支付信息
                    String paySign = WXPaySignatureCertificateUtil.appPaySign(String.valueOf(timestamp), nonceStr, prepayId);
                    Map<String, String> param = new HashMap<>();
                    param.put("appid", WxV3PayConfig.APP_ID);
                    param.put("partnerid", WxV3PayConfig.Mch_ID);
                    param.put("prepayid", prepayId);
                    param.put("package", "Sign=WXPay");
                    param.put("noncestr", nonceStr);
                    param.put("timestamp", String.valueOf(timestamp));
                    param.put("sign", paySign);
                    map.put("code",200);
                    map.put("message", "下单成功");
                    map.put("data", param);
                    return map;
                }
                    map.put("code",200);
                    map.put("message", "下单失败");
                    map.put("data", response);
                    return map;
            } catch (Exception e) {
                e.printStackTrace();
            }
    }


    /**
     * 微信支付回调通知
     * @return
     */
    @Override
    public Map<String, Object> weChatNotificationHandler(HttpServletRequest request, HttpServletResponse response){
        Map<String,Object> map = new HashMap<>();
        try {
            BufferedReader br = request.getReader();
            String str = null;
            StringBuilder sb = new StringBuilder();
            while ((str = br.readLine())!=null) {
                sb.append(str);
            }
            // 构建request,传入必要参数
            NotificationRequest requests = new NotificationRequest.Builder()
                    .withSerialNumber(request.getHeader("Wechatpay-Serial"))
                    .withNonce(request.getHeader("Wechatpay-Nonce"))
                    .withTimestamp(request.getHeader("Wechatpay-Timestamp"))
                    .withSignature(request.getHeader("Wechatpay-Signature"))
                    .withBody(String.valueOf(sb))
                    .build();
            //验签
            NotificationHandler handler = new NotificationHandler(WXPaySignatureCertificateUtil.getVerifier(), WxV3PayConfig.apiV3Key.getBytes(StandardCharsets.UTF_8));
            //解析请求体
            Notification notification = handler.parse(requests);
            String decryptData = notification.getDecryptData();
            //解析
            JSONObject jsonObject = JSONObject.parseObject(decryptData);
            //支付状态交易状态,枚举值: SUCCESS:支付成功 REFUND:转入退款 NOTPAY:未支付 CLOSED:已关闭 REVOKED:已撤销(付款码支付)
            // USERPAYING:用户支付中(付款码支付) PAYERROR:支付失败(其他原因,如银行返回失败)
            String trade_state = String.valueOf(jsonObject.get("trade_state"));
            if (trade_state.equals("SUCCESS")) {
                //订单号
                String orderNumber = String.valueOf(jsonObject.get("out_trade_no"));
                //微信支付微信生成的订单号
                String transactionId = String.valueOf(jsonObject.get("transaction_id"));
                //省略查询订单
                //此处处理业务
                    map.put("code","SUCCESS");
                    map.put("message","成功");
                    //消息推送成功
                    return map;
                }
                map.put("code","RESOURCE_NOT_EXISTS");
                map.put("message", "订单不存在");
                return map;
            }catch (Exception e) {
            e.printStackTrace();
        }
        map.put("code","FAIL");
        map.put("message", "失败");
        return map;
    }
/**
     * 关闭订单
     * @param outTradeNo 订单号
     * @return
     */
    @Override
    public Map<String, Object> closeOrder(String outTradeNo) {
        Map<String,Object> map = new HashMap<>();
        try {
            //验证证书
                CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign();
            //关闭订单
            String url = StrFormatter.format(WXPayConstants.DOMAIN_API+WXPayConstants.PAY_TRANSACTIONS_OUT_TRADE_NO, outTradeNo);
            HttpPost httpPost = new HttpPost(url);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            //2.添加商户id
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("mchid", WxV3PayConfig.Mch_ID);
            objectMapper.writeValue(bos, rootNode);
            //3.调起微信关单接口
            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            System.out.println(response.getStatusLine().getStatusCode() == 204);
            //无数据(Http状态码为204) 微信返回结果无数据 状态码为204 成功
            if (response.getStatusLine().getStatusCode() == 204) {
                
                //code 退款码请前往微信支付文档查询
                map.put("code",200);
                map.put("message", "关闭订单成功!");
                return map;
            }
        } catch (Exception e) {
            log.error("关单失败:" + outTradeNo + e);
        }
        return null;
    }

 /**
     * 微信退款
     * @param outTradeNo 订单号
     * @return
     */
    @Override
    public Map<String, Object> weChatRefunds(String outTradeNo) {
        Map<String,Object> map = new HashMap<>();
        //退款总金额
        BigDecimal totalPrice = BigDecimal.ZERO;
        totalPrice = totalPrice.add(BigDecimal.valueOf(600));
        //转换金额
        Integer money=new BigDecimal(String.valueOf(totalPrice)).movePointRight(2).intValue();
        
        try {
            //验证证书
             CloseableHttpClient httpClient = WXPaySignatureCertificateUtil.checkSign();
            //申请退款接口
            HttpPost httpPost = new HttpPost(WXPayConstants.DOMAIN_API+WXPayConstants.REFUND_DOMESTIC_REFUNDS);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type","application/json; charset=utf-8");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode rootNode = objectMapper.createObjectNode();
            //微信支付订单号
            rootNode.put("transaction_id", "微信支付订单号")
                    //退款订单号
                    .put("out_refund_no","生成退款订单号")
                    .put("notify_url","退款回调");
                    //退款金额
            rootNode.putObject("amount")
                    .put("refund", "100.00")
                    //原订单金额
                    .put("total", "100.00")
                    .put("currency","CNY");
            objectMapper.writeValue(bos, rootNode);
            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            //退款成功返回消息
            String bodyAsString = EntityUtils.toString(response.getEntity());
            JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
            if (jsonObject.get("status").equals("SUCCESS") || jsonObject.get("status").equals("PROCESSING")) {
                //code返回
                map.put("code",200);
                map.put("message", "退款成功");
                return map;
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        map.put("code",500);
        map.put("message", "申请退款失败!");
        map.put("data", jsonObject);
        return map;
    }

    /**
     * 申请退款回调
     * @param request
     * @return
     */
    @Override
    public Map<String,Object> weChatPayRefundsNotify(HttpServletRequest request) {
        Map<String,Object> map = new HashMap<>();
        try {
            BufferedReader br = request.getReader();
            String str = null;
            StringBuilder sb = new StringBuilder();
            while ((str = br.readLine())!=null) {
                sb.append(str);
            }
            // 构建request,传入必要参数
            NotificationRequest requests = new NotificationRequest.Builder()
                    .withSerialNumber(request.getHeader("Wechatpay-Serial"))
                    .withNonce(request.getHeader("Wechatpay-Nonce"))
                    .withTimestamp(request.getHeader("Wechatpay-Timestamp"))
                    .withSignature(request.getHeader("Wechatpay-Signature"))
                    .withBody(String.valueOf(sb))
                    .build();
            //验签
            NotificationHandler handler = new NotificationHandler(WXPaySignatureCertificateUtil.getVerifier(), WxV3PayConfig.apiV3Key.getBytes(StandardCharsets.UTF_8));
            //解析请求体
            Notification notification = handler.parse(requests);
            String decryptData = notification.getDecryptData();
            //解析
            JSONObject jsonObject = JSONObject.parseObject(decryptData);
            String refund_status = String.valueOf(jsonObject.get("refund_status"));
            if (refund_status.equals("SUCCESS")) {
                //订单号
                String orderNumber = String.valueOf(jsonObject.get("out_trade_no"));
                //微信支付订单号
                String transactionId = String.valueOf(jsonObject.get("transaction_id"));

                //这里是处理业务逻辑
                
                
                //code 退款码请前往微信支付文档查询
                map.put("code","RESOURCE_NOT_EXISTS");
                map.put("message", "订单不存在");
                return map;
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        map.put("code","USER_ACCOUNT_ABNORMAL");
        map.put("message", "退款请求失败");
        return map;
    }

}

代码可复制粘贴使用 无业务逻辑代码 支付代码简洁

如果更换支付类型如:APP、二维码支付、扫码支付、JSAPI支付

请看以下示例二维码支付代码

 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3"+"/pay/transactions/native");

 HttpPost httpPost = new HttpPost("这里更换")

整体不变只需要微信返回正确状态码内处理即可 如以下返回为 二维码支付参数

            //完成签名并执行请求
                CloseableHttpResponse response = httpClient.execute(httpPost);
                //获取返回状态
                int statusCode = response.getStatusLine().getStatusCode();
           if (statusCode == 200) { //处理成功
              String result = EntityUtils.toString(response.getEntity(), "UTF-8");
              JSONObject object = JSONObject.parseObject(result);
                 map.put("code",200);
                 map.put("message", "下单成功");
                 map.put("data", object);
                 return map;
           }
                 map.put("code",500);
                 map.put("message", "下单失败");
                 map.put("data", response);
                 return map;

修改方式 根据官方文档返回参数类型为准

你学废了吗?

  • 37
    点赞
  • 120
    收藏
    觉得还不错? 一键收藏
  • 76
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 76
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值