步骤三:通过config接口注入权限验证配置
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名,见附录1
jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
步骤四:通过ready接口处理成功验证
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
步骤五:通过error接口处理失败验证
wx.error(function(res){
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
具体的实现
<!DOCTYPE html>
<!-- saved from url=(0029)http://www.duomeina.com/d.asp -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>微信JS-SDK Demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
<link rel="stylesheet" href="./some/style2.css">
</head>
<body ontouchstart="">
<div class="wxapi_container">
<div class="lbox_close wxapi_form">
<button class="btn btn_primary" id="scanQRCode1" style="display:none;">点击扫描二维码</button>
<div id="result"></div>
</div>
</div>
<script src="./some/jweixin-1.js"></script>
<script src="./some/jquery-1.8.3.min.js"></script>
<script>
var appId = '';
var timestamp = 0;//为了让后台传过来的timetamp是数字类型 否则字符串 估计又会报config fail错误
var nonceStr = '';
var signature = '';
$(document).ready(function(){
init({//用init.js去请求服务器获得相应的数据 这里是我自己封装的ajax请求 就不贴出来了
url:"/testSaoMa/getticket",//这是servlet 具体的请根据自己的servlert地址去填写
dataType:"json",
showType:"return",
Deferred:false,
Callback:function(dta){//获取数据
appId = dta.appId;
timestamp = dta.timestamp;
nonceStr = dta.nonceStr;
signature = dta.signature;
/*
* 注意:
* 1. 所有的JS接口只能在公众号绑定的域名下调用,公众号开发者需要先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
* 2. 如果发现在 Android 不能分享自定义内容,请到官网下载最新的包覆盖安装,Android 自定义分享接口需升级至 6.0.2.58 版本及以上。
* 3. 常见问题及完整 JS-SDK 文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
*
* 开发中遇到问题详见文档“附录5-常见错误及解决办法”解决,如仍未能解决可通过以下渠道反馈:
* 邮箱地址:weixin-open@qq.com
* 邮件主题:【微信JS-SDK反馈】具体问题
* 邮件内容说明:用简明的语言描述问题所在,并交代清楚遇到该问题的场景,可附上截屏图片,微信团队会尽快处理你的反馈。
*/
wx.config({//开始微信的配置 将获取的数据拿去请求
debug: false,
appId: appId,
timestamp: timestamp,
nonceStr: nonceStr,
signature: signature,
jsApiList: [//可以调用下面的接口 我们这里只是调用scanQRCode 也就是扫码接口
'checkJsApi',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'onMenuShareQZone',
'hideMenuItems',
'showMenuItems',
'hideAllNonBaseMenuItem',
'showAllNonBaseMenuItem',
'translateVoice',
'startRecord',
'stopRecord',
'onVoiceRecordEnd',
'playVoice',
'onVoicePlayEnd',
'pauseVoice',
'stopVoice',
'uploadVoice',
'downloadVoice',
'chooseImage',
'previewImage',
'uploadImage',
'downloadImage',
'getNetworkType',
'openLocation',
'getLocation',
'hideOptionMenu',
'showOptionMenu',
'closeWindow',
'scanQRCode',
'chooseWXPay',
'openProductSpecificView',
'addCard',
'chooseCard',
'openCard'
]
});
wx.ready(function () {
// 9.1.2 扫描二维码并返回结果
wx.scanQRCode({
needResult: 1,
desc: 'scanQRCode desc',
success: function (res) {
//alert(JSON.stringify(res));
//document.getElementById("result").innerHtml=JSON.stringify(res);
//$("#result").html(JSON.stringify(res));
$("#result").html(res.resultStr);
}
});
});
wx.error(function (res) {//错误时调用
alert(res.errMsg);
});
}
});
})
</script>
<script src="./some/zepto.js"></script>
<script src="init.js"></script>
</body></html>
上面颜色不同的部分就是配置微信的过程那是固定不变的
微信JSSdk里面给出了一个方法 不需要导入任何的包 能获得 timestamp nonceStr
package com.weixin.util;
import java.util.UUID;
import com.alibaba.fastjson.JSONObject;
import java.util.Map;
import java.util.HashMap;
import java.util.Formatter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;
class Sign {
/**
* 获取nonce_str timestamp signature的方法
* @param jsapi_ticket 传入的ticket
* @param url 传入需要在微信中打开扫码的url
* @return map
*/
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;
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;
}
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
三:写Servlet(spring里面的Controller也行)来控制
Servlet代码
package com.weixin.util;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.annotations.Since;
/**
* Servlet implementation class getticket
*/
@WebServlet("/getticket")
public class getticket extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public getticket() {
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());
doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// doGet(request, response);
String jsapi_ticket = HttpUtil.getJsTicket();
String jsonstr = "{\"appId\":\""+WX_Token.APPID+"\",";
// 注意 URL 一定要动态获取
String url = "http://lg.kezir.com/testSaoMa/jsDemo.html";
Map<String, String> ret = Sign.sign(jsapi_ticket, url);
for (Map.Entry entry : ret.entrySet()) {
jsonstr += "\""+entry.getKey() + "\":\"" + entry.getValue()+"\",";
}
jsonstr = jsonstr.substring(0,jsonstr.length()-1);
jsonstr +="}";
System.out.println(jsonstr);
response.getWriter().println(jsonstr);
}
}
图解
现在就只剩下方法Http.getJsTicket()没讲了(url直接设置分享的网址就行了)
这是用来获取ticket的
1先根据appId和appSecret获取access_token
2再根据access_token获取ticket
获取ticket接口调用请求说明
http请求方式: GET
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=wx_card
package com.weixin.util;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class HttpUtil {
private static String access_Token = "";
/**
* get请求获取网址
* @param url
* @param charset
* @return
*/
public static String sendGet(String url,String charset){
CloseableHttpClient httpClient=HttpClients.createDefault();
HttpGet get=new HttpGet(url);
CloseableHttpResponse response = null;
String result=null;
try {
response=httpClient.execute(get);
HttpEntity entity=response.getEntity();
//System.out.println(entity.getContentType().getValue());
result=EntityUtils.toString(entity,charset);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
//获取tickect
public static String getJsTicket(){
JSONObject jsonObject = new JSONObject();
String ticket = "";
if(access_Token ==""){//如果是第一次获取就直接去请求新的
ticket = getTicket();
}else{//否则就请求旧的
String result = sendGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+access_Token+"&type=jsapi","UTF-8");
jsonObject = JSON.parseObject(result);
String resultCode = jsonObject.getString("errcode");
if(resultCode !="0"){//请求旧的如果不行
ticket = getTicket();//再去请求新的
}
else{//如果请求的新的ok
ticket = jsonObject.getString("ticket");//直接获取
}
}
return ticket;
}
/**
* 获取最新的ticket
* @return
*/
public static String getTicket(){
JSONObject jsonObject = new JSONObject();
access_Token = WX_Token.getAccessTokenByNet().getAccess_token();//获取Access_token代码就不贴了
String result = sendGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+WX_Token.getAccessTokenByNet().getAccess_token()+"&type=jsapi","UTF-8");
jsonObject = JSON.parseObject(result);
return jsonObject.getString("ticket");
}
}
![]()