第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > 微信公众号开发笔记(三):微信JSAPI支付功能开发

微信公众号开发笔记(三):微信JSAPI支付功能开发

时间:2024-08-08 18:51:23

相关推荐

微信公众号开发笔记(三):微信JSAPI支付功能开发

很久之前做了微信支付,其中也趟过很多坑,现在有时间就做个自我梳理吧算是。

公众号开发的基本配置(不明白的可以参考/TOP__ONE/article/details/78183209),这里不再继续阐述。

如果以下代码涉及到微信工具类方法,而我没有提到的,请到链接下载:/download/top__one/10875681

实现微信页面的分享自定义接口功能,需要先配置js-sdk以下数据项,所以需要先获取这些数据项。详细配置可以参考上一篇文章/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 = "";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 +"&timestamp=" + 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./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[0903131540]]></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./wiki/doc/api/jsapi.php?chapter=7_1

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。