獲取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 }
接口調用請求地址
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 }
定義一個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 }
獲取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 }
運行里面的main方法查看獲取的值即可
好了,到此獲取access_token的方法基本結束了
有什么問題請指正^.^
如果在操作過程中有問題,歡迎隨時討論^.^
其他文章關聯
(一)Java開發微信公眾號(一)---初識微信公眾號以及環境搭建
(二)Java開發微信公眾號(二)---開啟開發者模式,接入微信公眾平台開發
(三)Java開發微信公眾號(三)---微信服務器請求消息,響應消息,事件消息以及工具處理類的封裝
(四)Java開發微信公眾號(四)---微信服務器post消息體的接收及消息的處理
(五)Java開發微信公眾號(五)---微信開發中如何獲取access_token以及緩存access_token