javascript
微信公众号开发笔记(三):微信JSAPI支付功能开发
很久之前做了微信支付,其中也趟過很多坑,現在有時間就做個自我梳理吧算是。
公眾號開發的基本配置(不明白的可以參考https://blog.csdn.net/TOP__ONE/article/details/78183209),這里不再繼續闡述。
如果以下代碼涉及到微信工具類方法,而我沒有提到的,請到鏈接下載:https://download.csdn.net/download/top__one/10875681
實現微信頁面的分享自定義接口功能,需要先配置js-sdk以下數據項,所以需要先獲取這些數據項。詳細配置可以參考上一篇文章https://blog.csdn.net/TOP__ONE/article/details/85247401中的第一步后臺參數準備配置,這里就不重復寫了。
在頁面配置好以下參數,同樣是引用的js-1.2.0版本
<script type="text/javascript">$(document).ready(function(){var appId = $("#appId").val();var timestamp = $("#timestamp").val();var nonceStr = $("#nonceStr").val();var signature = $("#signature").val();//var jsonObj = eval('('+t+')');wx.config({debug: false,appId: appId,timestamp: timestamp,nonceStr: nonceStr,signature: signature,jsApiList: ['chooseWXPay','checkJsApi','closeWindow']});wx.error(function(res){//alert(JSON.stringify(res));// config信息驗證失敗會執行error函數,如簽名過期導致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數中查看,對于SPA可以在這里更新簽名。 });wx.checkJsApi({jsApiList: ['checkJsApi'], // 需要檢測的JS接口列表,所有JS接口列表見附錄2,success: function(res) {//alert(res);// 以鍵值對的形式返回,可用的api值true,不可用為false// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}}});});準備好頁面參數配置好以后就可以進行下面程序了,進行 統一下單 微信統一下單操作:
$(function(){ //此方法就是為了獲取統一訂單id之類的信息,與后臺配套$("#paybt").click(function(){$.ajax({type: "POST",url: "*/payGetPreId.action",data:,dataType : "html",success : function(msg) {msg=eval('(' + msg + ')'); if("fail"==msg.info){alert(mgs.content);return false;}wx.chooseWXPay({timestamp : msg.timeStamp, // 支付簽名時間戳,注意微信jssdk中的所有使用timestamp字段均為小寫。但最新版的支付后臺生成簽名使用的timeStamp字段名需大寫其中的S字符nonceStr : msg.nonceStr, // 支付簽名隨機串,不長于 32 位package : msg.prep, // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***)signType : 'MD5', // 簽名方式,默認為'SHA1',使用新版支付需傳入'MD5'paySign : msg.paySign, // 支付簽名success : function(res) {$.ajax({type: "POST",async: false,url: pay/success/",data:,dataType : "html",success : function(msg) {//alert(msg);}}); a();},cancel: function(res) {//支付取消alert('支付取消');}});}});});});后臺對應的payGetPreId方法
/*** 獲取統一下單的id* * @author wang* @dateTime 上午10:17:51* @param RenewalController* .java* @return* @throws ServiceException* */@ResponseBody@RequestMapping(value = "/payGetPreId", produces = { "application/json;charset=UTF-8" })public String payGetPreId(Model model, @RequestParam Map<String, String> map) {String buy_time = StringUtils.getNowTime();// 生成訂單號String rStr = TokenGenerator.getPwd(6);String id = buy_time.replace("-", "").replace(" ", "").replace(":", "")+ rStr;WxPaySendData data = new WxPaySendData();String nonce_str = Sign.create_nonce_str();String timep = Sign.create_timestamp();String ip = GetIp.getLocalIp(this.getRequest());data.setAppid(PropertieSingle.getInstance().getProperty("APPID"));data.setMch_id(PropertieSingle.getInstance().getProperty("APP_MCH"));data.setBody("IncallOrderPay");data.setNonce_str(nonce_str);// 支付回調url需要重新設置 data.setNotify_url("http://*/payBack.action");logger.info("微信支付回調url地址======"+data.getNotify_url());data.setOut_trade_no(id);data.setTotal_fee((int) (Double.parseDouble(map.get("combo_price")) * 100));// 單位:分//data.setTotal_fee(1);// 單位:分data.setTrade_type("JSAPI");data.setSpbill_create_ip(ip);// 獲取本地ipString openid = (String) this.getSession().getAttribute("openid");data.setOpenid(openid);logger.info("微信支付中的openid參數========"+data.getOpenid());String sign = UnifiedorderService.unifiedOrder(data, PropertieSingle.getInstance().getProperty("APP_SECRET"));Map<String, String> m = new DOMXML().parse(sign);String pre1 = m.get("prepay_id");String prep = "prepay_id=" + pre1;// 加 sessionSortedMap<Object, Object> parameters = new TreeMap<Object, Object>();parameters.put("appId",PropertieSingle.getInstance().getProperty("APPID"));parameters.put("timeStamp", timep);parameters.put("nonceStr", nonce_str);parameters.put("package", prep);parameters.put("signType", "MD5");this.getSession().setAttribute("p", parameters);// FIXME 再獲取一次singture 查看下文檔String signAgain = Sign.createSign(parameters, PropertieSingle.getInstance().getProperty("APP_SECRET"));String paySign = signAgain;String nonceStr = (String) parameters.get("nonceStr");String timeStamp = (String) parameters.get("timeStamp");JSONObject json = new JSONObject();json.put("info", "ok");json.put("timeStamp", timeStamp);json.put("nonceStr", nonceStr);json.put("prep", prep);json.put("paySign", paySign);map.put("wxhost", PropertieSingle.getInstance().getProperty("WXNOTIFYHOST"));json.put("map", map);return json.toString();}/*** 微信支付回調方法,用于驗證微信發來的請求* * @param model* @param map*/@ResponseBody@RequestMapping(value = "/payBack", produces = { "application/json;charset=UTF-8" })public void payBack(Model model, @RequestParam Map<String, String> map) {InputStream inStream = null;ByteArrayOutputStream outSteam = null;String result = "";try {inStream = this.getRequest().getInputStream();outSteam = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = inStream.read(buffer)) != -1) {outSteam.write(buffer, 0, len);}result = new String(outSteam.toByteArray(), "utf-8");} catch (Exception e) {e.printStackTrace();} finally {if (outSteam != null) {try {outSteam.close();} catch (IOException e) {e.printStackTrace();}}if (inStream != null) {try {inStream.close();} catch (IOException e) {e.printStackTrace();}}}// 解析微信發過來回調內容Map<String, String> m = XMLUtil.doXMLParse(result);if (m.get("result_code").equalsIgnoreCase("success")) {//成功回調,可以進行自己的業務操作,參數可以從m中取System.out.println(m.get("out_trade_no"));//m.get("out_trade_no").substring(0,m.get("out_trade_no").length()-1));try {this.getResponse().getWriter().write(PayCommonUtil.setXML("SUCCESS", ""));} catch (IOException e) {e.printStackTrace();}// 告訴微信服務器,我收到信息了,不要在調用回調action了 ?? ???System.out.println("-------------"+ PayCommonUtil.setXML("SUCCESS", ""));} else {System.out.println("11111111111111111");}}?其中涉及到的工具類sign
package com.chinatsp.wechat.util;import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Formatter; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.UUID;public class Sign {public static void main(String[] args) {String jsapi_ticket = "jsapi_ticket";// 注意 URL 一定要動態獲取,不能 hardcodeString url = "http://example.com";Map<String, String> ret = sign(jsapi_ticket, url);for (Map.Entry entry : ret.entrySet()) {System.out.println(entry.getKey() + ", " + entry.getValue());}};/*** 這是jssdk中需要的那個singture簽名* @param jsapi_ticket* @param url* @return*/public static Map<String, String> sign(String jsapi_ticket, String url) {Map<String, String> ret = new HashMap<String, String>();String nonce_str = create_nonce_str();//定義的字符串String timestamp = create_timestamp();//同上String string1;String signature = "";System.out.println(nonce_str);System.out.println(timestamp);System.out.println(jsapi_ticket);System.out.println(url);//注意這里參數名必須全部小寫,且必須有序string1 = "jsapi_ticket=" + jsapi_ticket +"&noncestr=" + nonce_str +"×tamp=" + timestamp +"&url=" + url;System.out.println(string1);try{MessageDigest crypt = MessageDigest.getInstance("SHA-1");//加密方法crypt.reset();crypt.update(string1.getBytes("UTF-8"));signature = byteToHex(crypt.digest());}catch (NoSuchAlgorithmException e){e.printStackTrace();}catch (UnsupportedEncodingException e){e.printStackTrace();}ret.put("url", url);ret.put("jsapi_ticket", jsapi_ticket);ret.put("nonceStr", nonce_str);ret.put("timestamp", timestamp);ret.put("signature", signature);return ret;}/*** 這是微信支付里面需要哪個簽名* @param parameters* @param key* @return*/private static String characterEncoding = "UTF-8";@SuppressWarnings("rawtypes")public static String createSign(SortedMap<Object,Object> parameters,String key){ StringBuffer sb = new StringBuffer(); Set es = parameters.entrySet();//所有參與傳參的參數按照accsii排序(升序) Iterator it = es.iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); String k = (String)entry.getKey(); Object v = entry.getValue(); if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + key);String signature = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();return signature; }//加密方法private static String byteToHex(final byte[] hash) {Formatter formatter = new Formatter();for (byte b : hash){formatter.format("%02x", b);}String result = formatter.toString();formatter.close();return result;}public static String create_nonce_str() {return UUID.randomUUID().toString().replaceAll("-", "");}public static String create_timestamp() {return Long.toString(System.currentTimeMillis() / 1000);} }工具類DOMXML
package com.chinatsp.wechat.util; import java.io.StringReader; import java.util.HashMap; import java.util.Map;import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; public class DOMXML {public Map<String,String> parse(String protocolXML) { Map<String,String> m = new HashMap<String, String>();try { DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder .parse(new InputSource(new StringReader(protocolXML))); Element root = doc.getDocumentElement(); NodeList books = root.getChildNodes(); if (books != null) { for (int i = 0; i < books.getLength(); i++) { Node book = books.item(i); // System.out.println("節點=" + book.getNodeName() + "\ttext=" // + book.getFirstChild().getNodeValue()); m.put(book.getNodeName(), book.getFirstChild().getNodeValue());} } } catch (Exception e) { e.printStackTrace(); }return m;} }GetIp工具類
package com.chinatsp.wechat.util;import javax.servlet.http.HttpServletRequest;public class GetIp{/*** 從Request對象中獲得客戶端IP,處理了HTTP代理服務器和Nginx的反向代理截取了ip* @param request* @return ip*/public static String getLocalIp(HttpServletRequest request) {String remoteAddr = request.getRemoteAddr();String forwarded = request.getHeader("X-Forwarded-For");String realIp = request.getHeader("X-Real-IP");String ip = null;if (realIp == null) {if (forwarded == null) {ip = remoteAddr;} else {ip = forwarded.split(",")[0];}} else {if (realIp.equals(forwarded)) {ip = realIp;} else {if(forwarded != null){forwarded = forwarded.split(",")[0];}ip = forwarded;}}return ip;} }UnifiedorderService.unifiedOrder工具類方法 重點
package com.chinatsp.wechat.util;import java.io.IOException; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap;import org.slf4j.Logger; import org.slf4j.LoggerFactory;import weixin.util.HttpUtils;import com.alibaba.fastjson.JSONObject; import com.chinatsp.wechat.bean.WxPaySendData; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;public class UnifiedorderService {private final static Logger logger = LoggerFactory.getLogger(UnifiedorderService.class);public static String unifiedOrder(WxPaySendData data,String key){//統一下單支付String returnXml = null;try {//生成sign簽名SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();parameters.put("appid", data.getAppid()); parameters.put("body", data.getBody());parameters.put("mch_id", data.getMch_id());parameters.put("nonce_str", data.getNonce_str());parameters.put("notify_url", data.getNotify_url());parameters.put("out_trade_no", data.getOut_trade_no());parameters.put("total_fee", data.getTotal_fee()+"");parameters.put("trade_type", data.getTrade_type());parameters.put("spbill_create_ip", data.getSpbill_create_ip());parameters.put("openid", data.getOpenid()); // parameters.put("time_start", data.getTime_start()); // parameters.put("time_expire", data.getTime_expire());logger.info("SIGN:"+Sign.createSign(parameters,key));data.setSign(Sign.createSign(parameters,key));XStream xs = new XStream(new DomDriver("UTF-8",new XmlFriendlyNameCoder("-_", "_")));xs.alias("xml", WxPaySendData.class);String xml = xs.toXML(data);logger.info("統一下單xml為:\n" + xml);returnXml = HttpUtils.doRequest("https://api.mch.weixin.qq.com/pay/unifiedorder","POST", xml);logger.info("返回結果:" + returnXml);System.out.println(returnXml); } catch (Exception e) {e.printStackTrace();} return returnXml;}public static void main(String[] args) {WxPaySendData data = new WxPaySendData();data.setAppid("wx1b");data.setBody("wxgzzgzgufy");data.setMch_id("13901");data.setNonce_str("12345678");data.setNonce_str(Sign.create_nonce_str());data.setNotify_url("yy/testindex.action");data.setOut_trade_no("122125112");data.setTotal_fee(1);//單位:分data.setTrade_type("JSAPI");data.setSpbill_create_ip("192.16.");data.setOpenid("oogDE");String sign = UnifiedorderService.unifiedOrder(data, "pq19L**SwY5EB");// String s = "<xml><appid><![CDATA[wx2c43b]]></appid><attach><![CDATA[支付測試]]></attach><bank_type><![CDATA[CFT]]></bank_type> <fee_type><![CDATA[CNY]]></fee_type> <is_subscribe><![CDATA[Y]]></is_subscribe> <mch_id><![CDATA[10000100]]></mch_id> <nonce_str><![CDATA[5d2b6c46e531c]]></nonce_str> <openid><![CDATA[oUpFkE]]></openid> <out_trade_no><![CDATA[14653]]></out_trade_no> <result_code><![CDATA[SUCCESS]]></result_code> <return_code><![CDATA[SUCCESS]]></return_code> <sign><![CDATA[B552ED6B278AB241]]></sign> <sub_mch_id><![CDATA[10000]]></sub_mch_id> <time_end><![CDATA[20140903131540]]></time_end> <total_fee>1</total_fee> <trade_type><![CDATA[JSAPI]]></trade_type> <transaction_id><![CDATA[100440079030005092168]]></transaction_id> </xml>"; // String xmlToJSON = XmlUtils.xmlToJSON(s); // Map<String,String> map = (Map)JSONObject.toJSON(xmlToJSON); // System.out.println(map.get("prepay_id"));Map<String,String> m=XMLUtil.doXMLParse(sign);System.out.println(m.size());} }至此,微信公眾號的支付功能就開發完畢了·、留此備忘一下~
具體的jsapi支付功能請參考詳細文檔https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
總結
以上是生活随笔為你收集整理的微信公众号开发笔记(三):微信JSAPI支付功能开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2011系列服务器,2011年中服务器领
- 下一篇: 游戏被攻击了怎么办,有没有什么好的解决办