这几天一直在调试wxjssdk,按照api的需求,http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html ,先是根据appid和秘钥获取access_token并存入缓存:注意的是 此处的appid 和 秘钥 是 微信公众平台的appid(区别于微信开放平台,开放平台无法设置域名)。
public final String sharing(String url, HttpServletResponse response) { StringBuilder stringBuilder = new StringBuilder(); Map<String,String> resMap = new HashMap<String, String>(); //返回给app端 net.sf.json.JSONObject jb = new net.sf.json.JSONObject(); net.sf.json.JSONObject data = new net.sf.json.JSONObject(); try { if (url.contains("#")){ url = url.substring(0,url.indexOf("#")); //不需要获取后面的#的内容 } Map<String,String> ecPaymentMap = myPayService.findPaymentTypeListInfo(PAYMENT_TYPE_ID); String accessToken = cacheUtil.readCache("access_token"); //获取token if (StringUtil.isEmpty(accessToken)){ Map<String,String> getTokenMap = new HashMap<String, String>(); getTokenMap.put("grant_type","client_credential"); //获取access_token填写client_credential getTokenMap.put("appid", ecPaymentMap.get("appId")); //第三方用户唯一凭证 getTokenMap.put("secret",ecPaymentMap.get("appKey")); //第三方用户唯一凭证密钥, String resTokenData = HttpClientTools.doGet(WXURLConstant.ACCESSTOKENURL, getTokenMap); if (StringUtil.isEmpty(resTokenData)){ logger.error("WXJs Token is null"); throw new RuntimeException(); } JSONObject jsonObject = JSONObject.parseObject(resTokenData); logger.info("WXJs resData" + jsonObject); if (jsonObject.get("access_token") !=null){ cacheUtil.setCache("access_token",jsonObject.get("access_token").toString(),Integer.valueOf(jsonObject.get("expires_in").toString())); }else { logger.error("get WXJs token error,errorCode: " + jsonObject.get("errcode")); } accessToken=cacheUtil.readCache("access_token"); } String jsapiTicket = cacheUtil.readCache("jsapiTicket"); //获取jsapiTicket if (StringUtil.isEmpty(jsapiTicket)){ Map<String,String> map = new HashMap<String, String>(); //请求获取JS-SDK使用权限签名算法 map.put("access_token",accessToken); //请求参数access_token map.put("type","jsapi"); //请求参数type 固定 String ticketResData = HttpClientTools.doGet(WXURLConstant.JSAPITICKET, map); if (StringUtil.isEmpty(ticketResData)){ logger.error("requestData is null"); return null; } JSONObject jsonObject = JSONObject.parseObject(ticketResData); if (!"0".equals(jsonObject.get("errcode").toString())){ logger.error("WX get jsapiTicket error" + jsonObject.toString()); jb.element("status", 002); jb.element("msg", "jsapi error"); data.element("data",jsonObject); jb.put("data",data); stringBuilder.append(jb); response.resetBuffer(); response.setContentType("text/html;charset=UTF-8"); response.getWriter().print(stringBuilder); response.getWriter().flush(); response.getWriter().close(); response.flushBuffer(); return stringBuilder.toString(); } cacheUtil.setCache("jsapiTicket",jsonObject.get("ticket").toString(),WXJSSDKConstant.EXPIRETIME); //缓存2个小时 其实有自动任务一个小时会执行一次 防止过期 jsapiTicket = jsonObject.get("ticket").toString(); } String timestamp = String.valueOf(System.currentTimeMillis()/1000); String nonceStr = TenpayUtil.getNonceStr(); Map<String,String> requestSignMap = new HashMap<String, String>(); //后去signature requestSignMap.put("noncestr", nonceStr); requestSignMap.put("jsapi_ticket",jsapiTicket); requestSignMap.put("timestamp",timestamp); requestSignMap.put("url",url); String signature = ""; try { signature = WXUtil.sha1Sign(requestSignMap); } catch (JDOMException e) { e.printStackTrace(); } //增加签名 jb.element("status", 0); jb.element("msg", "OK"); resMap.put("appId", ecPaymentMap.get("appId")); resMap.put("timestamp", timestamp); resMap.put("nonceStr", nonceStr); resMap.put("signature", signature); data.element("data",resMap); jb.element("data", data); stringBuilder.append(jb.toString()); response.resetBuffer(); response.setContentType("text/html;charset=UTF-8"); response.getWriter().print(stringBuilder.toString()); response.getWriter().flush(); response.getWriter().close(); response.flushBuffer(); } catch (IOException e) { e.printStackTrace(); } return stringBuilder.toString(); }
第二步 是根据acces_token获取jsapi_ticket并存入缓存,注意此处的参数type要是jsapi,还有一个获取卡卷的接口,此处容易出错
第三部 就是根据jsapiticket 来获取signature,参数主要是16位随机数,ticket 时间串(注意此处的格式是秒) url (注意路径:传递的时候需要转码,后台后去的时候需要解码,这个一定要注意了,好多人在这上面被坑的。。。)
noncestr
jsapi_ticket
timestamp
url
第四步 把获得的结果传到前台即可
遇到的问题,主要是 报这个 config invalid signature
用jsskd自带的签名工具验签 发现没有问题,但是无论如何就是报签名错误。然后google了好多,最后发现原来是url的问题: 前端需要转码 需要转码 需要转码 ,后台需要解码 需要解码 需要解码。
前端:url在JavaScript中千万别忘记“encodeURIComponent”!
url在JavaScript中千万别忘记“encodeURIComponent”!
url在JavaScript中千万别忘记“encodeURIComponent”!
后台:
public String sharing(HttpServletRequest request, HttpServletResponse response){ String url = request.getParameter("url"); //分享链接url try { logger.info("beforeDecode:" + url); url = URLDecoder.decode(url,"utf-8"); logger.info("afterEncode:" + url); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return wXSharingService.sharing(url,response); }