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

作者: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

 

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值