1. 程式人生 > >java微信支付(統一下訂單)

java微信支付(統一下訂單)

微信支付統一下訂單:

微信公眾號配置共五個地方:

1、設定key:微信商戶平臺——賬戶設定——API安全——金鑰設定

2、頁面授權域名:用來過的openID,公眾號設定——功能設定——設定【網頁授權域名】(【js安全域名】【業務域名】也一併設定了吧)

3、設定支付目錄:微信支付——公眾號支付——設定支付目錄

4、配置回撥資訊:開發——基本配置

5、設定管理員:設定——安全中心

支付的話,設定紅字的配置即可

package com.wxpay;

import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.Random;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
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 net.sf.json.JSONObject;

import com.entity.PayOrder;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;

/**
 * 微信支付,訂單服務類
 *
 * @author muyunfei
 *
 *<p>Modification History:</p>
 *<p>Date					Author			Description</p>
 *<p>------------------------------------------------------------------</p>
 *<p>8 4, 2016			muyunfei			新建</p>
 */
public class WxOrderService {
	
	/**
	 * 建立微信同一訂單
	 * @return
	 */
	public  String createOrder(PayOrder order){
		try {
			//根據order生成訂單簽名
			if(null!=order&&(null==order.getSign()||"".equals(order.getSign()))){
				String sign = WxPayUtil.getSign(order);
				order.setSign(sign);
			}
			String orderXML = WxPayUtil.orderToXml(order);
			 CloseableHttpClient httpclient = HttpClients.createDefault();
			 HttpPost httpPost= new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");
			 //傳送json格式的資料
			 StringEntity myEntity = new StringEntity(orderXML, 
					   ContentType.create("text/plain", "UTF-8"));
			 //設定需要傳遞的資料
			 httpPost.setEntity(myEntity);
			 // Create a custom response handler
			 ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
				 //對訪問結果進行處理
				 public String handleResponse(
                       final HttpResponse response) throws ClientProtocolException, IOException {
					 int status = response.getStatusLine().getStatusCode();
					 if (status >= 200 && status < 300) {
						 HttpEntity entity = response.getEntity();
						 if(null!=entity){
							String result= EntityUtils.toString(entity);
							System.out.println(result);
                  		 	return result;
						 }else{
                       		return null;
						 }
					 } else {
						 throw new ClientProtocolException("Unexpected response status: " + status);
					 }
               }
           };
           	//返回的json物件
           String responseBody = httpclient.execute(httpPost, responseHandler);
           	System.out.println(responseBody);
			httpclient.close();
			return responseBody;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	
}
下訂單支付簽名:
package com.wxpay;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.entity.PayOrder;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;

/**
 * 微信支付,工具類
 *
 * @author muyunfei
 *
 *<p>Modification History:</p>
 *<p>Date					Author			Description</p>
 *<p>------------------------------------------------------------------</p>
 *<p>11 30, 2016			muyunfei			新建</p>
 */
public class WxPayUtil {
	
	
	/**
	 * 簽名
	 * 第一步,設所有傳送或者接收到的資料為集合M,將集合M內非空引數值的引數按照引數名ASCII碼從小到大排序(字典序),
	 * 使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字串stringA。 
	 * 特別注意以下重要規則: 
	 * ◆ 引數名ASCII碼從小到大排序(字典序); 
	 * ◆ 如果引數的值為空不參與簽名; 
	 * ◆ 引數名區分大小寫; 
	 * ◆ 驗證呼叫返回或微信主動通知簽名時,傳送的sign引數不參與簽名,將生成的簽名與該sign值作校驗。 
	 * ◆ 微信介面可能增加欄位,驗證簽名時必須支援增加的擴充套件欄位 
	 * 第二步,在stringA最後拼接上key得到stringSignTemp字串,並對stringSignTemp進行MD5運算,再將得到的字串所有字元轉換為大寫,得到sign值signValue。
	 * key設定路徑:微信商戶平臺(pay.weixin.qq.com)-->賬戶設定-->API安全-->金鑰設定
	 * @param map
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public static String getSign(Map<String,Object> map) throws UnsupportedEncodingException{
        ArrayList<String> list = new ArrayList<String>();
        for(Map.Entry<String,Object> entry:map.entrySet()){
        	//引數為空不參與簽名
            if(entry.getValue()!=""){
            	list.add(entry.getKey() + "=" + entry.getValue());
            }
        }
        int size = list.size();
        String [] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < size; i ++) {
            sb.append(arrayToSort[i]);
            if(i!=size-1){
            	sb.append("&");
            }
        }
        String result = sb.toString();
        result += "&key=" + WxUtil.key;
        //Util.log("Sign Before MD5:" + result);
        result = MD5.MD5Encode(result).toUpperCase();
        //Util.log("Sign Result:" + result);
        return result;
    }
	
	 /**
     * 簽名演算法
     * @param o 要參與簽名的資料物件
     * @return 簽名
     * @throws IllegalAccessException
     */
    public static String getSign(Object o) throws IllegalAccessException {
        ArrayList<String> list = new ArrayList<String>();
        Class cls = o.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            if (f.get(o) != null && f.get(o) != "") {
                list.add(f.getName() + "=" + f.get(o) );
            }
        }
        int size = list.size();
        String [] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < size; i ++) {
            sb.append(arrayToSort[i]);
            if(i!=size-1){
            	sb.append("&");
            }
        }
        String result = sb.toString();
        result += "&key=" + WxUtil.key;
        result = MD5.MD5Encode(result).toUpperCase();
        return result;
    }
    

	
	
	/**
	 * 生成隨機字串
	 * @param length
	 * @return
	 */
	public static String getRandomString2(int length){  
        Random random = new Random();  
          
        StringBuffer sb = new StringBuffer();  
          
        for(int i = 0; i < length; ++i){  
            int number = random.nextInt(3);  
            long result = 0;  
              
            switch(number){  
            case 0:  
                result = Math.round(Math.random() * 25 + 65);  
                sb.append(String.valueOf((char)result));  
                break;  
            case 1:  
                result = Math.round(Math.random() * 25 + 97);  
                sb.append(String.valueOf((char)result));  
                break;  
            case 2:  
                sb.append(String.valueOf(new Random().nextInt(10)));  
                break;  
            }  
        }  
        return sb.toString();     
    }  
    
    
    /**
     * 獲取xml資訊
     * @param xmlString
     * @return
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public static Map<String,Object> getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException {

        //這裡用Dom的方式解析回包的最主要目的是防止API新增回包欄位
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputStream is = null;
        if (xmlString != null && !xmlString.trim().equals("")) {
        	is = new ByteArrayInputStream(xmlString.getBytes("utf-8"));
        }
        Document document = builder.parse(is);

        //獲取到document裡面的全部結點
        NodeList allNodes = document.getFirstChild().getChildNodes();
        Node node;
        Map<String, Object> map = new HashMap<String, Object>();
        int i=0;
        while (i < allNodes.getLength()) {
            node = allNodes.item(i);
            if(node instanceof Element){
                map.put(node.getNodeName(),node.getTextContent());
            }
            i++;
        }
        return map;

    }
	

	/**
	 * 擴充套件xstream使其支援CDATA
	 * 內部類XppDriver
	 */
	private static XStream xstream = new XStream(new XppDriver() {
		public HierarchicalStreamWriter createWriter(Writer out) {
			return new PrettyPrintWriter(out) {
				// 對所有xml節點的轉換都增加CDATA標記
				boolean cdata = true;
				public void startNode(String name, Class clazz) {
					super.startNode(name, clazz);
				}
				protected void writeText(QuickWriter writer, String text) {
					if (cdata) {
						//writer.write("<![CDATA[");
						writer.write(text);
						//writer.write("]]>");
					} else {
						writer.write(text);
					}
				}
			};
		}
	});

	/**
	 * 文字訊息物件轉換成xml
	 * 
	 * @param textMessage 文字訊息物件
	 * @return xml
	 */
	public static String orderToXml(PayOrder order) {
		xstream.alias("xml", order.getClass());
		String xmlStr=xstream.toXML(order);
		xmlStr=xmlStr.replaceAll("__", "_");
		return xmlStr;
	}
}
訂單實體類:
package com.entity;

