1、準備基本配置信息(即在微信支付平臺申請的APP_ID、APP_SECRET、PARTNER、PARTNER_KEY)php
//微信支付標識 public static final String APP_ID="xxxxx"; //微信支付密鑰 public static final String APP_SECRET="xxxxxx"; //商戶號支付密鑰 public static final String PARTNER_KEY="xxxxx"; //商戶號 public static final String PARTNER="xxxx";
2、調用微信支付平臺中的統一下單API,進行下單處理(參數簽名、生成支付ID等信息給客戶端),參數說明參照,官網說明html
3、如何在服務端進行下單操做:java
1.構建微信支付服務器簽名支付請求請求類node
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.*; /* '微信支付服務器簽名支付請求請求類 '============================================================================ 'api說明: 'init(app_id, app_secret, partner_key, app_key); '初始化函數,默認給一些參數賦值,如cmdno,date等。 'setKey(key_)'設置商戶密鑰 'getLasterrCode(),獲取最後錯誤號 'GetToken();獲取Token 'getTokenReal();Token過時後實時獲取Token 'createMd5Sign(signParams);生成Md5簽名 'genPackage(packageParams);獲取package包 'createSHA1Sign(signParams);建立簽名SHA1 'sendPrepay(packageParams);提交預支付 'getDebugInfo(),獲取debug信息 '============================================================================ '*/ public class RequestHandler { /** Token獲取網關地址地址 */ private String tokenUrl; /** 預支付網關url地址 */ private String gateUrl; /** 查詢支付通知網關URL */ private String notifyUrl; /** 商戶參數 */ private String appid; private String appkey; private String partnerkey; private String appsecret; private String key; /** 請求的參數 */ private SortedMap parameters; /** Token */ private String Token; private String charset; /** debug信息 */ private String debugInfo; private String last_errcode; private HttpServletRequest request; private HttpServletResponse response; /** * 初始構造函數。 * * @return */ public RequestHandler(HttpServletRequest request, HttpServletResponse response) { this.last_errcode = "0"; this.request = request; this.response = response; //this.charset = "GBK"; this.charset = "UTF-8"; this.parameters = new TreeMap(); // 驗證notify支付訂單網關 notifyUrl = "https://gw.tenpay.com/gateway/simpleverifynotifyid.xml"; } /** * 初始化函數。 */ public void init(String app_id, String app_secret, String partner_key) { this.last_errcode = "0"; this.Token = "token_"; this.debugInfo = ""; this.appid = app_id; this.partnerkey = partner_key; this.appsecret = app_secret; this.key = partner_key; } public void init() { } /** * 獲取最後錯誤號 */ public String getLasterrCode() { return last_errcode; } /** *獲取入口地址,不包含參數值 */ public String getGateUrl() { return gateUrl; } /** * 獲取參數值 * * @param parameter * 參數名稱 * @return String */ public String getParameter(String parameter) { String s = (String) this.parameters.get(parameter); return (null == s) ? "" : s; } //設置密鑰 public void setKey(String key) { this.partnerkey = key; } //設置微信密鑰 public void setAppKey(String key){ this.appkey = key; } // 特殊字符處理 public String UrlEncode(String src) throws UnsupportedEncodingException { return URLEncoder.encode(src, this.charset).replace("+", "%20"); } // 獲取package的簽名包 public String genPackage(SortedMap<String, String> packageParams,String partnerkey) throws UnsupportedEncodingException { String sign = createSign(packageParams,partnerkey); 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(); sb.append(k + "=" + UrlEncode(v) + "&"); } // 去掉最後一個& String packageValue = sb.append("sign=" + sign).toString(); // System.out.println("UrlEncode後 packageValue=" + packageValue); return packageValue; } /** * 建立md5摘要,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。 */ public String createSign(SortedMap<String, String> packageParams,String partnerkey) { 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=" + partnerkey); System.out.println("md5 sb:" + sb+"key="+this.getKey()); String sign = MD5Util.MD5Encode(sb.toString(), this.charset) .toUpperCase(); System.out.println("packge簽名:" + sign); return sign; } /** * 建立package簽名 */ public boolean createMd5Sign(String signParams) { StringBuffer sb = new StringBuffer(); Set es = this.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 (!"sign".equals(k) && null != v && !"".equals(v)) { sb.append(k + "=" + v + "&"); } } // 算出摘要 String enc = TenpayUtil.getCharacterEncoding(this.request, this.response); String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase(); String tenpaySign = this.getParameter("sign").toLowerCase(); // debug信息 this.setDebugInfo(sb.toString() + " => sign:" + sign + " tenpaySign:" + tenpaySign); return tenpaySign.equals(sign); } //輸出XML public String parseXML() { StringBuffer sb = new StringBuffer(); sb.append("<xml>"); Set es = this.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(null != v && !"".equals(v) && !"appkey".equals(k)) { sb.append("<" + k +">" + getParameter(k) + "</" + k + ">\n"); } } sb.append("</xml>"); return sb.toString(); } /** * 設置debug信息 */ protected void setDebugInfo(String debugInfo) { this.debugInfo = debugInfo; } public void setPartnerkey(String partnerkey) { this.partnerkey = partnerkey; } public String getDebugInfo() { return debugInfo; } public String getKey() { return partnerkey; } }
2.構建微信支付簽名參數git
private String weiPaySignParams(String imei, String reqIP, RequestHandler reqHandler, String remoteAddr, String orderNo, ThirdOrderInfoObj thirdOrderObj, WeUserModel weUserModel, String goodsOrderToken) { String result = ""; try { //接收財付統統知的URL 即訂單支付完成回調地址 String notify_url = SysUtil.readPro("weiPayV3.callback.path"); //金額轉化爲分爲單位 String finalmoney = (int)(thirdOrderObj.getPayprice()*100)+""; WeiPayObj weiPayObj = new WeiPayObj(orderNo,notify_url,orderNo,finalmoney,remoteAddr,"商品購買") ; WeiPayObj resultWeiPayObj = WeiPaySignUtils.weiPaySign(weiPayObj,reqHandler); int addResult = OrderUtils.createOrder(imei,reqIP,"weiPay", orderNo, "", resultWeiPayObj.getFinalSign(),thirdOrderObj,weUserModel,goodsOrderToken); if(addResult>0){ result = OrderUtils.printJson(1, "上報成功", WeiPayConfig.APP_ID, WeiPayConfig.PARTNER, "Sign=WXPay", resultWeiPayObj.getNonceStr(), resultWeiPayObj.getTimestamp(), resultWeiPayObj.getPrepayId(), resultWeiPayObj.getFinalSign(), orderNo, "", thirdOrderObj.getOrdernum()); }else{ result = "{\"status\":0,\"errorCode\":\"5004\",\"message\":\"訂單入庫失敗\"}"; } } catch (Exception e) { log.error("", e); e.printStackTrace(); result = "{\"status\":0,\"errorCode\":\"5003\",\"message\":\"簽名過程失敗\"}"; } return result; }
3.構建微信支付參數實體類WeiPayObj apache
public class WeiPayObj { private String orderNum; private String notifyUrl; //回調地址 private String orderNo; //訂單號 private String finalMoney; //金額 private String remoteAddr; //Ip 默認 127.0.0.1 private String nonceStr; //隨機串 private String timestamp; //時間戳 private String prepayId; //預付單ID private String finalSign; //簽名結果 private String attach; //訂單描述 // 省略 set get方法 }
4.構建微信支付簽名工具類api
import com.tenpay.util.WXUtil; import com.weipayv3.utils.RequestHandler; import com.weipayv3.utils.Sha1Util; import com.weipayv3.utils.WeiPayConfig; import com.weipayv3.utils.WxOrderUtil; import java.util.SortedMap; import java.util.TreeMap; /** * 微信支付V3版簽名 */ public class WeiPaySignUtils { public static WeiPayObj weiPaySign(WeiPayObj weiPayObj,RequestHandler reqHandler){ String appid = WeiPayConfig.APP_ID; //應用對應的憑證 String appsecret = WeiPayConfig.APP_SECRET; //商戶號對應的密鑰 String partnerkey = WeiPayConfig.PARTNER_KEY; //商戶號 String partner = WeiPayConfig.PARTNER; //隨機串 String noncestr = getNonceStr(); String body = weiPayObj.getOrderNum(); String attach = weiPayObj.getAttach(); SortedMap<String, String> packageParams = new TreeMap<String, String>(); packageParams.put("appid", appid); packageParams.put("attach", attach); //商品 packageParams.put("body", body); packageParams.put("mch_id", partner); //隨機串 packageParams.put("nonce_str", noncestr); //回調地址 packageParams.put("notify_url", weiPayObj.getNotifyUrl()); //商品訂單號 packageParams.put("out_trade_no", weiPayObj.getOrderNo()); //這裏寫的金額爲1 分到時修改 packageParams.put("total_fee", weiPayObj.getFinalMoney()); packageParams.put("trade_type", "APP"); //請求地址 packageParams.put("spbill_create_ip", weiPayObj.getRemoteAddr()); reqHandler.init(appid, appsecret, partnerkey); //預付單簽名 String sign = reqHandler.createSign(packageParams,partnerkey); String xml = "<xml>" + "<appid>" + appid + "</appid>" + "<mch_id>" + partner + "</mch_id>" + "<nonce_str>" + noncestr + "</nonce_str>" + "<sign>" + sign + "</sign>" + "<body><![CDATA[" + body + "]]></body>" + "<attach>" + attach + "</attach>" + "<out_trade_no>" + weiPayObj.getOrderNo() + "</out_trade_no>" + "<total_fee>" + weiPayObj.getFinalMoney() + "</total_fee>" + "<spbill_create_ip>" + weiPayObj.getRemoteAddr() + "</spbill_create_ip>" + "<notify_url>" + weiPayObj.getNotifyUrl() + "</notify_url>" + "<trade_type>APP</trade_type>" + "</xml>"; //預付單 String prepay_id = WxOrderUtil.getPrepayId(xml); SortedMap<String, String> finalpackage = new TreeMap<String, String>(); String timestamp = Sha1Util.getTimeStamp(); finalpackage.put("appid", appid); finalpackage.put("noncestr", noncestr); finalpackage.put("package", "Sign=WXPay"); finalpackage.put("partnerid", partner); finalpackage.put("prepayid", prepay_id); finalpackage.put("timestamp", timestamp); //簽名 String finalsign = reqHandler.createSign(finalpackage,partnerkey); weiPayObj.setPrepayId(prepay_id); weiPayObj.setTimestamp(timestamp); weiPayObj.setNonceStr(noncestr); weiPayObj.setFinalSign(finalsign); return weiPayObj; } public String getNonceStr() { Random random = new Random(); return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "GBK"); } }
4.構建參數簽名工具類服務器
/* '============================================================================ 'api說明: 'createSHA1Sign建立簽名SHA1 'getSha1()Sha1簽名 '============================================================================ '*/ public class Sha1Util { public static String getNonceStr() { Random random = new Random(); return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8"); } public static String getTimeStamp() { return String.valueOf(System.currentTimeMillis() / 1000); } //建立簽名SHA1 public static String createSHA1Sign(SortedMap<String, String> signParams) throws Exception { StringBuffer sb = new StringBuffer(); Set es = signParams.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(); sb.append(k + "=" + v + "&"); //要採用URLENCODER的原始值! } String params = sb.substring(0, sb.lastIndexOf("&")); // System.out.println("sha1以前:" + params); // System.out.println("SHA1簽名爲:"+getSha1(params)); return getSha1(params); } //Sha1簽名 public static String getSha1(String str) { if (str == null || str.length() == 0) { return null; } char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; try { MessageDigest mdTemp = MessageDigest.getInstance("SHA1"); mdTemp.update(str.getBytes("UTF-8")); byte[] md = mdTemp.digest(); int j = md.length; char buf[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; buf[k++] = hexDigits[byte0 >>> 4 & 0xf]; buf[k++] = hexDigits[byte0 & 0xf]; } return new String(buf); } catch (Exception e) { return null; } } }
5.構建微信支付生成預付單工具類微信
import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import java.util.HashMap; import java.util.Map; /** * 微信支付訂單工具類 * @author binshangwen * @date 2016-12-14 */ public class WxOrderUtil{ /** * 訂單預支付ID */ public static String getPrepayId(String xml) { String prepay_id=""; String unifiedorder = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 建立HttpClientBuilder HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); // HttpClient CloseableHttpClient closeableHttpClient = httpClientBuilder.build(); HttpPost httpPost = new HttpPost(unifiedorder); StringEntity entity; try { entity = new StringEntity(xml, "utf-8"); httpPost.setEntity(entity); HttpResponse httpResponse; // post請求 httpResponse = closeableHttpClient.execute(httpPost); HttpEntity httpEntity = httpResponse.getEntity(); if (httpEntity != null) { // 打印響應內容 String result = EntityUtils.toString(httpEntity, "UTF-8"); System.out.println(result); // 過濾 result = result.replaceAll("<![CDATA[|]]>", ""); prepay_id = Jsoup.parse(result).select("prepay_id").html(); if (prepay_id != null) return prepay_id; } // 釋放資源 closeableHttpClient.close(); } catch (Exception e) { e.printStackTrace(); } return prepay_id; } /** * 訂單查詢 * @param xml * @return */ public static Map<String, String> reqOrderquery(String xml){ // 建立HttpClientBuilder HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); // HttpClient CloseableHttpClient closeableHttpClient = httpClientBuilder.build(); HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/orderquery"); System.out.println(xml); StringEntity entity; Map<String, String> map = null; try { entity = new StringEntity(xml, "utf-8"); httpPost.setEntity(entity); HttpResponse httpResponse; // post請求 httpResponse = closeableHttpClient.execute(httpPost); // getEntity() HttpEntity httpEntity = httpResponse.getEntity(); if (httpEntity != null) { // 打印響應內容 String result = EntityUtils.toString(httpEntity, "UTF-8"); System.out.println(result); // 過濾 result = result.replaceAll("<![CDATA[|]]>", ""); System.out.println(result); Document doc= Jsoup.parse(result); map = mapPutData(doc); } // 釋放資源 closeableHttpClient.close(); } catch (Exception e) { e.printStackTrace(); } return map; } /** *構造訂單查詢返回結果 * @param doc * @return */ public static Map<String, String> mapPutData(Document doc){ Map<String, String> map = new HashMap<String, String>(); String appid="",mch_id="",sign="",result_code="",err_code="",err_code_des="", trade_type="",trade_state="",total_fee="",transaction_id="",out_trade_no="",trade_state_desc="",return_code="",return_msg=""; if(doc!=null){ return_code=doc.select("return_code").html(); return_msg=doc.select("return_msg").html(); appid=doc.select("appid").html(); mch_id=doc.select("mch_id").html(); sign=doc.select("sign").html(); result_code=doc.select("result_code").html(); err_code=doc.select("err_code").html(); err_code_des=doc.select("err_code_des").html(); trade_type=doc.select("trade_type").html(); trade_state=doc.select("trade_state").html(); total_fee=doc.select("total_fee").html(); transaction_id=doc.select("transaction_id").html(); out_trade_no =doc.select("out_trade_no").html(); trade_state_desc =doc.select("trade_state_desc").html(); } map.put("return_code",return_code); map.put("return_msg",return_msg); map.put("appid",appid); map.put("mch_id",mch_id); map.put("sign",sign); map.put("result_code",result_code); map.put("err_code",err_code); map.put("err_code_des",err_code_des); map.put("trade_type",trade_type); map.put("trade_state",trade_state); map.put("total_fee",total_fee); map.put("transaction_id",transaction_id); map.put("out_trade_no",out_trade_no); map.put("trade_state_desc",trade_state_desc); return map; } }