//2.獲取getJsapiTicket的接口地址,有效期爲7200秒 private static final String GET_JSAPITICKET_URL="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi"; /** * @desc :2.獲取JsapiTicket * * @param accessToken 有效憑證 * @return * @throws Exception String */ public static String getJsapiTicket(String accessToken) throws Exception { //1.獲取請求url String url=GET_JSAPITICKET_URL.replace("ACCESS_TOKEN", accessToken); //2.發起GET請求,獲取返回結果 JSONObject jsonObject=HttpHelper.doGet(url); logger.info("jsonObject:"+jsonObject.toJSONString()); //3.解析結果,獲取accessToken String jsapiTicket=""; if (null != jsonObject) { //4.錯誤消息處理 if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) { int errCode = jsonObject.getInteger("errcode"); String errMsg = jsonObject.getString("errmsg"); throw new Exception("error code:"+errCode+", error message:"+errMsg); //5.成功獲取jsapiTicket }else { jsapiTicket=jsonObject.getString("ticket"); } } return jsapiTicket; }
/** * @desc :4.獲取前端jsapi須要的配置參數 * * @param request * @return String */ public static String getJsapiConfig(HttpServletRequest request){ //1.準備好參與簽名的字段 //1.1 url /* *以http://localhost/test.do?a=b&c=d爲例 *request.getRequestURL的結果是http://localhost/test.do *request.getQueryString的返回值是a=b&c=d */ String urlString = request.getRequestURL().toString(); String queryString = request.getQueryString(); String queryStringEncode = null; String url; if (queryString != null) { queryStringEncode = URLDecoder.decode(queryString); url = urlString + "?" + queryStringEncode; } else { url = urlString; } //1.2 noncestr String nonceStr=UUID.randomUUID().toString(); //隨機數 //1.3 timestamp long timeStamp = System.currentTimeMillis() / 1000; //時間戳參數 String signedUrl = url; String accessToken = null; String ticket = null; String signature = null; //簽名 try { //1.4 jsapi_ticket accessToken=getAccessToken(Env.APP_ID, Env.APP_SECRET); ticket=getJsapiTicket(accessToken); //2.進行簽名,獲取signature signature=getSign(ticket,nonceStr,timeStamp,signedUrl); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } logger.info("accessToken:"+accessToken); logger.info("ticket:"+ticket); logger.info("nonceStr:"+nonceStr); logger.info("timeStamp:"+timeStamp); logger.info("signedUrl:"+signedUrl); logger.info("signature:"+signature); logger.info("appId:"+Env.APP_ID); String configValue = "{signature:'" + signature + "',nonceStr:'" + nonceStr + "',timeStamp:'" + timeStamp + "',appId:'" + Env.APP_ID + "'}"; logger.info("configValue:"+configValue); return configValue; } /** * @desc : 4.1 生成簽名的函數 * * @param ticket jsticket * @param nonceStr 隨機串,本身定義 * @param timeStamp 生成簽名用的時間戳 * @param url 須要進行免登鑑權的頁面地址,也就是執行dd.config的頁面地址 * @return * @throws Exception String */ public static String getSign(String jsTicket, String nonceStr, Long timeStamp, String url) throws Exception { String plainTex = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "×tamp=" + timeStamp + "&url=" + url; System.out.println(plainTex); try { MessageDigest crypt = MessageDigest.getInstance("SHA-1"); crypt.reset(); crypt.update(plainTex.getBytes("UTF-8")); return byteToHex(crypt.digest()); } catch (NoSuchAlgorithmException e) { throw new Exception(e.getMessage()); } catch (UnsupportedEncodingException e) { throw new Exception(e.getMessage()); } } /** * @desc :4.2 將bytes類型的數據轉化爲16進制類型 * * @param hash * @return * String */ private static String byteToHex(byte[] hash) { Formatter formatter = new Formatter(); for (byte b : hash) { formatter.format("%02x", new Object[] { Byte.valueOf(b) }); } String result = formatter.toString(); formatter.close(); return result; }
(1)參與簽名的字段包括:javascript
noncestr(隨機字符串),html
有效的jsapi_ticket,前端
timestamp(時間戳),java
url(當前網頁的URL,不包含#及其後面部分) 。jquery
(2)對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式 (即 key1=value1&key2=value2…)拼接成字符串string1。這裏須要注意的是全部參數名均爲小寫字符。對string1做sha1加密,字段名和字段值都採用原始值,不進行URL 轉義。web
(3)對string1進行sha1簽名,獲得signature:ajax
(1)待簽名參數:算法
noncestr=Wm3WZYTPz0wzccnW
json
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
api
timestamp=1414587457
url=http://mp.weixin.qq.com
(2)字典序
string1=jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-
HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com
(3)sha1加密
signature=sha1(string1)
測試號:
在須要調用JS接口的頁面引入以下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
//1.jsapi簽名校驗 wx.config({ beta: true,// 必須這麼寫,不然在微信插件有些jsapi會有問題 debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: _config.appId, // 必填,公衆號的惟一標識 timestamp: _config.timeStamp, // 必填,生成簽名的時間戳 nonceStr: _config.nonceStr, // 必填,生成簽名的隨機串 signature: _config.signature,// 必填,簽名,見附錄1 jsApiList: [ 'checkJsApi', 'onMenuShareAppMessage', 'onMenuShareWechat', 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'closeWindow', 'scanQRCode', 'previewFile', 'openEnterpriseChat', 'selectEnterpriseContact','chooseInvoice' ]// 必填,須要使用的JS接口列表,全部JS接口列表見附錄2 });
//2.jsapi簽名校驗失敗後執行error wx.error(function(err){ alert('wx error: ' + JSON.stringify(err)); // config信息驗證失敗會執行error函數,如簽名過時致使驗證失敗,具體錯誤信息能夠打開config的debug模式查看,也能夠在返回的res參數中查看,對於SPA能夠在這裏更新簽名。 });
(1)使用 jssdk 上傳圖片到微信服務器,返回圖片對應的mediaId( 即 serverId)
//2.2 上傳圖片 var images = { localId : [], serverId : [] }; $("#uploadImg").click(function(){ //2.2.1拍照或從手機相冊中選圖 wx.chooseImage({ success : function(res) { images.localId = res.localIds; alert('已選擇 ' + res.localIds.length + ' 張圖片'); //2.2.2 上傳圖片 uploadImg(); } }); }); // 2.2.2 上傳圖片 function uploadImg() { if (images.localId.length == 0) { alert('請先使用 chooseImage 接口選擇圖片'); return; } var i = 0, length = images.localId.length; images.serverId = []; function upload() { wx.uploadImage({ localId : images.localId[i], success : function(res) { i++; alert('已上傳:' + i + '/' + length); images.serverId.push(res.serverId); //將serverId上傳至服務器 alert("ajax請求即將執行--"); $.ajax({ type : "POST", url : "http://se9mxs.natappfree.cc/weixin_gz/uploadimg", data : { serverId : res.serverId }, dataType : "text", success : function(data) { alert(data); } }); if (i < length) { upload(); } }, fail : function(res) { alert(JSON.stringify(res)); } }); } upload(); };
(2)使用素材管理接口,根據 mediaId 從微信服務器將圖片下載至服務器本地。參見:Java微信公衆平臺開發_06_素材管理
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String mediaId=request.getParameter("serverId"); System.out.println("serverId:"+mediaId); try { String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET); //String savePath=System.getProperty("user.dir").replaceAll("\\\\", "/")+"/WebContent/img/"+mediaId+".png"; String fileDir=request.getSession().getServletContext().getRealPath("").replaceAll("\\\\", "/")+"/img/"; System.out.println("fileDir:"+fileDir); //2.調用業務類,獲取臨時素材 TempMaterialService.getTempMaterial(accessToken, mediaId, fileDir); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } PrintWriter out = response.getWriter(); out.print("HHHHHHHHHH"); out.close(); out = null; }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSSDK之上傳圖片</title> <script src="js/jquery-3.2.1.min.js"></script> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> <script type="text/javascript"> var _config = <%=com.ray.weixin.gz.util.AuthHelper.getJsapiConfig(request)%> ; </script> <script type="text/javascript" src="js/auth.js"></script> </head> <body> <div align="center"> <img id="userImg" alt="頭像" src=""> </div> <div align="center"> <span>UserName:</span> <div id="userName" style="display: inline-block"></div> </div> <div align="center"> <span>UserId:</span> <div id="userId" style="display: inline-block"></div> </div> <div align="center"> <span class="desc">是否驗證成功</span> <button class="btn btn_primary" id="yanzheng">驗證</button> </div> <div align="center"> <span class="desc">測試按鈕</span> <button class="btn btn_primary" id="ceshi">測試</button> </div> <div align="center"> <span class="desc">上傳圖片按鈕</span> <button class="btn btn_primary" id="uploadImg">上傳圖片</button> </div> <div align="center"> <span class="desc">拍照上傳圖片按鈕</span> <button class="btn btn_primary" id="uploadImgFromCamera">拍照上傳</button> </div> <div align="center"> <span class="desc">掃碼按鈕</span> <button class="btn btn_primary" id="qrcode" >掃碼</button> </div> </body> </html>
auth.js
//1.jsapi簽名校驗 wx.config({ beta: true,// 必須這麼寫,不然在微信插件有些jsapi會有問題 debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: _config.appId, // 必填,公衆號的惟一標識 timestamp: _config.timeStamp, // 必填,生成簽名的時間戳 nonceStr: _config.nonceStr, // 必填,生成簽名的隨機串 signature: _config.signature,// 必填,簽名,見附錄1 jsApiList: [ 'checkJsApi', 'onMenuShareAppMessage', 'onMenuShareWechat', 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'closeWindow', 'scanQRCode', 'previewFile', 'openEnterpriseChat', 'selectEnterpriseContact','chooseInvoice' ]// 必填,須要使用的JS接口列表,全部JS接口列表見附錄2 }); //2.jsapi簽名校驗成功後執行ready wx.ready(function(){ // config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後,config是一個客戶端的異步操做,因此若是須要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則能夠直接調用,不須要放在ready函數中。 //2.1 提示jsapi簽名驗證成功 $("#yanzheng").html("驗證成功"); $("#ceshi").click(function(){ alert("ceshiaaa"); }); $("#checkJsApi").click(function(){ wx.checkJsApi({ jsApiList: [ 'checkJsApi', 'onMenuShareAppMessage', 'onMenuShareWechat', 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'closeWindow', 'scanQRCode', 'previewFile', 'openEnterpriseChat', 'selectEnterpriseContact','chooseInvoice' ], // 須要檢測的JS接口列表,全部JS接口列表見附錄2, success: function(res) { // 以鍵值對的形式返回,可用的api值true,不可用爲false // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"} } }); }); //2.2 上傳圖片 var images = { localId : [], serverId : [] }; $("#uploadImg").click(function(){ //2.2.1拍照或從手機相冊中選圖 wx.chooseImage({ success : function(res) { images.localId = res.localIds; alert('已選擇 ' + res.localIds.length + ' 張圖片'); //2.2.2 上傳圖片 uploadImg(); } }); }); // 2.2.2 上傳圖片 function uploadImg() { if (images.localId.length == 0) { alert('請先使用 chooseImage 接口選擇圖片'); return; } var i = 0, length = images.localId.length; images.serverId = []; function upload() { wx.uploadImage({ localId : images.localId[i], success : function(res) { i++; alert('已上傳:' + i + '/' + length); images.serverId.push(res.serverId); //將serverId上傳至服務器 alert("ajax請求即將執行--"); $.ajax({ type : "POST", url : "http://se9mxs.natappfree.cc/weixin_gz/uploadimg", data : { serverId : res.serverId }, dataType : "text", success : function(data) { alert(data); } }); if (i < length) { upload(); } }, fail : function(res) { alert(JSON.stringify(res)); } }); } upload(); }; //2.3 掃一掃 $("#qrcode").click(function(){ wx.scanQRCode({ needResult: 1, // 默認爲0,掃描結果由微信處理,1則直接返回掃描結果, scanType: ["qrCode","barCode"], // 能夠指定掃二維碼仍是一維碼,默認兩者都有 success: function (res) { var result = res.resultStr; // 當needResult 爲 1 時,掃碼返回的結果 alert(result); }, fail:function (res) { var result = res.resultStr; // 當needResult 爲 1 時,掃碼返回的結果 alert(result); } }); }); //2.4 拉起發票列表 //注意,調用此接口時,config接口必須傳入beta參數。 $("#showInvoice").click(function(){ alert("timestamp:"+invoice_config.timestamp); alert("nonceStr:"+invoice_config.nonceStr); alert("signType:"+invoice_config.signType); alert("cardSign:"+invoice_config.cardSign); wx.invoke('chooseInvoice', { 'timestamp': invoice_config.timestamp, // 卡券簽名時間戳 'nonceStr' : invoice_config.nonceStr, // 卡券簽名隨機串 'signType' : invoice_config.signType, // 簽名方式,默認'SHA1' 'cardSign' : invoice_config.cardSign, // 卡券簽名 }, function(res) { // 這裏是回調函數 alert("aaaaaa"); alert(JSON.stringify(res)); // 返回的結果 }); }); }); //2.jsapi簽名校驗失敗後執行error wx.error(function(err){ alert('wx error: ' + JSON.stringify(err)); // config信息驗證失敗會執行error函數,如簽名過時致使驗證失敗,具體錯誤信息能夠打開config的debug模式查看,也能夠在返回的res參數中查看,對於SPA能夠在這裏更新簽名。 });
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <display-name>weixin_gz</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!--微信公衆號回調--> <servlet> <servlet-name>weixin</servlet-name> <servlet-class>com.ray.weixin.gz.controller.WeiXinServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>weixin</servlet-name> <url-pattern>/weixin</url-pattern> </servlet-mapping> <!-- 微信公衆號回調--> <servlet> <description></description> <display-name>uploadimg</display-name> <servlet-name>uploadimg</servlet-name> <servlet-class>com.ray.weixin.gz.controller.UploadImgServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>uploadimg</servlet-name> <url-pattern>/uploadimg</url-pattern> </servlet-mapping> </web-app>
package com.ray.weixin.gz.controller;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ray.weixin.gz.config.Env;
import com.ray.weixin.gz.service.tempmaterial.TempMaterialService;
import com.ray.weixin.gz.util.AuthHelper;
/**
* Servlet implementation class UploadImgServlet
*/
public class UploadImgServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UploadImgServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String mediaId=request.getParameter("serverId");
System.out.println("serverId:"+mediaId);
try {
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
//String savePath=System.getProperty("user.dir").replaceAll("\\\\", "/")+"/WebContent/img/"+mediaId+".png";
String fileDir=request.getSession().getServletContext().getRealPath("").replaceAll("\\\\", "/")+"/img/";
System.out.println("fileDir:"+fileDir);
//2.調用業務類,獲取臨時素材
TempMaterialService.getTempMaterial(accessToken, mediaId, fileDir);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
PrintWriter out = response.getWriter();
out.print("HHHHHHHHHH");
out.close();
out = null;
}
}
package com.ray.weixin.gz.controller;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ray.weixin.gz.config.Env;
import com.ray.weixin.gz.service.tempmaterial.TempMaterialService;
import com.ray.weixin.gz.util.AuthHelper;
/**
* Servlet implementation class UploadImgServlet
*/
public class UploadImgServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UploadImgServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String mediaId=request.getParameter("serverId");
System.out.println("serverId:"+mediaId);
try {
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
//String savePath=System.getProperty("user.dir").replaceAll("\\\\", "/")+"/WebContent/img/"+mediaId+".png";
String fileDir=request.getSession().getServletContext().getRealPath("").replaceAll("\\\\", "/")+"/img/";
System.out.println("fileDir:"+fileDir);
//2.調用業務類,獲取臨時素材
TempMaterialService.getTempMaterial(accessToken, mediaId, fileDir);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
PrintWriter out = response.getWriter();
out.print("HHHHHHHHHH");
out.close();
out = null;
}
}
其餘的同上一節