1. 程式人生 > >微信公眾號掃一掃封裝介面

微信公眾號掃一掃封裝介面

一.微信準備功能

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;
	}
	
}