Java開發微信公眾號(五)---微信開發中如何獲取access_token以及緩存access_token


獲取access_token是微信api最重要的一個部分,因為調用其他api很多都需要用到access_token。比如自定義菜單接口、客服接口、獲取用戶信息接口、用戶分組接口、群發接口等在請求的時候都需要用到access_token。

(一)access_token的介紹

       access_token是公眾號的全局唯一接口調用憑據,公眾號調用各接口時都需使用access_token。開發者需要進行妥善保存。access_token的存儲至少要保留512個字符空間。access_token的有效期目前為2個小時,需時刷新,重復獲取將導致上次獲取的access_token失效。

      公眾號可以使用AppID和AppSecret調用本接口來獲取access_token。AppID和AppSecret可在微信公眾平台官網-開發者中心頁中獲得。且一個公眾號每天獲取access_token的次數上限為2000次。詳情請查看微信開發文檔“獲取access_token”

      通過開發者文檔我們可以發現access_token的有效期限是2個小時,刷新的時候會導致上次獲取的access_token失效,而且一個公眾號每天獲取access_token的次數上限為2000次。如果我們不做控制,而是選擇各個業務邏輯點各自去刷新access_token,那么就可能會產生沖突,導致服務不穩定。所以我們需要有一個地方來保存我們獲取到的access_token 和獲取時間,每次有請求的時候先到這個地方查看是否已有 access_token,並判斷這個access_token是否在有效期內,在的話直接返回,反之則重新調用接口獲取access_token,同時在我們保存access_token的地方更新token和時間。

先和大家說一下我保存access_token的思路(目前先實現token的獲取,access_token的緩存和更新后期會加上):

1.首先定義一個存放token的數據庫表

2.首先,用戶在調用需要access_token接口的時候,先查詢數據庫里保存access_token的值是否存在。

3.如果access_token存在的話,判斷此access_token是否有效。如果有效的話,直接返回此值。

4.如果沒有效,則調用獲取access_token的接口,再次獲取,並且更改數據庫表中已經存在的access_token值 和 時間。

5.接第一步驟,如果access_token不存在,則調用獲取access_token的接口,將獲取到的數據保存在數據庫表里。

 正常情況下,微信會返回下述JSON數據包給公眾號:

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

錯誤時微信會返回錯誤碼等信息,JSON數據包示例如下(該示例為AppID無效錯誤):

{"errcode":40013,"errmsg":"invalid appid"}

封裝access_token類  Token

 1 package com.webchat.util.weixin.model;
 2 
 3 /**
 4  * token憑證 簽名
 5  * 
 6  * @author Administrator
 7  *
 8  */
 9 public class Token {
10     //接口訪問憑證
11     private String accessToken;
12     //有效期限
13     private int expiresIn;
14     //獲取token的最新時間
15     private long addTime;
16     //簽名
17     private String ticket;
18     public String getAccessToken() {
19         return accessToken;
20     }
21     public void setAccessToken(String accessToken) {
22         this.accessToken = accessToken;
23     }
24     public int getExpiresIn() {
25         return expiresIn;
26     }
27     public void setExpiresIn(int expiresIn) {
28         this.expiresIn = expiresIn;
29     }
30     public long getAddTime() {
31         return addTime;
32     }
33     public void setAddTime(long addTime) {
34         this.addTime = addTime;
35     }
36     public String getTicket() {
37         return ticket;
38     }
39     public void setTicket(String ticket) {
40         this.ticket = ticket;
41     }
42 }
View Code

 接口調用請求地址

https請求方式: 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

 

 

    

 對於https請求,我們需要一個證書信任管理器,這個管理器類需要自己定義,但需要實現X509TrustManager接口,首先定義一個MyX509TrustManager 類。

 1 package com.webchat.util.weixin.utils;
 2 
 3 import java.security.cert.CertificateException;
 4 import java.security.cert.X509Certificate;
 5 
 6 import javax.net.ssl.X509TrustManager;
 7 
 8 public class MyX509TrustManager implements X509TrustManager{
 9 
10     public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
11         // TODO Auto-generated method stub
12 
13     }
14 
15     public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
16         // TODO Auto-generated method stub
17 
18     }
19 
20     public X509Certificate[] getAcceptedIssuers() {
21         // TODO Auto-generated method stub
22         return null;
23     }
24 
25 }
View Code

