您的位置:首页 > 移动开发 > 微信开发

微信公众号入门笔记(四)获取access_token

2016-01-31 10:55 441 查看
作者:zhutulang

 

以下是微信公众平台开发者文档中截取的内容:

 

access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。

接口调用请求说明

http请求方式: GET

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

参数说明

参数

是否必须

说明

grant_type



获取access_token填写client_credential

appid



第三方用户唯一凭证

secret



第三方用户唯一凭证密钥,即appsecret

返回说明

正常情况下,微信会返回下述JSON数据包给公众号:

{"access_token":"ACCESS_TOKEN","expires_in":7200}

参数

说明

access_token

获取到的凭证

expires_in

凭证有效时间,单位:秒

 

 

那么,从以上的说明中我们知道:

(1)我们需要以get方式发送https请求。

(2)appid和secret 可以从我们的公众号后台查看。

(3)目前,access_token的有效期目前为2个小时,我们需要提供一个定时刷新机制。并且最好能有一个强制刷新的机制。

 

一、如何发送https请求

对于第一点,用HttpClient包发送https请求,核心思路就是忽略校验过程,代码参考自:

http://blog.csdn.net/rongyongfeikai2/article/details/41659353

 

SSLClient 类如下:

 package com.dongliushui.util;

importjava.security.cert.CertificateException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
importorg.apache.http.conn.scheme.SchemeRegistry;
importorg.apache.http.conn.ssl.SSLSocketFactory;
importorg.apache.http.impl.client.DefaultHttpClient;

/**
*@ClassName: SSLClient
*@Description: 用于进行Https请求的HttpClient
*@author (代码来源):http://blog.csdn.net/rongyongfeikai2/article/details/41659353
*@date 2016年1月8日
*@version V1.0
*/
public class SSLClient extendsDefaultHttpClient {

publicSSLClient() throws Exception{
super();
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {

@Override
publicvoid checkClientTrusted(
java.security.cert.X509Certificate[]chain, String authType)
throwsCertificateException {
//TODO Auto-generated method stub

}

@Override
publicvoid checkServerTrusted(
java.security.cert.X509Certificate[]chain, String authType)
throwsCertificateException {
//TODO Auto-generated method stub

}

@Override
publicjava.security.cert.X509Certificate[] getAcceptedIssuers() {
//TODO Auto-generated method stub
returnnull;
}

};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = newSSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = this.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", 443, ssf));
}
}

 

HttpUtil 类如下:

package com.dongliushui.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.sf.json.JSONObject;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
importorg.apache.http.client.entity.UrlEncodedFormEntity;
importorg.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
importorg.apache.http.impl.client.DefaultHttpClient;
importorg.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