public class PayOrder {
	
	private String appid; //微信分配的公眾賬號ID
	private String mch_id;//微信支付分配的商戶號
	private String nonce_str ;//隨機字串,不長於32位
	private String sign;//簽名
	private String body;//商品簡單描述 不長於128位
	private String detail;//商品詳細 不長於6000位,商品詳細列表,使用Json格式,傳輸簽名前請務必使用CDATA標籤將JSON文字串保護起來。可以不填
	private String out_trade_no;//商戶訂單號 32個字元內
	private String total_fee;//訂單總金額,單位為分
	private String spbill_create_ip; //APP和網頁支付提交使用者端ip,Native支付填呼叫微信支付API的機器IP
	private String notify_url;//接收微信支付非同步通知回撥地址,通知url必須為直接可訪問的url,不能攜帶引數。
	private String trade_type;//交易型別 取值如下:JSAPI,NATIVE,APP
	private String limit_pay;//指定支付方式  no_credit--指定不能使用信用卡支付,可以不填
	private String openid;//使用者標識,trade_type=JSAPI,此引數必傳,使用者在商戶appid下的唯一標識。openid如何獲取
	
	public PayOrder(){};
	
	public PayOrder(String appid, String mchId, String nonceStr, String sign,
			String body, String detail, String outTradeNo, String totalFee,
			String spbillCreateIp, String notifyUrl, String tradeType,
			String limitPay, String openid) {
		super();
		this.appid = appid;
		mch_id = mchId;
		nonce_str = nonceStr;
		this.sign = sign;
		this.body = body;
		this.detail = detail;
		out_trade_no = outTradeNo;
		total_fee = totalFee;
		spbill_create_ip = spbillCreateIp;
		notify_url = notifyUrl;
		trade_type = tradeType;
		limit_pay = limitPay;
		this.openid = openid;
	}
	public String getAppid() {
		return appid;
	}
	public void setAppid(String appid) {
		this.appid = appid;
	}
	public String getMch_id() {
		return mch_id;
	}
	public void setMch_id(String mchId) {
		mch_id = mchId;
	}
	public String getNonce_str() {
		return nonce_str;
	}
	public void setNonce_str(String nonceStr) {
		nonce_str = nonceStr;
	}
	public String getSign() {
		return sign;
	}
	public void setSign(String sign) {
		this.sign = sign;
	}
	public String getBody() {
		return body;
	}
	public void setBody(String body) {
		this.body = body;
	}
	public String getDetail() {
		return detail;
	}
	public void setDetail(String detail) {
		this.detail = detail;
	}
	public String getOut_trade_no() {
		return out_trade_no;
	}
	public void setOut_trade_no(String outTradeNo) {
		out_trade_no = outTradeNo;
	}
	public String getTotal_fee() {
		return total_fee;
	}
	public void setTotal_fee(String totalFee) {
		total_fee = totalFee;
	}
	public String getSpbill_create_ip() {
		return spbill_create_ip;
	}
	public void setSpbill_create_ip(String spbillCreateIp) {
		spbill_create_ip = spbillCreateIp;
	}
	public String getNotify_url() {
		return notify_url;
	}
	public void setNotify_url(String notifyUrl) {
		notify_url = notifyUrl;
	}
	public String getTrade_type() {
		return trade_type;
	}
	public void setTrade_type(String tradeType) {
		trade_type = tradeType;
	}
	public String getLimit_pay() {
		return limit_pay;
	}
	public void setLimit_pay(String limitPay) {
		limit_pay = limitPay;
	}
	public String getOpenid() {
		return openid;
	}
	public void setOpenid(String openid) {
		this.openid = openid;
	}
	
	
	
}

MD5加密:
package com.wxpay;

import java.security.MessageDigest;

/**
 * 微信支付
 *
 * @author muyunfei
 *
 *<p>Modification History:</p>
 *<p>Date					Author			Description</p>
 *<p>------------------------------------------------------------------</p>
 *<p>8 4, 2016			muyunfei			新建</p>
 */
public class MD5 {
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * 轉換位元組陣列為16進位制字串
     * @param b 位元組陣列
     * @return 16進位制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
        	System.out.println(aB);
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }

    /**
     * 轉換byte到16進位制
     * @param b 要轉換的byte
     * @return 16進位制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * MD5編碼
     * @param origin 原始字串
     * @return 經過MD5加密之後的結果
     */
    public static String MD5Encode(String origin) {
    	System.out.println(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;

    }


}