微信支付退款开发

作者: 呼噜噜睡 | 来源:发表于2020-02-26 15:59 被阅读0次

    微信退款开发需要的步骤比较多,首先是按照官方文档生成证书,下载下来是一个zip。有时候会很疑惑,这个证书怎么用?实际上呢,就是发送接口的时候带上证书就可了。看一个具体的例子吧,以JSAPI微信退款为例。
    1、首先是发起退款申请
    因为每次发起退款请求,都要带上证书,如果直接从证书文件读取内容,速度很慢,因此将证书内容存放于内存中。大致如下:

    @Getter
    @Configuration
    public class WxConfig {
        /**
         * 微信支付,证书存放父路径  证书名称:商户id_cert.p12  商户id_cert.pem  商户id_key.pem
         */
        @Value("${wx.apiCertLocation}")
        private String apiCertLocation;
    
        /**
         * 从 商户id_cert.p12文件读取内容,放入字节数组。(不要每次都从io中获取数据,太慢)
         */
        private byte [] certData;
    
        /**
         * 将商户id_cert.p12文件内容转换成流
         * @return
         */
        public InputStream getCertStream() throws IOException {
            if(certData==null||certData.length==0){
                InputStream certStream = new FileInputStream(apiCertLocation+mchId+"_cert.p12");
                this.certData = IOUtils.toByteArray(certStream);
                certStream.close();
            }
            return new ByteArrayInputStream(this.certData);
        }
    }
    

    下面就是发送带证书的请求了:

            InputStream certStream = wxConfig.getCertStream();
            String xmlResult = requestWithApiCert(REFUND_URL,xmlStr,mchId(),certStream);
            certStream.close();
    

    具体的工具类:

    /**
         * 微信支付 带API证书的请求
         * @return
         * @throws Exception
         */
        public static String requestWithApiCert(String url,  String data, String mchId,InputStream certStream) throws Exception {
            BasicHttpClientConnectionManager connManager;
            // 证书
            char[] password = mchId.toCharArray();
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(certStream, password);
            // 实例化密钥库 & 初始化密钥工厂
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(ks, password);
            // 创建 SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                    sslContext,
                    new String[]{"TLSv1"},
                    null,
                    new DefaultHostnameVerifier());
            connManager = new BasicHttpClientConnectionManager(
                    RegistryBuilder.<ConnectionSocketFactory>create()
                            .register("http", PlainConnectionSocketFactory.getSocketFactory())
                            .register("https", sslConnectionSocketFactory)
                            .build(),
                    null,
                    null,
                    null
            );
            HttpClient httpClient = HttpClientBuilder.create()
                    .setConnectionManager(connManager)
                    .build();
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().build();
            httpPost.setConfig(requestConfig);
            StringEntity postEntity = new StringEntity(data, "UTF-8");
            httpPost.addHeader("Content-Type", "text/xml");
            httpPost.setEntity(postEntity);
            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            return EntityUtils.toString(httpEntity, "UTF-8");
        }
    

    微信退款回调中,有一个req_info字段,需要解密才可以使用:

    /**
         * 注意此方法 如果报错:Illegal key size or default parameters   
    一般需要到oracle官网下载local_policy.jar US_export_policy.jar 
    包进行替换,路径:jdk安装路径/jre/lib/security
         * @param reqInfo
         * @param apiKey
         * @return reqInfo的xml字符串
         * @throws Exception
         */
        public static String getReqInfoXml(String reqInfo,String apiKey) throws Exception{
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(apiKey.getBytes());
            String keyMd5String = (new BigInteger(1, md5.digest())).toString(16).toLowerCase();
            SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(), "AES");
            cipher.init(2, key);
            return new String(cipher.doFinal(Base64.decodeBase64(reqInfo)));
        }
    

    至此,就完毕了。

    相关文章

      网友评论

        本文标题:微信支付退款开发

        本文链接:https://www.haomeiwen.com/subject/qekbchtx.html