JSSDK JAVA开发第一步:绑定域名
先登录微信公众平台进入“公众号设置”(作者:在页面左下角,认证订阅号,认证服务号皆可配置)
(备注:登录后可在“开发者中心”可查看对应的接口权限。)
再选择页面上方“功能设置”
这时可以看到“JS接口安全域名”。点击设置弹出以下输入框,按照要求填写域名(注意:IP不可用)
如:www.ipastimes.com, ipastimes.com, examples.ipastimes.com 可用
JSSDK JAVA开发第二步:引入微信JS
在需要引用微信JS接口的页面引入微信js文件(微信在其浏览器内置wx对象)http://res.wx.qq.com/open/js/jweixin-1.0.0.js
JSSDK JAVA开发第三步:后台实现签名逻辑
1.获取access_token
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/**
* 获取接口访问凭证
*
* @param appid 凭证
* @param appsecret 密钥
* @return
*/
public
static
String getAccess_token(String appid, String appsecret) {
//凭证获取(GET)
String token_url =
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"
;
String requestUrl = token_url.replace(
"APPID"
, appid).replace(
"APPSECRET"
, appsecret);
// 发起GET请求获取凭证
JSONObject jsonObject = httpsRequest(requestUrl,
"GET"
,
null
);
String access_token =
null
;
if
(
null
!= jsonObject) {
try
{
access_token = jsonObject.getString(
"access_token"
);
}
catch
(JSONException e) {
// 获取token失败
log.error(
"获取token失败 errcode:{} errmsg:{}"
, jsonObject.getInt(
"errcode"
), jsonObject.getString(
"errmsg"
));
}
}
return
access_token;
}
|
2.获取jsapi_ticket
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/**
* 调用微信JS接口的临时票据
*
* @param access_token 接口访问凭证
* @return
*/
public
static
String getJsApiTicket(String access_token) {
String url =
"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi"
;
String requestUrl = url.replace(
"ACCESS_TOKEN"
, access_token);
// 发起GET请求获取凭证
JSONObject jsonObject = httpsRequest(requestUrl,
"GET"
,
null
);
String ticket =
null
;
if
(
null
!= jsonObject) {
try
{
ticket = jsonObject.getString(
"ticket"
);
}
catch
(JSONException e) {
// 获取token失败
log.error(
"获取token失败 errcode:{} errmsg:{}"
, jsonObject.getInt(
"errcode"
), jsonObject.getString(
"errmsg"
));
}
}
return
ticket;
}
|
3.实现签名逻辑(根据官方sample改)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
import
java.io.UnsupportedEncodingException;
import
java.security.MessageDigest;
import
java.security.NoSuchAlgorithmException;
import
java.text.SimpleDateFormat;
import
java.util.Date;
import
java.util.Formatter;
import
java.util.HashMap;
import
java.util.Map;
import
java.util.UUID;
import
javax.servlet.http.HttpServletRequest;
import
net.sf.json.JSONObject;
import
org.apache.struts2.ServletActionContext;
public
class
PastUtil {
public
static
Token token =
null
;
public
static
String time =
null
;
public
static
String jsapi_ticket =
null
;
/**
*
* @param appId 公账号appId
* @param appSecret
* @param url 当前网页的URL,不包含#及其后面部分
* @return
*/
public
static
String getParam(String appId,String appSecret){
if
(token ==
null
){
token = CommonUtil.getToken(appId, appSecret);
jsapi_ticket = CommonUtil.getJsApiTicket(token.getAccessToken());
time = getTime();
}
else
{
if
(!time.substring(
0
,
13
).equals(getTime().substring(
0
,
13
))){
//每小时刷新一次
token =
null
;
token = CommonUtil.getToken(appId, appSecret);
jsapi_ticket = CommonUtil.getJsApiTicket(token.getAccessToken());
time = getTime();
}
}
String url = getUrl();
Map
params.put(
"appid"
, appId);
JSONObject jsonObject = JSONObject.fromObject(params);
String jsonStr = jsonObject.toString();
System.out.println(jsonStr);
return
jsonStr;
}
private
static
String getUrl(){
HttpServletRequest request = ServletActionContext.getRequest();
StringBuffer requestUrl = request.getRequestURL();
String queryString = request.getQueryString();
String url = requestUrl +
"?"
+queryString;
return
url;
}
public
static
Map
Map
new
HashMap
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String str;
String signature =
""
;
//注意这里参数名必须全部小写,且必须有序
str =
"jsapi_ticket="
+ jsapi_ticket +
"&noncestr="
+ nonce_str +
"×tamp="
+ timestamp +
"&url="
+ url;
try
{
MessageDigest crypt = MessageDigest.getInstance(
"SHA-1"
);
crypt.reset();
crypt.update(str.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
);
}
//获取当前系统时间 用来判断access_token是否过期
public
static
String getTime(){
Date dt=
new
Date();
SimpleDateFormat sdf =
new
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
);
return
sdf.format(dt);
}
}
|
大部分开发者在签名认证处出错,开启debug模式,当进入页面时会alert出如下信息:
按照如下步骤排错:
1.确认签名算法正确,可用 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。
2.确认config中noncestr, timestamp与用以签名中的对应noncestr, timestamp一致。
3.确认url是页面完整的url,包括GET参数部分。
4.确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。
5.确保一定缓存access_token和jsapi_ticket,可以减少两次服务器请求加速体验外,还避免了触发频率限制,提高服务稳定性。
附JS SDK权限表
更多信息请参考:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html