SpringBoot 微信退款

一:微信支付证书配置

SpringBoot 微信退款_第1张图片

二:证书读取以及读取后的使用

package com.zhx.guides.assistant.config.wechatpay;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
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 org.springframework.core.io.ClassPathResource;

import javax.net.ssl.SSLContext;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;

/**
 * @Class WeChatConfigUtil
 * @Version 1.0
 * @Date 创建时间:2020-06-15 16:19
 * @Copyright Copyright by 
 * @Direction 类说明
 */
public class WeChatConfigUtil {

    private static byte[] certData;

    /****
     * @throws Exception
     */
    static {
        try {
            //从微信商户平台下载的安全证书存放的目录
            //String certPath = "D:\\config\\apiclient_cert.p12";
            //File file = new File(certPath);
            //InputStream certStream = new FileInputStream(file);
            //使用springboot配置文件内读取的方式
            ClassPathResource classPathResource = new ClassPathResource("\\user_key\\apiclient_cert.p12");
            InputStream certStream = classPathResource.getInputStream();
            WeChatConfigUtil.certData = IOUtils.toByteArray(certStream);
            certStream.read(WeChatConfigUtil.certData);
            certStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始退款操作
     *
     * @param mchId 商户ID
     * @param url   请求URL
     * @param data  退款参数
     * @return
     * @throws Exception
     */
    public static String doRefund(String mchId, String url, String data) throws Exception {
        /**
         * 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
         */
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        //这里自行实现我是使用数据库配置将证书上传到了服务器可以使用 FileInputStream读取本地文件
        //ByteArrayInputStream inputStream = FileUtil.getInputStream("https://############################.p12");
        ByteArrayInputStream inputStream = new ByteArrayInputStream(WeChatConfigUtil.certData);
        try {
            //这里写密码..默认是你的MCHID
            keyStore.load(inputStream, mchId.toCharArray());
        } finally {
            inputStream.close();
        }
        SSLContext sslcontext = SSLContexts.custom()
                //这里也是写密码的
                .loadKeyMaterial(keyStore, mchId.toCharArray())
                .build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();
        try {
            HttpPost httpost = new HttpPost(url);
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                HttpEntity entity = response.getEntity();
                //接受到返回信息
                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                EntityUtils.consume(entity);
                return jsonStr;
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

}

三:发起订单退款操作

/**
 * 封装查询请求数据
 * @param tradeRefund 	退款订单请求信息
 * @param path				数据访问PATH
 * @return
 */
private static SortedMap refundData( TradeRefund tradeRefund , String path ) throws Exception {
	//构建参数
	Map dataMap = new HashMap<>();
	dataMap.put("appid","wx#################");
	dataMap.put("mch_id","137#############");
	//自行实现该随机串
	dataMap.put("nonce_str",Core.MD5("12344"));
	dataMap.put("out_trade_no","P190808170038402889c5318502");
	dataMap.put("out_refund_no","P190808170038402889c5318502");
	dataMap.put("total_fee","1");
	dataMap.put("refund_fee","1");
	dataMap.put("refund_desc","退款");
	//生成签名
	String sign = PayToolUtil.createSign("UTF-8", dataMap , WeichatPayConfigure.API_KEY );
	//WXPayUtil.generateSignature(dataMap, "rv4###################");
	dataMap.put("sign", sign);
	//map数据转xml
	String requestXML = getRequestXml( dataMap );
	logger.info( "订单退款请求参数:\n"  + requestXML );
	//发起退款
	String responseXml = WeChatConfigUtil.doRefund( WeichatPayConfigure.MCH_ID , "https://api.mch.weixin.qq.com/secapi/pay/refund", requestXML );
}

/** 
 * @author 
 * @date 2016-4-22 
 * @Description:将请求参数转换为xml格式的string 
 * @param parameters 
 *            请求参数 
 * @return 
 */  
public static String getRequestXml(SortedMap parameters) {  
	StringBuffer sb = new StringBuffer();  
	sb.append("");  
	Set es = parameters.entrySet();  
	Iterator it = es.iterator();  
	while (it.hasNext()) {  
		Map.Entry entry = (Map.Entry) it.next();  
		String k = (String) entry.getKey();  
		String v = (String) entry.getValue();  
		if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {  
			sb.append("<" + k + ">" + "");  
		} else {  
			sb.append("<" + k + ">" + v + "");  
		}  
	}  
	sb.append("");  
	return sb.toString();  
}  
/** 
 * @author 
 * @date 2016-4-22 
 * @Description:sign签名 
 * @param characterEncoding 
 *            编码格式 
 * @param packageParams
 *            请求参数 
 * @return 
 */  
public static String createSign(String characterEncoding, SortedMap packageParams, String API_KEY) {  
	StringBuffer sb = new StringBuffer();  
	Set es = packageParams.entrySet();  
	Iterator it = es.iterator();  
	while (it.hasNext()) {  
		Map.Entry entry = (Map.Entry) it.next();  
		String k = (String) entry.getKey();  
		String v = (String) entry.getValue();  
		if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {  
			sb.append(k + "=" + v + "&");  
		}  
	}  
	sb.append("key=" + API_KEY);  
	String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  
	return sign;  
}  
package com.zhx.guides.assistant.interfaces.pay.wechatpay.util;

import java.security.MessageDigest;

public class MD5Util {
	
    private static String byteArrayToHexString(byte b[]) {  
        StringBuffer resultSb = new StringBuffer();  
        for (int i = 0; i < b.length; i++)  
            resultSb.append(byteToHexString(b[i]));  
  
        return resultSb.toString();  
    }  
  
    private static String byteToHexString(byte b) {  
        int n = b;  
        if (n < 0)  
            n += 256;  
        int d1 = n / 16;  
        int d2 = n % 16;  
        return hexDigits[d1] + hexDigits[d2];  
    }  
  
    public static String MD5Encode(String origin, String charsetname) {  
        String resultString = null;  
        try {  
            resultString = new String(origin);  
            MessageDigest md = MessageDigest.getInstance("MD5");  
            if (charsetname == null || "".equals(charsetname))  
                resultString = byteArrayToHexString(md.digest(resultString  
                        .getBytes()));  
            else  
                resultString = byteArrayToHexString(md.digest(resultString  
                        .getBytes(charsetname)));  
        } catch (Exception exception) {  
        }  
        return resultString;  
    }  
  
    /***
     * 简化版本
     * @param s
     * @return
     */
    public final static String MD5(String s) {
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
		try {
			byte[] btInput = s.getBytes("utf-8");
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			mdInst.update(btInput);
			// 获得密文
			byte[] md = mdInst.digest();
			// 把密文转换成十六进制的字符串形式
			int j = md.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
    
    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",  
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };  

}
/** 
 * @author 
 * @date 2016-4-22 
 * @Description:将请求参数转换为xml格式的string 
 * @param parameters 
 *            请求参数 
 * @return 
 */  
public static String getRequestXml(SortedMap parameters) {  
	StringBuffer sb = new StringBuffer();  
	sb.append("");  
	Set es = parameters.entrySet();  
	Iterator it = es.iterator();  
	while (it.hasNext()) {  
		Map.Entry entry = (Map.Entry) it.next();  
		String k = (String) entry.getKey();  
		String v = (String) entry.getValue();  
		if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {  
			sb.append("<" + k + ">" + "");  
		} else {  
			sb.append("<" + k + ">" + v + "");  
		}  
	}  
	sb.append("");  
	return sb.toString();  
}  

四:请求XML示例


   wx2421b1c4370ec43b
   10000100
   6cefdb308e1e2e8aabd48cf79e546a02 
   1415701182
   1415757673
   1
   1
   
   FE56DD4AA85C0EECA82C35595A69E153

五:官方信息

官方地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4

需注意这两个参数我使用的是out_trade_no

SpringBoot 微信退款_第2张图片

六:依赖类信息

 


import java.io.Serializable;

import org.apache.http.Header;

/**
 * @Class HttpClientResponse
 * @Author
 * @Version 1.0
 * @Date 创建时间:2019-04-23 15:11
 * @Copyright Copyright by company
 * @Direction 类说明
 */
public class HttpClientResponse implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private String body ;
	private Header[] headers ;
	private String reasonPhrase ;
	private int statusCode ;
	
	public String getBody() {
		return body;
	}
	public void setBody(String body) {
		this.body = body;
	}
	public Header[] getHeaders() {
		return headers;
	}
	public void setHeaders(Header[] headers) {
		this.headers = headers;
	}
	public String getReasonPhrase() {
		return reasonPhrase;
	}
	public void setReasonPhrase(String reasonPhrase) {
		this.reasonPhrase = reasonPhrase;
	}
	public int getStatusCode() {
		return statusCode;
	}
	public void setStatusCode(int statusCode) {
		this.statusCode = statusCode;
	}
	
}

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Class HttpClientResponse
 * @Author 
 * @Version 1.0
 * @Date 创建时间:2019-04-23 15:11
 * @Copyright Copyright by company
 * @Direction 类说明
 */
public class HttpClientUtil {    
        
    /**  
     * 发送http get请求  
     */    
    public static HttpClientResponse httpGet(String url, Map headers, String encode){
        HttpClientResponse response = new HttpClientResponse();
        if(encode == null){
            encode = "utf-8";
        }
        String content = null;
        //since 4.3 不再使用 DefaultHttpClient
        CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build();
        HttpGet httpGet = new HttpGet(url);
        //设置header
        if (headers != null && headers.size() > 0) {
            for (Map.Entry entry : headers.entrySet()) {
                httpGet.setHeader(entry.getKey(),entry.getValue());
            }
        }
        CloseableHttpResponse httpResponse = null;
        try {
            httpResponse = closeableHttpClient.execute(httpGet);
            HttpEntity entity = httpResponse.getEntity();
            content = EntityUtils.toString(entity, encode);
            response.setBody(content);
            response.setHeaders(httpResponse.getAllHeaders());
            response.setReasonPhrase(httpResponse.getStatusLine().getReasonPhrase());
            response.setStatusCode(httpResponse.getStatusLine().getStatusCode());
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                httpResponse.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {  //关闭连接、释放资源
            closeableHttpClient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response;
    }
    /**
     * 发送 http post 请求,参数以form表单键值对的形式提交。
     */
    public static HttpClientResponse httpPostForm(String url,Map params, Map headers,String encode)throws Exception{
        HttpClientResponse response = new HttpClientResponse();
        if(encode == null){
            encode = "utf-8";
        }
        //HttpClients.createDefault()等价于 HttpClientBuilder.create().build();
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        HttpPost httpost = new HttpPost(url);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(1000).setConnectTimeout(1500).build();//设置请求和传输超时时间
        httpost.setConfig( requestConfig );
        //设置header
        if (headers != null && headers.size() > 0) {
            for (Map.Entry entry : headers.entrySet()) {
                httpost.setHeader(entry.getKey(),entry.getValue());
            }
        }
        //组织请求参数
        List paramList = new ArrayList ();
        if(params != null && params.size() > 0){
            Set keySet = params.keySet();
            for(String key : keySet) {
                paramList.add(new BasicNameValuePair(key, params.get(key)));
            }
        }
        try {
            httpost.setEntity(new UrlEncodedFormEntity(paramList, encode));
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        String content = null;
        CloseableHttpResponse  httpResponse = null;
        try {
            httpResponse = closeableHttpClient.execute(httpost);
            HttpEntity entity = httpResponse.getEntity();
            content = EntityUtils.toString(entity, encode);
            response.setBody(content);
            response.setHeaders(httpResponse.getAllHeaders());
            response.setReasonPhrase(httpResponse.getStatusLine().getReasonPhrase());
            response.setStatusCode(httpResponse.getStatusLine().getStatusCode());
        } catch (Exception e) {
            throw e ;
        }finally{
            try {
                httpResponse.close();
            } catch (IOException e) {}
        }
        try {  //关闭连接、释放资源
            closeableHttpClient.close();
        } catch (IOException e) {}
        return response;
    }

    /**
     * 发送 http post 请求,参数以原生字符串进行提交
     * @param url
     * @param encode
     * @return
     */
    public static HttpClientResponse httpPostRaw(String url,String stringJson,Map headers, String encode)throws Exception{
        HttpClientResponse response = new HttpClientResponse();
        if(encode == null){
            encode = "utf-8";
        }
        //HttpClients.createDefault()等价于 HttpClientBuilder.create().build();
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        HttpPost httpost = new HttpPost(url);
        //设置超时信息
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();//设置请求和传输超时时间
        httpost.setConfig(requestConfig);

        //设置header
        httpost.setHeader("Content-type", "application/json");
        if (headers != null && headers.size() > 0) {
            for (Map.Entry entry : headers.entrySet()) {
                httpost.setHeader(entry.getKey(),entry.getValue());
            }
        }
        //组织请求参数
        StringEntity stringEntity = new StringEntity(stringJson, encode);
        httpost.setEntity(stringEntity);
        String content = null;
        CloseableHttpResponse  httpResponse = null;
        try {
            //响应信息
            httpResponse = closeableHttpClient.execute(httpost);
            HttpEntity entity = httpResponse.getEntity();
            content = EntityUtils.toString(entity, encode);
            response.setBody(content);
            response.setHeaders(httpResponse.getAllHeaders());
            response.setReasonPhrase(httpResponse.getStatusLine().getReasonPhrase());
            response.setStatusCode(httpResponse.getStatusLine().getStatusCode());
        } catch (Exception e) {
           throw e ;
        }finally{
            try {
                httpResponse.close();
            } catch (Exception e) {}
        }
        try {  //关闭连接、释放资源
            closeableHttpClient.close();
        } catch (Exception e) {
        }
        return response;
    }

    /**
     * 发送 http put 请求,参数以原生字符串进行提交
     * @param url
     * @param encode
     * @return
     */
    public static HttpClientResponse httpPutRaw(String url,String stringJson,Map headers, String encode){
        HttpClientResponse response = new HttpClientResponse();
        if(encode == null){
            encode = "utf-8";
        }
        //HttpClients.createDefault()等价于 HttpClientBuilder.create().build();
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        HttpPut httpput = new HttpPut(url);

        //设置header
        httpput.setHeader("Content-type", "application/json");
        if (headers != null && headers.size() > 0) {
            for (Map.Entry entry : headers.entrySet()) {
                httpput.setHeader(entry.getKey(),entry.getValue());
            }
        }
        //组织请求参数
        StringEntity stringEntity = new StringEntity(stringJson, encode);
        httpput.setEntity(stringEntity);
        String content = null;
        CloseableHttpResponse  httpResponse = null;
        try {
            //响应信息
            httpResponse = closeableHttpClient.execute(httpput);
            HttpEntity entity = httpResponse.getEntity();
            content = EntityUtils.toString(entity, encode);
            response.setBody(content);
            response.setHeaders(httpResponse.getAllHeaders());
            response.setReasonPhrase(httpResponse.getStatusLine().getReasonPhrase());
            response.setStatusCode(httpResponse.getStatusLine().getStatusCode());
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                httpResponse.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            closeableHttpClient.close();  //关闭连接、释放资源
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response;
    }

        
}
Maven 引用


	commons-httpclient
	commons-httpclient
	3.1

 

你可能感兴趣的:(spring,boot,微信退款,springboot,微信退款)