定義一個weixin.properties 文件

#wei xin pei zhi
wx_token=mywebchat

wx_appid=wx6138e8XXXXXXX
wx_secret=4364283f8XXXXXXXXXXXX

讀取配置文件的工具類

 1 package com.webchat.util.weixin;
 2 
 3 import java.io.IOException;
 4 import java.util.Properties;
 5 
 6 import org.apache.log4j.Logger;
 7 import org.springframework.core.io.ClassPathResource;
 8 import org.springframework.core.io.Resource;
 9 import org.springframework.core.io.support.PropertiesLoaderUtils;
10 
11 /**
12  * 讀取配置文件工具類
13  * @author Administrator
14  *
15  */
16 public class ConfigUtil {
17 
18     private static final Logger LOG = Logger.getLogger(ConfigUtil.class);
19 
20     private static Properties config = null;
21 
22     /**
23      * 返回weixin.properties配置信息
24      * @param key key值
25      * @return value值
26      */
27     public static String getProperty(String key) {
28         if (config == null) {
29             synchronized (ConfigUtil.class) {
30                 if (null == config) {
31                     try {
32                         Resource resource = new ClassPathResource("static/weixin/weixin.properties");
33                         config = PropertiesLoaderUtils.loadProperties(resource);
34                     } catch (IOException e) {
35                         LOG.error(e.getMessage(), e);
36                     }
37                 }
38             }
39         }
40 
41         return config.getProperty(key);
42     }
43 }
View Code

