java微信支付(統一下訂單)
阿新 • • 發佈:2019-01-05
微信支付統一下訂單:
微信公眾號配置共五個地方:
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;
}
}