微信公眾號掃一掃封裝介面
阿新 • • 發佈:2018-12-19
一.微信準備功能
1.準備備案域名以及80埠伺服器
本人準備是花生殼6元測試版
2.申請一個公眾號
本人申請為個人訂閱號(搜尋公眾號即可註冊)
3.公眾號配置appId和appsecret以及白名單
登入公眾號——》選擇左功能選單開發——》基本配置(注意白名單裡配置為伺服器的外網IP)
4.公眾號JS介面安全域名配置
填寫域名,下載檔案到tomcat/webapps/root下面
用域名加檔名,可以訪問裡面的內容即驗證成功
二.程式碼實現功能(需加入公眾號的appId和appsecret)
1.微信掃一掃功能封裝介面wechatOpt.js
/** * 微信相關通用操作js */ var weChatObj = { //微信掃一掃配置 wxScanConfig : function(url,callback){ var sUrl = window.location.href; //mylayer.loading(); $.ajax({ url:url, type:"post", data:{"s_url":sUrl}, dataType:"json", async: false, success:function(data){ layer.closeAll(); if(data.success){ var retData = data.obj; wx.config({ debug:false , // 開啟除錯模式,呼叫的所有api的返回值會在客戶端alert出來,若要檢視傳入的引數,可以在pc端開啟,引數資訊會通過log打出,僅在pc端時才會列印。 appId: retData.appId, // 必填,公眾號的唯一標識 timestamp:retData.timestamp, // 必填,生成簽名的時間戳 nonceStr: retData.nonceStr, // 必填,生成簽名的隨機串 signature: retData.signature,// 必填,簽名 jsApiList: [ 'checkJsApi', 'scanQRCode' ] // 必填,需要使用的JS介面列表 }); weChatObj.wxScanCheck(callback); } }, error:function(){ layer.closeAll(); // 資料異常需要關閉彈出層 //mylayer.msg("網路繁忙,請重新整理頁面重試",{icon:2,time:1500}); } }); }, //微信掃一掃jsApi檢查 wxScanCheck : function(callback){ wx.ready(function () { wx.checkJsApi({ jsApiList: [ 'checkJsApi', 'scanQRCode' ], success: function (res) { weChatObj.wxScanCode(callback); } }); }); }, //呼叫微信掃一掃介面 wxScanCode : function(callback){ wx.scanQRCode({ needResult: 1, // 預設為0,掃描結果由微信處理,1則直接返回掃描結果, scanType: ["qrCode"], // 可以指定掃二維碼還是一維碼,預設二者都有 success: function (res) { if(typeof callback == "function"){ callback(res); } }, cancel : function(res){ wx.closeWindow(); } }); }, //微信定位配置 wxLocateConfig : function(callback){ var sUrl = window.location.href; //mylayer.loading(); $.ajax({ url:"/AisinoCDWL/wechat/page/shware/getWxScanSign.do", type:"post", data:{"s_url":sUrl}, dataType:"json", async: false, success:function(data){ if(data.success){ var retData = data.obj; wx.config({ debug:false , // 開啟除錯模式,呼叫的所有api的返回值會在客戶端alert出來,若要檢視傳入的引數,可以在pc端開啟,引數資訊會通過log打出,僅在pc端時才會列印。 appId: retData.appId, // 必填,公眾號的唯一標識 timestamp:retData.timestamp, // 必填,生成簽名的時間戳 nonceStr: retData.nonceStr, // 必填,生成簽名的隨機串 signature: retData.signature,// 必填,簽名 jsApiList: [ 'checkJsApi', 'openLocation', 'getLocation' ] // 必填,需要使用的JS介面列表 }); weChatObj.wxLocateCheck(callback); }else{ //mylayer.msg("微信定位功能呼叫失敗,請重新整理重試",{icon:2,time:1500}); } }, error:function(){ layer.closeAll(); // 資料異常需要關閉彈出層 //mylayer.msg("網路繁忙,請重新整理頁面重試",{icon:2,time:1500}); } }); }, //微信jsApi檢查 wxLocateCheck : function(callback){ wx.ready(function () { wx.checkJsApi({ jsApiList: [ 'getLocation' ], success: function (res) { if (res.checkResult.getLocation == false) { // mylayer.msg('你的微信版本太低,不支援微信JS介面,請升級到最新的微信版本!',{icon:2,time:1500}); return; } if(typeof callback == "function"){ callback(res); } } }); }); }, //微信上傳圖片 wxUploadImg : function(callback){ var sUrl = window.location.href; $.ajax({ url:"/AisinoCDWL/wechat/page/shware/getWxScanSign.do", type:"post", data:{"s_url":sUrl}, dataType:"json", async: false, success:function(data){ if(data.success){ var retData = data.obj; wx.config({ debug:false , // 開啟除錯模式,呼叫的所有api的返回值會在客戶端alert出來,若要檢視傳入的引數,可以在pc端開啟,引數資訊會通過log打出,僅在pc端時才會列印。 appId: retData.appId, // 必填,公眾號的唯一標識 timestamp:retData.timestamp, // 必填,生成簽名的時間戳 nonceStr: retData.nonceStr, // 必填,生成簽名的隨機串 signature: retData.signature,// 必填,簽名 jsApiList: [ 'checkJsApi', 'chooseImage', 'uploadImage', 'downloadImage', 'getLocalImgData' ] // 必填,需要使用的JS介面列表 }); weChatObj.wxUploadImgCheck(callback); }else{ //mylayer.msg("微信上傳圖片相關功能驗證失敗,請重新整理重試",{icon:2,time:1500}); } }, error:function(){ layer.closeAll(); // 資料異常需要關閉彈出層 //mylayer.msg("網路繁忙,請重新整理頁面重試",{icon:2,time:1500}); } }); }, //驗證上傳圖片相關微信介面 wxUploadImgCheck : function(callback){ wx.ready(function () { wx.checkJsApi({ jsApiList: [ 'chooseImage', 'uploadImage', 'downloadImage', 'getLocalImgData' ], success: function (res) { if (res.checkResult.getLocation == false) { //mylayer.msg('你的微信版本太低,不支援微信JS介面,請升級到最新的微信版本!',{icon:2,time:1500}); return; } if(typeof callback == "function"){ callback(res); } } }); }); } };
2.微信前端呼叫掃一掃方法wechatmbl.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <html> <head> <title> </title> <!--引用微信JS庫--> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script> <!--引用jQuery庫--> <script type="text/javascript" src="<%=basePath%>static/js/jquery-2.1.4.js"></script> <script type="text/javascript" src="<%=basePath%>static/js/wechatOpt.js"></script> <script type="text/javascript" src="<%=basePath%>static/js/layer.js"></script> <meta charset="utf-8"> <script type="text/javascript"> var basePath = '<%=basePath%>'; var url = basePath+ "wechat/page/shware/getWxScanSign.do"; weChatObj.wxScanConfig(url,callback); //掃一掃的回撥函式 function callback(res){ var result = JSON.parse(res.resultStr); alert(result); } </script> </head> <body> <!-- <input type="button" value="掃一掃" id="scanQRCode"> --> <!-- <img src="static/Screenshot_20181031-104946.jpg"> --> </body> </html>
3.Https請求工具類HttpsUtil.java
package com.taxsearch.util.KBUtil; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ConnectException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.json.JSONObject; public class HttpsUtil { private static Logger log = LoggerFactory.getLogger(HttpsUtil.class); /** * @Title: httpsRequest * @Description: (HTTP請求) * @param: @param requestUrl * @param: @param requestMethod * @param: @param outputStr * @param: @return * @return: JSONObject * @throws */ public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; try { // 建立SSLContext物件,並使用我們指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 從上述SSLContext物件中得到SSLSocketFactory物件 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // 設定請求方式(GET/POST) conn.setRequestMethod(requestMethod); // 當outputStr不為null時向輸出流寫資料 if (null != outputStr) { OutputStream outputStream = conn.getOutputStream(); // 注意編碼格式 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 從輸入流讀取返回內容 InputStream inputStream = conn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } // 釋放資源 bufferedReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; conn.disconnect(); jsonObject = JSONObject.fromObject(buffer.toString()); } catch (ConnectException ce) { log.error("連線超時:{}", ce); } catch (Exception e) { log.error("https請求異常:{}", e); } return jsonObject; } }
4.微信掃一掃後臺介面,獲取access_token,簽名等WechatMblController.java
package com.taxsearch.controller.kp;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.taxsearch.commons.BaseController;
import com.taxsearch.commons.Logger;
import com.taxsearch.util.Json;
import com.taxsearch.util.KBUtil.HttpsUtil;
/**
*
* <移動端-商品掃描Controller>
* @author swj
* @version [版本號, 2017年4月24日]
* @see [相關類/方法]
* @since [產品/模組版本]
*/
@Controller("wechatMblController")
public class WechatMblController{
private static final Logger log = Logger.getLogger(BaseController.class);
/**
*
* @file_name : WechatMblController.java
* @method : wechat
* @description : 進入掃描頁面
* @author : linsa
* @return
* @date : 2018年11月2日
* @return : ModelAndView
*/
@RequestMapping(value="/wechat")
public ModelAndView wechat(){
ModelAndView mv=new ModelAndView();
mv.setViewName("wl/wechatmbl");
return mv;
}
/**
*
* <獲取微信掃一掃簽名>
* @author swj
* @date 2017年4月24日
* @param request
* @param response
* @param session
* @param model
* @see [類、類#方法、類#成員]
*/
@RequestMapping("wechat/page/shware/getWxScanSign")
@ResponseBody
public Json getWxScanSign(HttpServletRequest request,
HttpServletResponse response, HttpSession session, Model model){
Json retMap = new Json();
String appId = "wxb92dcb6ac93f8e5a";
String appsecret = "f68bd7d86973392e1f6ead8775b8931d";
//獲取access_token
String access_token = getToken(appId, appsecret);
//獲取JSTicket
String sJsapiTicket = getJSTicket(access_token);
Map<String,String> signResult = new HashMap<String,String>();
String jsUrl = Str(request.getParameter("s_url"));
log.info("獲取呼叫頁面: "+jsUrl);
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = getCharAndNumr(15);
try {
String signature = getSignature(sJsapiTicket, timestamp, nonceStr,jsUrl);
signResult.put("appId", appId);
signResult.put("timestamp", timestamp);
signResult.put("nonceStr", nonceStr);
signResult.put("signature", signature);
retMap.setSuccess(true);
retMap.setMsg("微信API簽名獲取成功!");
retMap.setObj(signResult);
log.info("獲取微信簽名完成:"+signResult+", jsUrl: "+jsUrl+",sJsapiTicket: "+sJsapiTicket);
} catch (Exception e) {
e.printStackTrace();
retMap.setSuccess(false);
retMap.setMsg("微信API簽名獲取失敗!");
}
return retMap;
}
public String getSignature(String jsapi_ticket, String timestamp,
String nonce, String jsurl) throws Exception {
/****
* 對 jsapi_ticket、 timestamp 和 nonce 按字典排序 對所有待簽名引數按照欄位名的 ASCII
* 碼從小到大排序(字典序)後,使用 URL 鍵值對的格式(即key1=value1&key2=value2…)拼接成字串
* string1。這裡需要注意的是所有引數名均為小寫字元。 接下來對 string1 作 sha1 加密,欄位名和欄位值都採用原始值,不進行
* URL 轉義。即 signature=sha1(string1)。
* **如果沒有按照生成的key1=value&key2=value拼接的話會報錯
*/
String[] paramArr = new String[] { "jsapi_ticket=" + jsapi_ticket,
"timestamp=" + timestamp, "noncestr=" + nonce, "url=" + jsurl };
Arrays.sort(paramArr);
// 將排序後的結果拼接成一個字串
String content = paramArr[0].concat("&" + paramArr[1])
.concat("&" + paramArr[2]).concat("&" + paramArr[3]);
// System.out.println("拼接之後的content為:"+content);
String gensignature = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 對拼接後的字串進行 sha1 加密
byte[] digest = md.digest(content.toString().getBytes());
gensignature = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
// e.printStackTrace();
log.error(e);
}
// 將 sha1 加密後的字串與 signature 進行對比
if (gensignature != null) {
return gensignature;// 返回signature
} else {
return "false";
}
}
/**
* 將位元組陣列轉換為十六進位制字串
*
* @param byteArray
* @return
*/
private String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 將位元組轉換為十六進位制字串
*
* @param mByte
* @return
*/
private String byteToHexStr(byte mByte) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
public String getCharAndNumr(int length) {
String val = "";
Random random = new Random();
for (int i = 0; i < length; i++) {
// 輸出字母還是數字
String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
// 字串
if ("char".equalsIgnoreCase(charOrNum)) {
// 取得大寫字母還是小寫字母
int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
val += (char) (choice + random.nextInt(26));
} else if ("num".equalsIgnoreCase(charOrNum)) { // 數字
val += String.valueOf(random.nextInt(10));
}
}
return val;
}
public String Str(Object obj){
String str = "";
if(obj!=null&&obj!=""){
str = obj.toString();
}
return str;
}
/**
* 獲取access_token
* @author gaomin
* @date 2018/11/2
*
*/
public String getToken(String appId, String appsecret){
String infoUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
+appId+"&secret="+appsecret;
JSONObject result = HttpsUtil.httpsRequest(infoUrl, "GET", null);
String access_token = "";
if(result.containsKey("errcode")){
access_token = "";
}else{
access_token = (String)result.get("access_token");
}
return access_token;
}
/**
* 獲取JSTicket
* @author gaomin
* @date 2018/11/2
*
*/
public String getJSTicket(String access_token){
String infoUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token="
+ access_token;
JSONObject result = HttpsUtil.httpsRequest(infoUrl, "GET", null);
String jsTicket = (String)result.get("ticket");
return jsTicket;
}
}