第三方应用微信退款功能

项目中用到微信退款功能,简述一下

打开微信支付开发文档!api列表申请退款,注意:退款需要双向证书

下载API证书,也可以按照以下路径下载:微信商户平台(pay.weixin.qq.com)-->账户中心-->账户设置-->API安全-->证书下载

有四个文件分被是:apiclient_cert.p12;apiclient_cert.pem;apiclient_key.pem;rootca.pem java开发的只用到p12证书!将该证书复制到linux系统下某个目录下(或者windowns系统某个目录下)然后就可以开发了

直接附上代码

	/**
	 * 
	 * @Description (微信退款)
	 * @param order
	 * @return
	 */
	public static Map<String,Object> refundOrder(Order order){
		Map<String,Object> retMap = new HashMap<String,Object>();
		
		try{
			//将金额单位转换成分
    		int amount = 1;
    		if(StringUtils.isNotEmpty(String.valueOf(order.getPayMoney()))){
    			amount = (int) Math.round(Double.parseDouble(String.valueOf(order.getPayMoney()))*100);
    		}
    		
    		//获得随机字符串
    		String nonce_str = StringUtil.createNonceStr();
			
    		//组装签名字符串
    		String signStr = "appid=" + WxPayConfig.APP_ID 
					+"&mch_id=" + WxPayConfig.APP_MCH_ID
					+"&nonce_str=" + nonce_str
					+"&out_refund_no=" + order.getOrderCode()
					+"&out_trade_no=" + order.getOrderId()
					+"&refund_fee=" + amount
					+"&total_fee=" + amount
					+"&key="+ WxPayConfig.APP_MCH_APPSECRET;
			System.out.println(signStr);
			//签名最后全部转为大写
			String sign = Md5Util.MD5Encode(signStr).toUpperCase();
			
			//拼接下单xml
			StringBuffer xml = new StringBuffer();
			xml.append("<xml>");
			xml.append("<appid>").append(WxPayConfig.APP_ID).append("</appid>");
			xml.append("<mch_id>").append(WxPayConfig.APP_MCH_ID).append("</mch_id>");
			xml.append("<nonce_str>").append(nonce_str).append("</nonce_str>");
			xml.append("<out_refund_no>").append(order.getOrderCode()).append("</out_refund_no>");
			xml.append("<out_trade_no>").append(order.getOrderId()).append("</out_trade_no>");
			xml.append("<refund_fee>").append(amount).append("</refund_fee>");
			xml.append("<total_fee>").append(amount).append("</total_fee>");
			xml.append("<sign>").append(sign).append("</sign>");
			xml.append("</xml>");
			
			//请求微信下单接口
			String retXmlStr =new HttpsRequest().sendPost(WxPayConfig.REFUND_ORDER_ADDRESS, xml.toString());
			//解析返回数据
			if(StringUtils.isNotEmpty(retXmlStr)){
				retMap = XmlUtil.xmlStrParser(retXmlStr);
			}
		}catch(Exception ex){
			ex.printStackTrace();
		}
		
		return retMap;
	}

