微信退款

需要用到的工具類 PayCommonUtil

package com.thinkgem.jeesite.common.wechat;

import java.text.SimpleDateFormat;
import java.util.*;

public class PayCommonUtil {
	/** 
     * 是否簽名正確,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。 
     * @return boolean 
     */  
    @SuppressWarnings("unchecked")
	public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> 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(!"sign".equals(k) && null != v && !"".equals(v)) {  
                sb.append(k + "=" + v + "&");  
            }  
        }  
          
        sb.append("key=" + API_KEY);  
          
        //算出摘要  
        String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();  
        String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();  
          
        //System.out.println(tenpaySign + "    " + mysign);  
        return tenpaySign.equals(mysign);  
    }  

    /**
     * @Description:sign簽名
     * @param characterEncoding
     *          編碼格式
     * @param packageParams
     *          請求參數
     * @param API_KEY
     * @return
     */
    @SuppressWarnings("unchecked")
	public static String createSign(String characterEncoding, SortedMap<Object, Object> 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) && !"notify_url".equals(k)&& !"out_trade_no".equals(k)&& !"spbill_create_ip".equals(k)&& !"total_fee".equals(k)&& !"trade_type".equals(k)) { 
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k) ) {  
                sb.append(k + "=" + v + "&");  
            }  
        }  
        sb.append("key=" + API_KEY);  
//        String stringA="appid=wxc7b425229b570867&mch_id=1406330002&nonce_str=1702585759&key=ab42e0b7aa6bce35164a2d14855d7264";
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  
//        String sign = MD5Util.MD5Encode(stringA, characterEncoding).toUpperCase();
//        System.out.println(sign);
//        System.out.println(MD5Util.MD5Encode("appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA&key=192006250b4c09247ec02edce69f6a2d", characterEncoding).toUpperCase());
//        System.out.println(sign);
        return sign;  
    }  
  
    /** 
     * @author 
     * @date 2016-4-22 
     * @Description:將請求參數轉換爲xml格式的string 
     * @param parameters 
     *            請求參數 
     * @return 
     */  
    @SuppressWarnings("unchecked")
	public static String getRequestXml(SortedMap<Object, Object> parameters) {  
        StringBuffer sb = new StringBuffer();  
        sb.append("<xml>");  
        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 + ">" + "<![CDATA[" + v + "]]></" + k + ">");  
            } else {  
                sb.append("<" + k + ">" + v + "</" + k + ">");  
            }  
        }  
        sb.append("</xml>");  
        return sb.toString();  
    }  
  
    /** 
     * 取出一個指定長度大小的隨機正整數. 
     *  
     * @param length 
     *            int 設定所取出隨機數的長度。length小於11 
     * @return int 返回生成的隨機數。 
     */  
    public static int buildRandom(int length) {  
        int num = 1;  
        double random = Math.random();  
        if (random < 0.1) {  
            random = random + 0.1;  
        }  
        for (int i = 0; i < length; i++) {  
            num = num * 10;  
        }  
        return (int) ((random * num));  
    }  
  
    /** 
     * 獲取當前時間 yyyyMMddHHmmss 
     *  
     * @return String 
     */  
    public static String getCurrTime() {  
        Date now = new Date();  
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");  
        String s = outFormat.format(now);  
        return s;  
    }
}


package com.thinkgem.jeesite.common.wechat;

import com.thinkgem.jeesite.common.config.Global;

import java.text.DecimalFormat;
import java.util.*;

/**
 * 微信支付
 * Created by yuhaiming on 2016/11/18 0018.
 */
public class WeChatUtil {
    /**
     * 基本常量設置
     */
    /**
     * 統一下單請求路徑
     */
    public static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    /**
     * 退款請求
     */
    public static String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    /**
     * APPID
     */
    public static String APP_ID = Global.getConfig("wechat.appid");

    public static String APP_SECRET = Global.getConfig("wechat.appsecret");
    /**
     * 微信支付商戶號
     */
    public static String MCH_ID = Global.getConfig("wechat.mch_id");

    /**
     * 密匙
     */
    public static String API_KEY = Global.getConfig("wechat.key");
    /**
     * 發起支付IP
     */
    public static String CREATE_IP = "112.117.94.77";
    /**
     * 回調url
     */
    public static String NOTIFY_URL = "http://tonyyule.ngrok.wendal.cn/app/home/paySeccess";

