微信支付流程:
1、在頁面點擊支付發生的動作
將訂單參數傳遞后台->后台根據訂單參數以及微信相關信息->獲取支付所需要的參數->后台處理支付所需要的參數返回給前端->前端獲取到支付參數->發起支付請求->支付成功的頁面會顯示跳回商家所設置的回調路徑->后台根據回調路徑處理相關業務邏輯;
2、程序案例;從官網中下載相關API
頁面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>every thing will be will</title> <script type="text/javascript" src="../static/js/jquery-3.3.1.min.js"></script> </head> <body> <input type="button" value="進行微信支付" id="payId"> <script type="text/javascript"> $(function(){ var appId,timeStamp,nonceStr,package,signType,paySign; $("#payId").click(function(){ pay(); }); //從后台獲取參數 function pay(){ var url = "http://localhost:8062/wxpay/order"; $.get(url,function(result) { appId = result.appId; timeStamp = result.timeStamp; nonceStr = result.nonceStr; package = result.package; signType = result.signType; paySign = result.paySign; if (typeof WeixinJSBridge == "undefined") { if (document.addEventListener) { document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); } else if (document.attachEvent) { document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } alert("請在微信上進行支付操作!"); onBridgeReady(); } else { onBridgeReady(); } }); } //去微信那邊發起支付請求 function onBridgeReady(){ alert("appId:"+appId+" "+"timeStamp:"+timeStamp+" "+"nonceStr:"+nonceStr+" "+"package:"+package+" "+"signType:"+signType+" "+"paySign:"+paySign+" "); WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":appId, //公眾號名稱,由商戶傳入 "timeStamp":timeStamp, //時間戳,自1970年以來的秒數 "nonceStr":nonceStr, //隨機串 "package":package, "signType":signType, //微信簽名方式: "paySign":paySign //微信簽名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { //alert('支付成功'); console.log("支付成功"); //支付成功后跳轉的頁面 }else if(res.err_msg == "get_brand_wcpay_request:cancel"){ alert('支付取消'); }else if(res.err_msg == "get_brand_wcpay_request:fail"){ alert('支付失敗'); alert(JSON.stringify(res)); WeixinJSBridge.call('closeWindow'); } //使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功后返回ok,但並不保證它絕對可靠。 }); } }) </script> </body> </html>
后台業務邏輯
所需的參數:
public class WxParam { public final static String WX_APPID = "";//商家平台ID,微信平台 public final static String WX_BODY = ""; //商品描述 public final static String WX_MCH_ID = "";//商戶ID ,微信平台 public final static String WX_NONCE_STR = "";//隨機字符串,UUID public final static String WX_OPEN_ID = "";//用戶OPENID public final static String WX_OUT_TRADE_NO = "";//商戶訂單號 public final static String WX_SPBILL_CREATE_IP = "";//終端IP,從請求頭拿到 public final static String WX_TOTAL_FEE = "";//支付金額,單位是分 public final static String WX_TRADE_TYPE = "";//交易類型;JSAPI public final static String WX_NOTIFY_URL = "";//通知地址;用戶支付成功后,返回應用程序的接口; public final static String WX_SIGN = "";//簽名,根據上面10個參數計算獲得 public final static String WX_PATERNERKEY = "";//商家密鑰 }
前端所需參數的處理,以及回調路徑
@Controller @RequestMapping("/wxpay") public class WxPayAction { /** * 訂單采用微信支付所需的參數接口 * @param request * @return */ @RequestMapping("/order") @ResponseBody public Map<String,String> orders(HttpServletRequest request){ try { String openId = "用戶的openid"; //存放微信支付所需的參數 final Map<String,String> paraMap = new HashMap<>(); // 獲取請求ip地址 String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } if (ip.indexOf(",") != -1) { String[] ips = ip.split(","); ip = ips[0].trim(); } String uuid = UUID.randomUUID().toString(); // paraMap.put("appid",WxParam.WX_APPID); paraMap.put("body","微信測試商品內容" ); paraMap.put("mch_id",WxParam.WX_MCH_ID ); paraMap.put("nonce_str",uuid ); paraMap.put("openid",openId ); paraMap.put("out_trade_no",UUID.randomUUID().toString().replaceAll("-", "") );//訂單號 paraMap.put("spbill_create_ip",ip );//終端IP,從請求頭拿到 paraMap.put("total_fee","1" );//支付金額,1分 paraMap.put("trade_type","JSAPI" );//支付類型 paraMap.put("notify_url","回調url" ); //這里的key是商家密鑰;這一步將回調路徑設置到sign參數里面了 String sign = WXPayUtil.generateSignedXml(paraMap,WxParam.WX_PATERNERKEY); paraMap.put("sign",sign ); //將map轉換為xml String xml = WXPayUtil.mapToXml(paraMap); // 統一下單 https://api.mch.weixin.qq.com/pay/unifiedorder String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; System.out.println("xml為:" + xml); //預支付 String xmlStr = HttpRequestUtil.httpsRequest(unifiedorder_url, "POST", xml); System.out.println("預支付返回的信息:"+xmlStr); //上面的數據主要是為了獲得預支付id;就相當於微信上提交訂單(訂單包含了回調函數),然后返回一個微信的訂單id; //以下內容返回前端頁面的json數據 String prepay_id = "";//預支付id if(xmlStr.indexOf("SUCCESS") != -1){ Map<String,String> map = WXPayUtil.xmlToMap(xmlStr); prepay_id = (String) map.get("prepay_id"); } Map<String,String> payMap = new HashMap<>(); payMap.put("appId",WxParam.WX_APPID ); //后面為什么要加"" payMap.put("timeStamp",WXPayUtil.getCurrentTimestamp()+"" ); payMap.put("nonceStr",WXPayUtil.generateNonceStr() ); payMap.put("signType","MD5" ); payMap.put("package","prepay_id="+prepay_id); String paySin = WXPayUtil.generateSignature(payMap, WxParam.WX_PATERNERKEY); payMap.put("paySign",paySin ); return payMap; }catch (Exception e){ } return null; } /** * 回調函數,處理業務邏輯 * @param request * * @param response * * @return */ @RequestMapping("/notify") public String wxCallBack(HttpServletRequest request, HttpServletResponse response){ InputStream is = null; try{ is = request.getInputStream(); InputStreamReader isr=new InputStreamReader(is,"utf-8"); BufferedReader br=new BufferedReader(isr); StringBuffer buffer=new StringBuffer(); String line=null; while((line=br.readLine())!=null){ buffer.append(line); } //從流中獲取 String xml = buffer.toString(); Map<String,String> notifyMap = WXPayUtil.xmlToMap(xml); System.out.println("微信返回的回調函數信息:"+xml); if(notifyMap.get("result_code").equals("SUCCESS")){ String ordersSn = notifyMap.get("out_trade_no");//商戶訂單號 String amountpaid = notifyMap.get("total_fee"); //實際支付金額 BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);// 將分轉換成元-實際支付金額:元 /* * 以下是自己的業務處理------僅做參考 更新order對應字段/已支付金額/狀態碼 */ System.out.println("===notify===回調方法已經被調!!!"); } // 告訴微信服務器收到信息了,回復微信服務器信息用流發送一個xml即可 response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>"); }catch (Exception e){ }finally { if(is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } }
用到的工具類
public class HttpRequestUtil { /* * 處理https GET/POST請求 * 請求地址、請求方法、參數 * */ public static String httpsRequest(String requestUrl,String requestMethod,String outputStr){ StringBuffer buffer=null; try{ //創建SSLContext SSLContext sslContext=SSLContext.getInstance("SSL"); TrustManager[] tm={new MyX509TrustManager()}; //初始化 sslContext.init(null, tm, new java.security.SecureRandom());; //獲取SSLSocketFactory對象 SSLSocketFactory ssf=sslContext.getSocketFactory(); URL url=new URL(requestUrl); HttpsURLConnection conn=(HttpsURLConnection)url.openConnection(); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestMethod(requestMethod); //設置當前實例使用的SSLSoctetFactory conn.setSSLSocketFactory(ssf); conn.connect(); //往服務器端寫內容 if(null!=outputStr){ OutputStream os=conn.getOutputStream(); os.write(outputStr.getBytes("utf-8")); os.close(); } //讀取服務器端返回的內容 InputStream is=conn.getInputStream(); InputStreamReader isr=new InputStreamReader(is,"utf-8"); BufferedReader br=new BufferedReader(isr); buffer=new StringBuffer(); String line=null; while((line=br.readLine())!=null){ buffer.append(line); } }catch(Exception e){ e.printStackTrace(); } return buffer.toString(); } }
public class MyX509TrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { // TODO Auto-generated method stub } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { // TODO Auto-generated method stub } @Override public X509Certificate[] getAcceptedIssuers() { // TODO Auto-generated method stub return null; } }