其中涉及到的工具类方法

	/**
	 * 
	 * @Title: createNonceStr 
	 * @Description: 创建
	 * @return
	 * @throws
	 */
	public static String createNonceStr(){
		String letter[] = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","S","Y","Z"};
		String nonce_str="";
		for(int i=0;i<26;i++){
			int num = new Random().nextInt(26);
			nonce_str+= letter[num];
		}
		return nonce_str;
	}
	/**
	 * MD5编码
	 * @param origin 原始字符串
	 * @return 经过MD5加密之后的结果
	 */
	public static String MD5Encode(String origin) {
	    String resultString = null;
	    try {
	        resultString = origin;
	        MessageDigest md = MessageDigest.getInstance("MD5");
	        resultString = byteArrayToHexString(md.digest(resultString.getBytes("UTF-8")));
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	    return resultString;
	}

	/**
	 * 将xml结构的字符串转换成map
	 * 
	 * @param xmlStr
	 * @return
	 */
	public static Map<String,Object> xmlStrParser(String xmlStr) {
		Map<String,Object> map = new HashMap<String,Object>();

		// 创建一个新的字符串
		StringReader read = new StringReader(xmlStr);

		// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
		InputSource source = new InputSource(read);

		// 创建一个新的SAXBuilder
		SAXBuilder sb = new SAXBuilder();

		try {
			// 通过输入源构造一个Document
			Document doc = sb.build(source);
			// 取的根元素
			Element root = doc.getRootElement();
			System.out.println(root.getName());// 输出根元素的名称(测试)

			// 得到根元素所有子元素的集合
			List jiedian = root.getChildren();

			// 获得XML中的命名空间(XML中未定义可不写)
			Namespace ns = root.getNamespace();
			Element et = null;
			for (int i = 0; i < jiedian.size(); i++) {
				et = (Element) jiedian.get(i);// 循环依次得到子元素
				// System.out.println("key/value==>" + et.getName() +"/"+
				// et.getText());
				map.put(et.getName(), et.getText());
			}

			// et = (Element) jiedian.get(0);
			// List zjiedian = et.getChildren();
			// for(int j=0;j<zjiedian.size();j++){
			// Element xet = (Element) zjiedian.get(j);
			// System.out.println(xet.getName());
			// }
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return map;
	}


加载证书以及发送请求类

package com.bluemobi.framework.utils.wxPay;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.SSLContext;

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.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;


public class HttpsRequest {
	
	private static Logger logger = Logger.getLogger(HttpsRequest.class);

    //表示请求器是否已经做了初始化工作
    private boolean hasInit = false;

    //连接超时时间,默认10秒
    private int socketTimeout = 10000;

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

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

    //HTTP请求器
    private CloseableHttpClient httpClient;

    /**
     * 构造方法
     */
    public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, NoSuchProviderException {
        init();
    }

    /***
     * 初始化https(加载证书)
	*/
    private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException , NoSuchProviderException{
    	
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(new File(WxPayConfig.CERT_LOCALPATH));//加载本地的证书进行https加密传输
        try {
            keyStore.load(instream, WxPayConfig.APP_MCH_ID.toCharArray());//设置证书密码
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } finally {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WxPayConfig.APP_MCH_ID.toCharArray()).build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"},null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
        hasInit = true;
    }

    /**
     * 通过Https往API post xml数据(post)
     *
     * @param url    API地址
     * @param xmlObj 要提交的XML数据对象
     * @return API回包的实际数据
     */
    public String sendPost(String url, String xmlObj) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, NoSuchProviderException {
        if (!hasInit) {
            init();
        }
        String result = null;
        HttpPost httpPost = new HttpPost(url);
        logger.info("API,POST过去的数据是:" + xmlObj);
        //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
        StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(postEntity);
        //设置请求器的配置
        httpPost.setConfig(requestConfig);
        logger.info("执行请求:" + httpPost.getRequestLine());
        try {
            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            result = EntityUtils.toString(entity, "UTF-8");
        } catch (ConnectionPoolTimeoutException e) {
            logger.error("http get throw ConnectionPoolTimeoutException(wait time out)");
        } catch (ConnectTimeoutException e) {
            logger.error("http get throw ConnectTimeoutException");
        } catch (SocketTimeoutException e) {
            logger.error("http get throw SocketTimeoutException");
        } catch (Exception e) {
            logger.error("http get throw Exception");
        } finally {
            httpPost.abort();
        }
        return result;
    }

    /**
     * 设置连接超时时间
     *
     * @param socketTimeouts 连接时长,默认10秒
     */
    public void setSocketTimeout(int socketTimeouts) {
        socketTimeout = socketTimeouts;
        resetRequestConfig();
    }

    /**
     * 设置传输超时时间
     *
     * @param connectTimeouts 传输时长,默认30秒
     */
    public void setConnectTimeout(int connectTimeouts) {
        connectTimeout = connectTimeouts;
        resetRequestConfig();
    }

    private void resetRequestConfig() {
        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
    }

    /**
     * 允许商户自己做更高级更复杂的请求器配置
     *
     * @param requestConfigs 设置HttpsRequest的请求器配置
     */
    public void setRequestConfig(RequestConfig requestConfigs) {
        requestConfig = requestConfigs;
    }

}

其中涉及到的包在 使用商户证书-点击(请参考微信支付提供的demo外链)下载就会有相应的jar包;主要是:httpclient-4.3.4.jar;httpcore-4.3.2.jar




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值