    /**
     * 生成微信簽名
     *
     * @param order_id    訂單ID
     * @param body        描述
     * @param order_price 價格
     * @return
     */
    public static String GetWeChatXML(String order_id, String body, double order_price,String openid) {
        String currTime = PayCommonUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = PayCommonUtil.buildRandom(4) + "";
        //隨機字符串
        String nonce_str = strTime + strRandom;//UUID.randomUUID().toString();
        // 獲取發起電腦 ip
        String spbill_create_ip = WeChatUtil.CREATE_IP;
        //交易類型
        String trade_type = "JSAPI";
        //微信價格最小單位分 轉換爲整數
        DecimalFormat df = new DecimalFormat("#######.##");
        order_price = order_price * 100;
        order_price = Math.ceil(order_price);
        String price = df.format(order_price);
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        packageParams.put("appid", APP_ID);
        packageParams.put("body", body);
        packageParams.put("mch_id", MCH_ID);
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("notify_url", NOTIFY_URL);// 回調接口
        packageParams.put("out_trade_no", order_id);
        packageParams.put("spbill_create_ip", spbill_create_ip);
        packageParams.put("total_fee", price);
        packageParams.put("trade_type", trade_type);
        packageParams.put("openid", openid);//o_6gNwi23RLC97cSPfHE-DEg3OLA
        String sign = PayCommonUtil.createSign("UTF-8", packageParams, API_KEY);
        packageParams.put("sign", sign);
        String requestXML = PayCommonUtil.getRequestXml(packageParams);
//        System.out.println(requestXML);
        return requestXML;
    }

    /**
     * 微信退款初始化數據
     * @param out_trade_no
     * @param total_fee
     * @param refund_fee
     * @return
     */
    public static String RefundInit(String out_trade_no,Double total_fee,Double refund_fee){
        String refundid = UUID.randomUUID().toString();
        refundid = refundid.substring(0, 32);
        String currTime = PayCommonUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = PayCommonUtil.buildRandom(4) + "";
        //隨機字符串
        String nonce_str = strTime + strRandom;
        //價格轉換
        DecimalFormat df = new DecimalFormat("#######.##");
        total_fee = total_fee * 100;
        total_fee = Math.ceil(total_fee);
        String total_price = df.format(total_fee);

        refund_fee = refund_fee * 100;
        refund_fee = Math.ceil(refund_fee);
        String refund_price = df.format(refund_fee);

        /*-----  1.生成預支付訂單需要的的package數據-----*/
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        packageParams.put("appid", APP_ID);
        packageParams.put("mch_id", MCH_ID);
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("op_user_id", MCH_ID);//操作員帳號, 默認爲商戶號
        packageParams.put("out_trade_no", out_trade_no);
        packageParams.put("out_refund_no", refundid);
        packageParams.put("total_fee", total_price);
        packageParams.put("refund_fee", refund_price);
        /*----2.根據package生成簽名sign---- */
        String sign = PayCommonUtil.createSign("UTF-8", packageParams, API_KEY);
        packageParams.put("sign", sign);
         /*----3.拼裝需要提交到微信的數據xml---- */
        String xml = PayCommonUtil.getRequestXml(packageParams);
        return xml;
    }


    /**
     *
     * 查詢訂單初始化數據
     * @param out_trade_no
     * @return
     */
    public static String OrderQuery(String out_trade_no){
        String currTime = PayCommonUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = PayCommonUtil.buildRandom(4) + "";
        //隨機字符串
        String nonce_str = strTime + strRandom;
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        packageParams.put("appid", APP_ID);
        packageParams.put("mch_id", MCH_ID);
        packageParams.put("out_trade_no", out_trade_no);
        packageParams.put("nonce_str", nonce_str);
        /*----2.根據package生成簽名sign---- */
        String sign = PayCommonUtil.createSign("UTF-8", packageParams, API_KEY);
        packageParams.put("sign", sign);
         /*----3.拼裝需要提交到微信的數據xml---- */
        String xml = PayCommonUtil.getRequestXml(packageParams);
        return xml;
    }


}


  /**
     * 微信退款
     * @param out_trade_no
     * @param total_fee
     * @param refund_fee
     * @return
     */
    public static Map<String, String> wxRefund(String out_trade_no,Double total_fee,Double refund_fee) {
        //證書文件路徑
        String path = Global.getProjectPath() + "/pp.p12";
        Map<String, String> result = new HashMap<String, String>();
        //初始化數據
        String data = WeChatUtil.RefundInit(out_trade_no,total_fee,refund_fee);
        try {
             /*----4.讀取證書文件,這一段是直接從微信支付平臺提供的demo中copy的,所以一般不需要修改---- */
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(path));
            try {
                //證書密碼(初始是商戶 ID)
                keyStore.load(instream, WeChatUtil.MCH_ID.toCharArray());
            } finally {
                instream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WeChatUtil.MCH_ID.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,new String[] { "TLSv1" },null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom() .setSSLSocketFactory(sslsf) .build();
            HttpPost httpost = new HttpPost(WeChatUtil.REFUND_URL);
            httpost.addHeader("Connection", "keep-alive");
            httpost.addHeader("Accept", "*/*");
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpost.addHeader("Host", "api.mch.weixin.qq.com");
            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpost.addHeader("Cache-Control", "max-age=0");
            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpost);
            HttpEntity entity = response.getEntity();
            String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
            EntityUtils.consume(entity);
            result = XMLUtil.doXMLParse(jsonStr);
        } catch (Exception e) {
            result.put("returncode", "error");
            result.put("returninfo", "退款失敗");
        }
        return result;
    }





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章