微信支付 退款 工具类 直接使用

1,075次阅读
没有评论
import com.alibaba.fastjson.JSONObject;
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.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
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.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
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;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;

/**
 * @Description: 微信支付
 * @Date: 2019/5/10
 */
@Component
@Transactional(readOnly = true)
@Slf4j
public class WxPayUtil {

 

    private static String spAppid = "wxf33";   //服务商appid
    private static String merchantId = "16206"; // 服务商商户号
    private static String merchantSerialNumber = "4AE2F8FFA270";// 服务商 证书序列号
    private static String privateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC5a3MAzAMv6o3m\n" +
            "dfRCDFKktSzq+wGbmUD2AkqH8aW3H6hATBS9UlFAxdh3ars6hTd8Kxeq7GQy8ZDE\n" +
            "xGj41smLW7/56eELbdVFiEDT8TO0Qf4c58zP9Xatd04v/PjTavt0PUVTeRCvrfds\n" +
        3YddrD38kcUusjMvlh8Ve9CV/rSW\n" +
            "+MwWXGbOoXbTlVPKH1FudabglQ==";//  服务商私钥
    private static String apiV3Key = "WCnqH";// apiV3Key
    private static String subAppid = "wx81c";  //子appid
    private static String subMerchantId = "16431";  //子商户号


    /**
     * 使用AK&SK初始化账号Client
     *
     * @return Client
     * @throws Exception
     */
    public static CloseableHttpClient createClient() throws Exception {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(privateKey);
        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId,
                new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)), apiV3Key.getBytes(StandardCharsets.UTF_8));
        // ... 若有多个商户号,可继续调用putMerchant添加商户信息

        // 从证书管理器中获取verifier
        Verifier verifier = certificatesManager.getVerifier(merchantId);
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier));

        // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
//    CloseableHttpClient httpClient = builder.build();
        return builder.build();
    }

    public static String sign(String timeStamp, String nonceStr, String package1) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {

        String message = subAppid + "\n"
                + timeStamp + "\n"
                + nonceStr + "\n"
                + package1 + "\n";
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(privateKey);
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(merchantPrivateKey);
        sign.update(message.getBytes("utf-8"));

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

    /**
     * 创建订单
     * @param payNum
     * @param payPrice
     * @param notifyUrl
     * @param description
     * @param openId
     * @return
     * @throws Exception
     */

    public static JSONObject createJsApiOrder(String payNum, BigDecimal payPrice, String notifyUrl, String description, String openId) throws Exception {
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi");
        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("sp_appid", spAppid)
                .put("sp_mchid", merchantId)
                .put("sub_mchid", subMerchantId)
                .put("sub_appid", subAppid)
                .put("description", description)
                .put("notify_url", notifyUrl)
                .put("out_trade_no", payNum);
        rootNode.putObject("amount")
                .put("total",payPrice.multiply(new BigDecimal(100)).intValue() ); //  payPrice.multiply(new BigDecimal(100)).intValue();
        rootNode.putObject("payer")
                .put("sub_openid", openId);

        objectMapper.writeValue(bos, rootNode);

        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));

        CloseableHttpResponse response = createClient().execute(httpPost);

        JSONObject bodyAsString = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
        System.err.println(bodyAsString);
        JSONObject jo = new JSONObject();
        Long timeStamp = System.currentTimeMillis() / 1000;
        String nonceStr = WXPayUtil.generateNonceStr();
        jo.put("appId", spAppid);
        jo.put("timeStamp", timeStamp + "");
        jo.put("nonceStr", nonceStr);
        jo.put("package", "prepay_id=" + bodyAsString.get("prepay_id"));
        jo.put("signType", "RSA");
        jo.put("paySign", sign(timeStamp + "", nonceStr, "prepay_id=" + bodyAsString.get("prepay_id")));

        return jo;
    }

    /**
     * 解析小程序支付回调报文
     * @param request
     * @return
     * @throws IOException
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     */
    public static JSONObject parseJsApiMessage(HttpServletRequest request) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
        InputStream is = null;
        is = request.getInputStream();
        StringBuffer buf = new StringBuffer();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"));
        String line = null;
        while ((line = reader.readLine()) != null) {
            buf.append(line);
            buf.append("\r\n");
        }

        System.out.println("接收到的报文:" + buf.toString());
        JSONObject jo = JSONObject.parseObject(buf.toString());

        JSONObject jo1 = JSONObject.parseObject(jo.getString("resource"));
        String nonce = jo1.getString("nonce");
        String associatedData = jo1.getString("associated_data");
        String ciphertext = jo1.getString("ciphertext");
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        // apiV3Key
        SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
        GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));

        cipher.init(Cipher.DECRYPT_MODE, key, spec);
        cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));

        String str = new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
        return JSONObject.parseObject(str);
    }




    /**
     *  微信退款
     * @param outTradeNo  商户订单号
     * @param outRefundNo
     * @param refund
     * @param total
     * @param notifyUrl
     * @param reason
     * @return
     * @throws Exception
     */
    public static JSONObject wxRefund(String outTradeNo, String outRefundNo, BigDecimal refund, BigDecimal total, String notifyUrl, String reason) throws Exception {

        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/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("sub_mchid", subMerchantId)
                .put("out_trade_no", outTradeNo)
                .put("out_refund_no", outRefundNo)
                .put("reason", reason)
                .put("notify_url", notifyUrl);
        rootNode.putObject("amount")
                .put("refund", refund.multiply(new BigDecimal(100)).intValue())
                .put("total", total.multiply(new BigDecimal(100)).intValue())
                .put("currency", "CNY");

        objectMapper.writeValue(bos, rootNode);

        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));

        CloseableHttpResponse response = createClient().execute(httpPost);

        JSONObject bodyAsString = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
        log.info("退款返回信息开始---------------");
        log.info("退款返回信息:{}",bodyAsString);
        log.info("退款返回信息结束---------------");
        return bodyAsString;
//        if(oConvertUtils.isNotEmpty(bodyAsString.getString("status"))){
//            return bodyAsString.getString("status");
//        }else {
//            return bodyAsString.getString("message");
//        }

    }





}
正文完
 0
评论(没有评论)