先
說明本人是個新手,負責人要求我在公司的微信公眾號H5界面中添加一個掃一掃功能,這對於我來說還是個不小的挑戰,因為之前的公眾號開發大部分都是公司的前輩的開發的。對於微信接口的使用,我一點都不熟悉。
廢話少說,現在我分享一下調用微信掃一掃的過程及代碼,系統框架采用的是SSH框架。
開發掃一掃的滿足條件:
一、需要微信公眾號的APP_ID
二、需要微信公眾號的開發者密碼AppSecret(如何查看AppSecreti:開發-基本配置-開發者密碼-重置 管理員掃碼即可看到)
三、需要一個內網穿透的軟件,我使用的是natapp
四、在微信公眾號中將自己的本機Ip添加到IP白名單中
滿足以上條件,那么我們就可以進行微信掃一掃的接口調用
首先創建微信配置工具類(部分代碼是來自網上的大牛們的代碼,由於瀏覽了幾天幾夜的網頁,具體是誰的我也搞不清了)
微信簽名類
package com.item.config;
import java.util.UUID;
import java.util.Map;
import java.util.HashMap;
import java.util.Formatter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;
public class Sign {
/* public static void main(String[] args) {
//獲取ticket
String ticket = WxUtils.getTicket();
// 注意 URL 一定要動態獲取,不能 hardcode
String url = "http://"+WxUtils.APP_DOMAIN+"/RAFFLE/gotoLetter";
Map<String, String> ret = sign(ticket, url);
for (Map.Entry entry : ret.entrySet()) {
System.out.println(entry.getKey() + ", " + entry.getValue());
}
}*/
/**
* 用於微信簽名
* //簽名生成規則如下:參與簽名的字段包括noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其后面部分)
* @param jsapi_ticket
* @param url 當前網頁的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 = "";
//注意這里參數名必須全部小寫,且必須有序
string1 = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + nonce_str +
"×tamp=" + 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;
}
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;
}
/**
* 創建隨機字符串
* @return
*/
private static String create_nonce_str() {
return UUID.randomUUID().toString().replace("-", "");
}
/**
* 創建隨機時間戳,保證每次的都不一樣
* @return
*/
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
獲取微信Ticket類
package com.item.config;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import net.sf.json.JSONObject;
public class WxUtils {
private static String APP_ID = "填寫你的APP_ID";
private static String AppSecret = "填寫你的Sercret";
public static String APP_DOMAIN ="填寫你的域名比如xx.com";
public static String getTicket(){
//grant_type:獲取access_token填寫client_credential || appid:第三方用戶唯一憑證 || secret:第三方用戶唯一憑證密鑰
String urlToken="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APP_ID+"&secret="+AppSecret+"";
String backToken = sendGet(urlToken,"utf-8",60000);
System.out.println("token:"+backToken);
String accessToken = (String) JSONObject.fromObject(backToken).get("access_token");
String url="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi";
String backTicket = sendGet(url,"utf-8",60000);
System.out.println("Ticket:"+backTicket);
String ticket = (String) JSONObject.fromObject(backTicket).get("ticket");
return ticket;
}
/**
*
* @title getAccessToken
* @Description 獲取訪問令牌
* @Date 2018-5-18上午11:07:18
* @return
*/
public static String getAccessToken(){
String url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APP_ID+"&secret="+AppSecret+"";
String backData = sendGet(url,"utf-8",10000);
String accessToken = (String) JSONObject.fromObject(backData).get("access_token");
return accessToken;
}
/**
*
* @title sendGet
* @Description
* @param url
* @param charset
* @param timeout
* @return
*/
public static String sendGet(String url, String charset, int timeout)
{
String result = "";
try
{
URL u = new URL(url);
try
{
URLConnection conn = u.openConnection();
conn.connect();
conn.setConnectTimeout(timeout);
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
String line="";
while ((line = in.readLine()) != null)
{
result = result + line;
}
in.close();
} catch (IOException e) {
return result;
}
}
catch (MalformedURLException e)
{
return result;
}
return result;
}
}
ScanAction類:進行微信簽名並存入Map中
package com.code.action.front;
import java.util.Map;
import com.code.action.BaseAction;
import com.item.config.Sign;
import com.item.config.WxUtils;
public class ScanAction extends BaseAction {
private Map<String, String> sign;
/*public static void main(String[] args) {
// 獲取ticket數據
String jsapi_ticket = WxUtils.getTicket();
String url = "http://" + WxUtils.APP_DOMAIN + "/調用微信接口所在的路徑下的jsp文件,由於我使用的是通過action進行跳轉,那么對應的就是寫你跳轉到該網頁的Action";
Map<String, String> sign = Sign.sign(jsapi_ticket, url);
for (Map.Entry entry : sign.entrySet()) {
System.out.println(entry.getKey() + "," + entry.getValue());
}
}*/
/**
* 進行微信簽名並存入Map中,在再跳轉到前端中,Map對象的值通過EL表達式進行獲取對象的值
* @author chenbufu
* @return
*/
public String getWxConfig() {
System.out.println("獲取微信配置");
// 獲取ticket數據
String jsapi_ticket = WxUtils.getTicket();
String url = "http://" + WxUtils.APP_DOMAIN + "/項目名/xx.action";
sign = Sign.sign(jsapi_ticket, url);
for (Map.Entry entry : sign.entrySet()) {
System.out.println(entry.getKey() + "," + entry.getValue());
}
System.out.println("----------" + jsapi_ticket);
return "success";
}
public Map<String, String> getSign() {
return sign;
}
public void setSign(Map<String, String> sign) {
this.sign = sign;
}
}
跳轉到前端代碼:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>管理</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link rel="stylesheet"
href="${pageContext.request.contextPath}/pub/js/imgbox/css/lrtk.css"
type="text/css" media="all" />
<script type="text/javascript"
src="${pageContext.request.contextPath}/pub/js/imgbox/jquery.min.js"></script>
<script type="text/javascript"
src="${pageContext.request.contextPath}/pub/js/imgbox/jquery.imgbox.pack.js"></script>
<link rel="stylesheet"
href="${pageContext.request.contextPath}/pub/css/bg/style.css"
type="text/css" media="all" />
<script type="text/javascript"
src="${pageContext.request.contextPath}/pub/js/jquery.idTabs.min.js"></script>
</head>
<body
style="margin:0px;padding:0px;overflow:hidden;padding-top:5px;widht:320px;">
《!--用於測試傳遞過來的參數
<table>
<tr>
<td>jsapi_ticket:</td>
<td>${sign.jsapi_ticket}</td>
</tr>
<tr>
<td>url:</td>
<td>${sign.url}</td>
</tr>
<tr>
<td>nonceStr:</td>
<td>${sign.nonceStr}</td>
</tr>
<tr>
<td>timestamp:</td>
<td>"${sign.timestamp}"</td>
</tr>
<tr>
<td>signature:</td>
<td>${sign.signature}</td>
</tr>
</table>
--》
<h3 id="menu-scan">微信掃一掃</h3> <span class="desc">調起微信掃一掃接口</span> <button class="btn btn_primary" id="scanQRCode0">scanQRCode(微信處理結果)</button> <button class="btn btn_primary" id="scanQRCode1">scanQRCode(直接返回結果)</button> </body> <script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> <script type="text/javascript"> wx.config({ debug : true, appId : 'wx808ff7c908d83c7c',//必填 timestamp : "${sign.timestamp}",//必填 nonceStr : "${sign.nonceStr}",//必填 signature : "${sign.signature}",//必填 jsApiList : [ 'checkJsApi', 'scanQRCode' ]//調用的接口,必填 }); //end_config alert(location.href.split('#')[0]); wx.error(function(res) { alert("出錯了:" + res.errMsg); }); // 9 微信原生接口 // 9.1.1 掃描二維碼直接跳轉 document.querySelector('#scanQRCode0').onclick = function () { wx.scanQRCode(); }; // 9.1.2 掃描二維碼並返回結果 document.querySelector('#scanQRCode1').onclick = function () { wx.scanQRCode({ needResult: 1, desc: 'scanQRCode desc', success: function (res) { alert(JSON.stringify(res)); } }); }; </script> </html>
如果報config: invalid signature..請點擊此參考連接進行排查錯誤:https://www.cnblogs.com/buoge/p/4522666.html
我之前一直卡在config: invalid signature 這個報錯過程中,通過在script代碼塊中輸入alert(location.href.split('#')[0]);語句,發現與我后台的url地址不同,后台寫的是具體的jsp路徑,而前台打印的是具體的action跳轉,於是我把后台的url改成action跳轉后就沒報錯了。