/**
*@ClassName: HttpUtil
* @Description:Http请求工具类
*@author zhutulang
*@date 2016年1月8日
*@version V1.0
*/
public class HttpUtil {

/**
* <p>Title: doHttpsPost</p>
* <p>Description: 发送https 形式的post请求</p>
* @param url 请求url
* @param contentType
* @param paramMap 参数map
* @return
* @author zhutulang
* @version 1.0
*/
publicstatic byte[] doHttpsPostJson(String url, String contentType, Map<String,String> paramMap){
returnpostJson(1, url, contentType, paramMap);
}

/**
* <p>Title: doHttpsPost</p>
* <p>Description: 发送http 形式的post请求</p>
* @param url 请求url
* @param contentType
* @param paramMap 参数map
* @return
* @author zhutulang
* @version 1.0
*/
publicstatic byte[] doPostJson(String url, String contentType, Map<String,String> paramMap){
return postJson(0, url, contentType,paramMap);
}

/**
* <p>Title: doHttpsGet</p>
* <p>Description: 发送https 形式的get请求</p>
* @param url 请求url
* @param contentType
* @return
* @author zhutulang
* @version 1.0
*/
publicstatic byte[] doHttpsGet(String url, String contentType){
returnget(1, url, contentType);
}

/**
* <p>Title: doGet</p>
* <p>Description: 发送http 形式的gett请求</p>
* @param url 请求url
* @param contentType
* @return
* @author zhutulang
* @version 1.0
*/
publicstatic byte[] doGet(String url, String contentType){
returnget(0, url, contentType);
}

/**
* <p>Title: post</p>
* <p>Description: 发送post请求,表单提交参数</p>
* @param type 0:普通post请求 1:https形式的post请求
* @param url 请求url
* @param contentType
* @param paramMap 参数map
* @return
* @author zhutulang
* @version 1.0
*/
privatestatic byte[] postCommon(int type, String url, String contentType,Map<String, String> paramMap){
//响应内容
byte[] bs = null;

HttpClient httpClient = null;
HttpPost httpPost = null;

try {

if(type == 0){
//创建发送 http 请求的httpClient实例
httpClient= new DefaultHttpClient();
}else if(type == 1){
//创建发送 https 请求的httpClient实例
httpClient= new SSLClient();
}

// 创建HttpPost
httpPost = new HttpPost(url);
httpPost.setHeader("content-type", contentType);
//设置参数
List<NameValuePair> list = newArrayList<NameValuePair>();
if(paramMap != null){
Iterator<Entry<String, String>>iterator = paramMap.entrySet().iterator();
while(iterator.hasNext()){
Entry<String,String> elem =(Entry<String, String>) iterator.next();
list.add(newBasicNameValuePair(elem.getKey(),elem.getValue()));
}
if(list.size() > 0){
UrlEncodedFormEntity entity = newUrlEncodedFormEntity(list,"UTF-8");
httpPost.setEntity(entity);
}
}
// 执行POST请求
HttpResponse response =httpClient.execute(httpPost);
// 获取响应实体
HttpEntity entity = response.getEntity();
if(entity != null){
bs = EntityUtils.toByteArray(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接,释放资源
httpClient.getConnectionManager().shutdown();
httpPost = null;
httpClient = null;
}
return bs;
}

/**
* <p>Title: post</p>
* <p>Description: 发送post请求,json方式提交参数</p>
* @param type 0:普通post请求 1:https形式的post请求
* @param url 请求url
* @param contentType
* @param paramMap 参数map
* @return
* @author zhutulang
* @version 1.0
*/
privatestatic byte[] postJson(int type, String url, String contentType, Map<String,String> paramMap){
//响应内容
byte[] bs = null;

HttpClient httpClient = null;
HttpPost httpPost = null;

try {

if(type == 0){
//创建发送 http 请求的httpClient实例
httpClient= new DefaultHttpClient();
}else if(type == 1){
//创建发送 https 请求的httpClient实例
httpClient= new SSLClient();
}

// 创建HttpPost
httpPost = new HttpPost(url);
httpPost.setHeader("content-type", contentType);
if(paramMap != null){
Iterator<Entry<String, String>>iterator = paramMap.entrySet().iterator();
// 接收参数json列表
JSONObject jsonParam = newJSONObject();
while(iterator.hasNext()){
Entry<String,String> elem =(Entry<String, String>) iterator.next();
jsonParam.put(elem.getKey(),elem.getValue());
}
if(jsonParam.size() > 0){
StringEntity entity = newStringEntity(jsonParam.toString(),"UTF-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
}
}
// 执行POST请求
HttpResponse response =httpClient.execute(httpPost);
// 获取响应实体
HttpEntity entity = response.getEntity();
if(entity != null){
bs = EntityUtils.toByteArray(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接,释放资源
httpClient.getConnectionManager().shutdown();
httpPost = null;
httpClient = null;
}
return bs;
}

/**
* <p>Title: get</p>
* <p>Description: 发送get请求</p>
* @param type 0:普通get请求 1:https形式的get请求
* @param url 请求url
* @param contentType
* @return
* @author zhutulang
* @version 1.0
*/
privatestatic byte[] get(int type, String url, String contentType){
//响应内容
byte[] bs = null;

HttpClient httpClient = null;
HttpGet httpGet = null;

try {
if(type == 0){
//创建发送 http 请求的httpClient实例
httpClient= new DefaultHttpClient();
}else if(type == 1){
//创建发送 https 请求的httpClient实例
httpClient= new SSLClient();
}

// 创建HttpPost
httpGet = new HttpGet(url);
httpGet.setHeader("content-type", contentType);
// 执行POST请求
HttpResponse response =httpClient.execute(httpGet);
// 获取响应实体
HttpEntity entity = response.getEntity();
if(entity != null){
bs = EntityUtils.toByteArray(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接,释放资源
httpClient.getConnectionManager().shutdown();
httpGet = null;
httpClient = null;
}
return bs;
}
}

二、如何定时刷新access_token

在集群环境中,这个问题可能会比较复杂。我们可能需要考虑到在集群中各个机器的任务调度协调,对于获取到的access_token,我们可能会考虑将它保存在数据库中,或者统一的缓存模块中,比如redis中。对于单服务器环境,我们大可以直接将其保存在内存中。

定时任务我们经常会用到quartz框架。不过spring也提供有任务调度的模块,我习惯用@Scheduled注解。至于它的使用,大家可自行百度。

以下代码中形如@Value("#{weixinProperties['AppId']}")

是通过spring读取配置文件,如果没见过这样做的朋友也可以自行去查找相关资料。

相关的配置放在一个名为weixin.properties的配置文件中:

#weixin properties
# 你自己的appid和appsecret
AppId=XXXXXXXXX
AppSecret=XXXXXXXXXXXXXXXXXXX
 
#get access_token urlget
get_access_token_url=https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
 
#batchget_material urlpost
batchget_material_url=https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN

 

Spring配置文件中:

<!-- weixin.properties 配置文件 -->
<bean id="weixinProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath*:weixin.properties</value>
</list>
</property>
</bean>
<bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="properties" ref="weixinProperties" />
</bean>

 

AccessTokenTaker 代码如下:

package com.dongliushui.quartz;

importjava.io.UnsupportedEncodingException;

import org.apache.log4j.Logger;
importorg.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
importorg.springframework.stereotype.Component;

import com.dongliushui.util.HttpUtil;

/**
*@ClassName: AccessTokenTaker
*@Description: 获取access_token
*@author zhutulang
*@date 2016年1月10日
*@version V1.0
*/
@Component
public class AccessTokenTaker {

@Value("#{weixinProperties['AppId']}")
private String appId;

@Value("#{weixinProperties['AppSecret']}")
private String appSecret;

@Value("#{weixinProperties['get_access_token_url']}")
private String getAccessTokenUrl;

/**
* access_token
*/
privatestatic String ACCESS_TOKEN = null;
/**
* 上次更新access_token时间
*/
privatestatic LongLAST_ACCESS_TOKEN_UPDATE_TIME = null;

privatestatic Logger log = Logger.getLogger(AccessTokenTaker.class);

/**
* <p>Title: get</p>
* <p>Description: 每隔一个小时去获取一次access_token</p>
* @author zhutulang
* @version 1.0
*/
@Scheduled(fixedRate=3600000)
privatevoid getTask(){
get();
}

/**
* <p>Title: getFromCache</p>
* <p>Description: 从缓存中获取access_token</p>
* @return
* @author zhutulang
* @version 1.0
*/
public String getFromCache(){
returnACCESS_TOKEN;
}

/**
* <p>Title: getNew</p>
* <p>Description: 强制更新、获取access_token</p>
* <p>如果发现现在的时间戳和上次更新的时间戳间隔小于5分钟,那么不更新</p>
* @return
* @author zhutulang
* @version 1.0
*/
publicsynchronized String getNew(){
longtimeNow = System.currentTimeMillis();
if(LAST_ACCESS_TOKEN_UPDATE_TIME== null){
get();
}elseif(timeNow - LAST_ACCESS_TOKEN_UPDATE_TIME < 300000){
//如果是5分钟以内
returnACCESS_TOKEN;
}else{
get();
}
returnACCESS_TOKEN;
}

/**
* <p>Title: get</p>
* <p>Description: 调用获取access_token接口</p>
* @author zhutulang
* @version 1.0
*/
synchronized void get(){
Stringurl = getAccessTokenUrl.replace("APPID",appId).replace("APPSECRET", appSecret);
StringcontentType = "application/json";
byte[]bytes = HttpUtil.doHttpsGet(url, contentType);
try{
StringaccessToken = new String(bytes, "UTF-8");
longtimeNow = System.currentTimeMillis();
ACCESS_TOKEN= accessToken;
LAST_ACCESS_TOKEN_UPDATE_TIME= timeNow;
log.info("执行获取access_token任务,access_token="+ACCESS_TOKEN);
log.info("时间戳="+LAST_ACCESS_TOKEN_UPDATE_TIME);
}catch (UnsupportedEncodingException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}

publicString getAppId() {
returnappId;
}

publicvoid setAppId(String appId) {
this.appId= appId;
}

publicString getAppSecret() {
returnappSecret;
}

publicvoid setAppSecret(String appSecret) {
this.appSecret= appSecret;
}

publicString getGetAccessTokenUrl() {
returngetAccessTokenUrl;
}

publicvoid setGetAccessTokenUrl(String getAccessTokenUrl) {
this.getAccessTokenUrl= getAccessTokenUrl;
}
}

 其它相关代码可查看:

http://download.csdn.net/detail/zhutulang/9423587

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: