手把手教你微信退款

//退款的核心就是验证证书

public R refuse(HttpServletRequest request,String orderId){
   try {
      String app_id = null;
      String mch_id = null;
      String mch_key = null;
      BladeCompany bladeCompany = bladeCompanyClient.getByTenantId();
      if (null == bladeCompany){
         return R.fail("商户未设置商户号信息");
      }
      app_id = bladeCompany.getAppId();
      mch_id = bladeCompany.getMchId();
      mch_key = bladeCompany.getMchKey();
      OrderTransaction orderTransaction = orderTransactionService.
            getOne(Wrappers.<OrderTransaction>lambdaQuery()
                  .eq(OrderTransaction::getId,orderId)
                  .eq(OrderTransaction::getPayStatus,OrderTransaction.PayStatus.PAID)
                  .eq(OrderTransaction::getIsRefund,0));
      if (null == orderTransaction){
         return R.fail("订单已退款");
      }
      //获取请求ip地址
      String ip = request.getHeader("x-forwarded-for");
      if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
         ip = request.getHeader("Proxy-Client-IP");
      }
      if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
         ip = request.getHeader("WL-Proxy-Client-IP");
      }
      if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
         ip = request.getRemoteAddr();
      }
      if(ip.indexOf(",")!=-1){
         String[] ips = ip.split(",");
         ip = ips[0].trim();
      }
      String nonceStr = WXPayUtil.generateNonceStr();
      //拼接统一下单地址参数
      Map<String, String> paraMap = new HashMap<String, String>();
      paraMap.put("appid", app_id);
      paraMap.put("mch_id", mch_id);
      paraMap.put("nonce_str", nonceStr);
      paraMap.put("transaction_id", orderTransaction.getPayId());//微信订单id
      paraMap.put("out_refund_no", orderTransaction.getOrderCode());//订单号
      //把金额转换为分
      BigDecimal amount = orderTransaction.getAmount();
      amount = amount.multiply(new BigDecimal(100));
      Integer totalFee = amount.intValue();
      paraMap.put("total_fee",String.valueOf(totalFee));
      paraMap.put("refund_fee", String.valueOf(totalFee));
      String sign = WXPayUtil.generateSignature(paraMap, mch_key);
      paraMap.put("sign",sign);
      String xml = WXPayUtil.mapToXml(paraMap);
      //读取证书
      String path = "/mnt/cert/" + bladeCompany.getMchId() + "/apiclient_cert.p12";
      String refuseUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
      RefundRequest refundRequest = new RefundRequest();
      //证书验证
      String xmlStr = refundRequest.httpsRequest(refuseUrl,xml,path,mch_id);
      if (xmlStr.indexOf("SUCCESS") != -1) {
         Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
         //微信退款id
         String refundId = map.get("refund_id");
         //微信退款金额 单位:分
         BigDecimal refundFee = new BigDecimal(map.get("refund_fee"));
         refundFee = refundFee.divide(new BigDecimal(100));
         refundFee = refundFee.setScale(2,BigDecimal.ROUND_HALF_DOWN);
         return orderTransactionService.refuse(orderId,refundId,refundFee);
      }
      return R.fail("退款失败");
   }catch (Exception e){
      log.error(e.getMessage());
      return R.fail("退款失败");
   }
}

 

package com.ovu.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.*;
import java.security.cert.CertificateException;
@Slf4j
public class RefundRequest {
    //连接超时时间,默认10秒
    private int socketTimeout = 10000;

    //传输超时时间,默认30秒
    private int connectTimeout = 30000;

    //请求器的配置
    private RequestConfig requestConfig;

    //HTTP请求器
    private CloseableHttpClient httpClient;

    /**
     * 加载证书
     * @param path
     * @throws IOException
     * @throws KeyStoreException
     * @throws UnrecoverableKeyException
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    private void initCert(String path,String mchId) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
        //拼接证书的路径
        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        //加载本地的证书进行https加密传输
        FileInputStream instream = new FileInputStream(new File(path));
        try {
            keyStore.load(instream, mchId.toCharArray());  //加载证书密码,默认为商户ID
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } finally {
            instream.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, mchId.toCharArray())       //加载证书密码,默认为商户ID
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1"},
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

        httpClient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();

        //根据默认超时限制初始化requestConfig
        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();

    }


    /**
     * 通过Https往API post xml数据
     * @param url   API地址
     * @param xmlObj   要提交的XML数据对象
     * @param path    当前目录,用于加载证书
     * @param mchId 商户id
     * @return
     * @throws IOException
     * @throws KeyStoreException
     * @throws UnrecoverableKeyException
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    public String httpsRequest(String url, String xmlObj, String path,String mchId) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
        //加载证书
        initCert(path,mchId);

        String result = null;

        HttpPost httpPost = new HttpPost(url);

        //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
        StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(postEntity);

        //设置请求器的配置
        httpPost.setConfig(requestConfig);

        try {
            HttpResponse response = httpClient.execute(httpPost);

            HttpEntity entity = response.getEntity();

            result = EntityUtils.toString(entity, "UTF-8");

        } catch (ConnectionPoolTimeoutException e) {
            log.trace("http get throw ConnectionPoolTimeoutException(wait time out)");

        } catch (ConnectTimeoutException e) {
            log.trace("http get throw ConnectTimeoutException");

        } catch (SocketTimeoutException e) {
            log.trace("http get throw SocketTimeoutException");

        } catch (Exception e) {
            log.trace("http get throw Exception");

        } finally {
            httpPost.abort();
        }

        return result;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值