(一)token的介绍
引用:access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效!
(二)token的获取参考文档
获取的流程我们完全可以参考微信官方文档:http://mp.weixin.qq.com/wiki/14/9f9c82c1af308e3b14ba9b973f99a8ba.html 如图:
(三)token获取流程分析
从公众平台获取账号的AppID和AppSecret;
token获取并解析存储执行体;
采用任务调度每隔两小时执行一次token获取执行体;
(四)token的获取流程的具体实现
①获取appid和appsecret
在微信公众平台【开发】——>【基本配置】中可以查看到我们需要的两个参数:
这里我们将他们定义到我们的配置文件【wechat.properties】中,大致代码为:
1
2
3
4
|
#获取到的appid
appid=wx7e32765bc24XXXX
#获取到的AppSecret
AppSecret=d58051564fe9d86093f9XXXXX
|
②token获取并解析存储执行体的代码编写
由于在这里我们需要通过http的get请求向微信服务器获取时效性为7200秒的token,所以我在这里写了一个http请求的工具类,以方便我们的使用,如下:
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
|
package
com.cuiyongzhi.wechat.util;
import
java.io.BufferedInputStream;
import
java.io.BufferedReader;
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.InputStreamReader;
import
java.io.OutputStreamWriter;
import
java.net.MalformedURLException;
import
java.net.URI;
import
java.net.URL;
import
java.net.URLConnection;
import
java.util.ArrayList;
import
java.util.List;
import
java.util.Map;
import
java.util.Set;
import
java.util.zip.GZIPInputStream;
import
org.apache.http.HttpResponse;
import
org.apache.http.NameValuePair;
import
org.apache.http.client.ClientProtocolException;
import
org.apache.http.client.HttpClient;
import
org.apache.http.client.entity.UrlEncodedFormEntity;
import
org.apache.http.client.methods.HttpGet;
import
org.apache.http.client.methods.HttpPost;
import
org.apache.http.entity.StringEntity;
import
org.apache.http.impl.client.DefaultHttpClient;
import
org.apache.http.message.BasicNameValuePair;
import
org.apache.http.protocol.HTTP;
import
org.apache.http.util.EntityUtils;
/**
* ClassName: HttpUtils
*
* @Description: http请求工具类
* @author dapengniao
* @date 2016年3月10日 下午3:57:14
*/
@SuppressWarnings
(
"deprecation"
)
public
class
HttpUtils {
/**
* @Description: http get请求共用方法
* @param @param reqUrl
* @param @param params
* @param @return
* @param @throws Exception
* @author dapengniao
* @date 2016年3月10日 下午3:57:39
*/
@SuppressWarnings
(
"resource"
)
public
static
String sendGet(String reqUrl, Map
throws
Exception {
InputStream inputStream =
null
;
HttpGet request =
new
HttpGet();
try
{
String url = buildUrl(reqUrl, params);
HttpClient client =
new
DefaultHttpClient();
request.setHeader(
"Accept-Encoding"
,
"gzip"
);
request.setURI(
new
URI(url));
HttpResponse response = client.execute(request);
inputStream = response.getEntity().getContent();
String result = getJsonStringFromGZIP(inputStream);
return
result;
}
finally
{
if
(inputStream !=
null
) {
inputStream.close();
}
request.releaseConnection();
}
}
/**
* @Description: http post请求共用方法
* @param @param reqUrl
* @param @param params
* @param @return
* @param @throws Exception
* @author dapengniao
* @date 2016年3月10日 下午3:57:53
*/
@SuppressWarnings
(
"resource"
)
public
static
String sendPost(String reqUrl, Map
throws
Exception {
try
{
Set
List
new
ArrayList
for
(String key : set) {
list.add(
new
BasicNameValuePair(key, params.get(key)));
}
if
(list.size() >
0
) {
try
{
HttpClient client =
new
DefaultHttpClient();
HttpPost request =
new
HttpPost(reqUrl);
request.setHeader(
"Accept-Encoding"
,
"gzip"
);
request.setEntity(
new
UrlEncodedFormEntity(list, HTTP.UTF_8));
HttpResponse response = client.execute(request);
InputStream inputStream = response.getEntity().getContent();
try
{
String result = getJsonStringFromGZIP(inputStream);
return
result;
}
finally
{
inputStream.close();
}
}
catch
(Exception ex) {
ex.printStackTrace();
throw
new
Exception(
"网络连接失败,请连接网络后再试"
);
}
}
else
{
throw
new
Exception(
"参数不全,请稍后重试"
);
}
}
catch
(Exception ex) {
ex.printStackTrace();
throw
new
Exception(
"发送未知异常"
);
}
}
/**
* @Description: http post请求json数据
* @param @param urls
* @param @param params
* @param @return
* @param @throws ClientProtocolException
* @param @throws IOException
* @author dapengniao
* @date 2016年3月10日 下午3:58:15
*/
public
static
String sendPostBuffer(String urls, String params)
throws
ClientProtocolException, IOException {
HttpPost request =
new
HttpPost(urls);
StringEntity se =
new
StringEntity(params, HTTP.UTF_8);
request.setEntity(se);
// 发送请求
@SuppressWarnings
(
"resource"
)
HttpResponse httpResponse =
new
DefaultHttpClient().execute(request);
// 得到应答的字符串,这也是一个 JSON 格式保存的数据
String retSrc = EntityUtils.toString(httpResponse.getEntity());
request.releaseConnection();
return
retSrc;
}
/**
* @Description: http请求发送xml内容
* @param @param urlStr
* @param @param xmlInfo
* @param @return
* @author dapengniao
* @date 2016年3月10日 下午3:58:32
*/
public
static
String sendXmlPost(String urlStr, String xmlInfo) {
// xmlInfo xml具体字符串
try
{
URL url =
new
URL(urlStr);
URLConnection con = url.openConnection();
con.setDoOutput(
true
);
con.setRequestProperty(
"Pragma:"
,
"no-cache"
);
con.setRequestProperty(
"Cache-Control"
,
"no-cache"
);
con.setRequestProperty(
"Content-Type"
,
"text/xml"
);
OutputStreamWriter out =
new
OutputStreamWriter(
con.getOutputStream());
out.write(
new
String(xmlInfo.getBytes(
"utf-8"
)));
out.flush();
out.close();
BufferedReader br =
new
BufferedReader(
new
InputStreamReader(
con.getInputStream()));
String lines =
""
;
for
(String line = br.readLine(); line !=
null
; line = br
.readLine()) {
lines = lines + line;
}
return
lines;
// 返回请求结果
}
catch
(MalformedURLException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
return
"fail"
;
}
private
static
String getJsonStringFromGZIP(InputStream is) {
String jsonString =
null
;
try
{
BufferedInputStream bis =
new
BufferedInputStream(is);
bis.mark(
2
);
// 取前两个字节
byte
[] header =
new
byte
[
2
];
int
result = bis.read(header);
// reset输入流到开始位置
bis.reset();
// 判断是否是GZIP格式
int
headerData = getShort(header);
// Gzip 流 的前两个字节是 0x1f8b
if
(result != -
1
&& headerData ==
0x1f8b
) {
// LogUtil.i("HttpTask", " use GZIPInputStream ");
is =
new
GZIPInputStream(bis);
}
else
{
// LogUtil.d("HttpTask", " not use GZIPInputStream");
is = bis;
}
InputStreamReader reader =
new
InputStreamReader(is,
"utf-8"
);
char
[] data =
new
char
[
100
];
int
readSize;
StringBuffer sb =
new
StringBuffer();
while
((readSize = reader.read(data)) >
0
) {
sb.append(data,
0
, readSize);
}
jsonString = sb.toString();
bis.close();
reader.close();
}
catch
(Exception e) {
e.printStackTrace();
}
return
jsonString;
}
private
static
int
getShort(
byte
[] data) {
return
(data[
0
] <<
8
) | data[
1
] &
0xFF
;
}
/**
* 构建get方式的url
*
* @param reqUrl
* 基础的url地址
* @param params
* 查询参数
* @return 构建好的url
*/
public
static
String buildUrl(String reqUrl, Map
StringBuilder query =
new
StringBuilder();
Set
for
(String key : set) {
query.append(String.format(
"%s=%s&"
, key, params.get(key)));
}
return
reqUrl +
"?"
+ query.toString();
}
}
|
我们在做http请求的时候需要目标服务器的url,这里在项目中为了方便对url的管理我们在资源目录下建立了interface_url.properties用于存放目标url,这里我们将请求token的url存入:
1
2
|
#获取token的url
tokenUrl=https://api.weixin.qq.com/cgi-bin/token
|
我们需要将我们配置的配置文件在项目初始化后能得到启动,所以我在这里加入一个项目初始化的代码实现,用于项目启动初始化interface_url.properties和wechat.properties中的配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package
com.cuiyongzhi.web.start;
import
javax.servlet.ServletConfig;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
/**
* ClassName: InterfaceUrlIntiServlet
* @Description: 项目启动初始化servlet
* @author dapengniao
* @date 2016年3月10日 下午4:08:43
*/
public
class
InterfaceUrlIntiServlet
extends
HttpServlet {
private
static
final
long
serialVersionUID = 1L;
@Override
public
void
init(ServletConfig config)
throws
ServletException {
InterfaceUrlInti.init();
}
}
|
初始化的具体实现,将初始化过后的方法都存入到GlobalConstants中方便项目中随意调用,如下:
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
|
package
com.cuiyongzhi.web.start;
import
java.io.IOException;
import
java.io.InputStream;
import
java.util.Properties;
import
com.cuiyongzhi.web.util.GlobalConstants;
/**
* ClassName: InterfaceUrlInti
* @Description: 项目启动初始化方法
* @author dapengniao
* @date 2016年3月10日 下午4:08:21
*/
public
class
InterfaceUrlInti {
public
synchronized
static
void
init(){
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Properties props =
new
Properties();
if
(GlobalConstants.interfaceUrlProperties==
null
){
GlobalConstants.interfaceUrlProperties =
new
Properties();
}
InputStream in =
null
;
try
{
in = cl.getResourceAsStream(
"interface_url.properties"
);
props.load(in);
for
(Object key : props.keySet()){
GlobalConstants.interfaceUrlProperties.put(key, props.get(key));
}
props =
new
Properties();
in = cl.getResourceAsStream(
"wechat.properties"
);
props.load(in);
for
(Object key : props.keySet()){
GlobalConstants.interfaceUrlProperties.put(key, props.get(key));
}
}
catch
(IOException e) {
e.printStackTrace();
}
finally
{
if
(in!=
null
){
try
{
in.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
return
;
}
}
|
当我们把所有的准备工作都做好了之后我们可以开始真正的去获取token了,这里我们将获取到的token解析之后依然存储到GlobalConstants中方便使用,简单代码如下:
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
|
package
com.cuiyongzhi.wechat.common;
import
java.util.HashMap;
import
java.util.Map;
import
net.sf.json.JSONObject;
import
com.cuiyongzhi.web.util.GlobalConstants;
import
com.cuiyongzhi.wechat.util.HttpUtils;
/**
* ClassName: WeChatTask
* @Description: 微信两小时定时任务体
* @author dapengniao
* @date 2016年3月10日 下午1:42:29
*/
public
class
WeChatTask {
/**
* @Description: 任务执行体
* @param @throws Exception
* @author dapengniao
* @date 2016年3月10日 下午2:04:37
*/
public
void
getToken_getTicket()
throws
Exception {
Map
new
HashMap
params.put(
"grant_type"
,
"client_credential"
);
params.put(
"appid"
, GlobalConstants.getInterfaceUrl(
"appid"
));
params.put(
"secret"
, GlobalConstants.getInterfaceUrl(
"AppSecret"
));
String jstoken = HttpUtils.sendGet(
GlobalConstants.getInterfaceUrl(
"tokenUrl"
), params);
String access_token = JSONObject.fromObject(jstoken).getString(
"access_token"
);
// 获取到token并赋值保存
GlobalConstants.interfaceUrlProperties.put(
"access_token"
, access_token);
System.out.println(
new
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
).format(
new
Date())+
"token为=============================="
+access_token);
}
}
|
(三)采用任务调度每隔两小时执行一次token获取执行体
我们阅读过微信的文档会发现我们的token获取的接口每天是有调用次数限制的,为了防止我们业务量比较大的情况下token的直接调用的接口次数不够用,所以我们需要根据token的时效性(7200s)在自己的业务服务器上做到token的缓存并定时获取,我这里用到的任务调度的方式是采用quartz,有关quartz的使用可以参考文章 http://cuiyongzhi.com/?tags=%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1 ,下面具体代码的实现:
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
|
package
com.cuiyongzhi.wechat.quartz;
import
org.apache.log4j.Logger;
import
com.cuiyongzhi.wechat.common.WeChatTask;
public
class
QuartzJob{
private
static
Logger logger = Logger.getLogger(QuartzJob.
class
);
/**
* @Description: 任务执行获取token
* @param
* @author dapengniao
* @date 2016年3月10日 下午4:34:26
*/
public
void
workForToken() {
try
{
WeChatTask timer =
new
WeChatTask();
timer.getToken_getTicket();
|