獲取access_token的工具類:WechatConfig

  1 package com.webchat.util.weixin;
  2 
  3 import java.io.BufferedReader;
  4 import java.io.InputStream;
  5 import java.io.InputStreamReader;
  6 import java.io.OutputStream;
  7 import java.net.ConnectException;
  8 import java.net.URL;
  9 import java.util.HashMap;
 10 import java.util.Map;
 11 
 12 import javax.net.ssl.HttpsURLConnection;
 13 import javax.net.ssl.SSLContext;
 14 import javax.net.ssl.SSLSocketFactory;
 15 import javax.net.ssl.TrustManager;
 16 
 17 import com.alibaba.fastjson.JSONObject;
 18 import com.webchat.util.weixin.model.Token;
 19 import com.webchat.util.weixin.utils.MyX509TrustManager;
 20 
 21 public class WebChatConfig {
 22     // 獲取access_token的接口地址(GET) 限2000(次/天)
 23     public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
 24     // 創建菜單
 25     public static final String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
 26     // 查詢自定義菜單
 27     public static final String MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";
 28     // 刪除自定義菜單
 29     public static final String MENU_DELTE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
 30     // 獲取jsapi_ticket的接口地址(GET) 限2000(次/天)
 31     public static final String JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
 32     // 發送模板消息
 33     public static final String SEND_MESSAGE = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
 34 
 35     // 微信appid
 36     public final static String APPID = ConfigUtil.getProperty("wx_appid");
 37     // 微信wx_secret
 38     public final static String SECERT = ConfigUtil.getProperty("wx_secret");
 39     
 40     
 41     
 42     public static void main(String[] args) {
 43         System.out.println(getToken(APPID, SECERT));
 44     }
 45 
 46     /**
 47      * 獲得Token
 48      * 
 49      * @param appId
 50      * @param secret
 51      * @return
 52      */
 53     public static String getToken(String appId, String secret) {
 54         Token accessTocken = getToken(appId, secret, System.currentTimeMillis() / 1000);
 55         return accessTocken.getAccessToken();
 56     }
 57 
 58     /**
 59      * 獲取access_token
 60      *
 61      * @param appid
 62      *            憑證
 63      * @param appsecret
 64      *            密鑰
 65      * @return
 66      */
 67     public static Token getToken(String appid, String appsecret, long currentTime) {
 68         Token Token = null;
 69         // 調用接口獲取token
 70         String requestUrl = ACCESS_TOKEN_URL.replace("APPID", appid).replace("APPSECRET", appsecret);
 71         JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
 72         // 如果請求成功
 73         if (null != jsonObject) {
 74             Token = new Token();
 75             Token.setAccessToken(jsonObject.getString("access_token"));
 76             // 正常過期時間是7200秒,此處設置3600秒讀取一次
 77             // 一天有獲取2000次的限制 ,設置1小時獲取一次AccessToken防止超出請求限制
 78             Token.setExpiresIn(jsonObject.getIntValue("expires_in") / 2);
 79             Token.setAddTime(currentTime);
 80         }
 81         return Token;
 82     }
 83 
 84     /**
 85      * 發起https請求並獲取結果
 86      *
 87      * @param requestUrl
 88      *            請求地址
 89      * @param requestMethod
 90      *            請求方式(GET、POST)
 91      * @param outputStr
 92      *            提交的數據
 93      * @return JSONObject(通過JSONObject.get(key)的方式獲取json對象的屬性值)
 94      */
 95     private static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
 96         JSONObject jsonObject = null;
 97         StringBuffer buffer = new StringBuffer();
 98         try {
 99             // 創建SSLContext對象,並使用我們指定的信任管理器初始化
100             TrustManager[] tm = { new MyX509TrustManager() };
101             SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
102             sslContext.init(null, tm, new java.security.SecureRandom());
103             // 從上述SSLContext對象中得到SSLSocketFactory對象
104             SSLSocketFactory ssf = sslContext.getSocketFactory();
105 
106             URL url = new URL(requestUrl);
107             HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
108             httpUrlConn.setSSLSocketFactory(ssf);
109 
110             httpUrlConn.setDoOutput(true);
111             httpUrlConn.setDoInput(true);
112             httpUrlConn.setUseCaches(false);
113             // 設置請求方式(GET/POST)
114             httpUrlConn.setRequestMethod(requestMethod);
115 
116             if ("GET".equalsIgnoreCase(requestMethod))
117                 httpUrlConn.connect();
118 
119             // 當有數據需要提交時
120             if (null != outputStr) {
121                 OutputStream outputStream = httpUrlConn.getOutputStream();
122                 // 注意編碼格式,防止中文亂碼
123                 outputStream.write(outputStr.getBytes("UTF-8"));
124                 outputStream.close();
125             }
126             // 將返回的輸入流轉換成字符串
127             InputStream inputStream = httpUrlConn.getInputStream();
128             InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
129             BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
130 
131             String str = null;
132             while ((str = bufferedReader.readLine()) != null) {
133                 buffer.append(str);
134             }
135             bufferedReader.close();
136             inputStreamReader.close();
137             // 釋放資源
138             inputStream.close();
139             inputStream = null;
140             httpUrlConn.disconnect();
141             jsonObject = JSONObject.parseObject(buffer.toString());
142             // jsonObject = JSONObject.fromObject(buffer.toString());
143         } catch (ConnectException ce) {
144             System.out.println("Weixin server connection timed out.");
145         } catch (Exception e) {
146             System.out.println("https request error:{}" + e.getMessage());
147         }
148         return jsonObject;
149     }
150 }
View Code

運行里面的main方法查看獲取的值即可

好了,到此獲取access_token的方法基本結束了

有什么問題請指正^.^

如果在操作過程中有問題,歡迎隨時討論^.^

 

 

 

 

 

 

其他文章關聯

(一)Java開發微信公眾號(一)---初識微信公眾號以及環境搭建

(二)Java開發微信公眾號(二)---開啟開發者模式,接入微信公眾平台開發

(三)Java開發微信公眾號(三)---微信服務器請求消息,響應消息,事件消息以及工具處理類的封裝

(四)Java開發微信公眾號(四)---微信服務器post消息體的接收及消息的處理

(五)Java開發微信公眾號(五)---微信開發中如何獲取access_token以及緩存access_token

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM