微信官方參考文檔:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183
基本說明:
access_token是公眾號的全局唯一接口調用憑據,公眾號調用各接口時都需使用access_token。開發者需要進行妥善保存。access_token的存儲至少要保留512個字符空間。access_token的有效期目前為2個小時,需定時刷新,重復獲取將導致上次獲取的access_token失效。
調用方式:
公眾號可以使用AppID和AppSecret調用本接口來獲取access_token。AppID和AppSecret可在“微信公眾平台-開發-基本配置”頁中獲得(需要已經成為開發者,且帳號沒有異常狀態)。調用接口時,請登錄“微信公眾平台-開發-基本配置”提前將服務器IP地址添加到IP白名單中,點擊查看設置方法,否則將無法調用成功。
特別說明:建議公眾號開發者使用中控服務器統一獲取和刷新Access_token,其他業務邏輯服務器所使用的access_token均來自於該中控服務器,不應該各自去刷新,否則容易造成沖突,導致access_token覆蓋而影響業務;
了解這些信息后,我們需要理解確定如下幾點:
1、統一token調用方法,其他地方需用到token均采用本方法獲取;
2、請求獲取token信息接口的實現;
3、token數據存儲至本地數據庫;
4、判斷是否需要重新獲取token還是直接從本地數據庫中查詢;
下面來進行具體的實現:
首先看一下整體的類圖:


那么在獲取token時,可以根據appid和appsecret來獲取,其中判斷是否需要更新的方法為:
能否獲取到當前仍有效的token:查詢SQL如下:


對應表結構參考如下:
對應的java代碼如下: 如果能獲取到,那么直接返回:

1 /** 2 * 通過參數獲取Token信息 3 * @param appID 4 * @param appSceret 5 * @return 6 */ 7 public Token getToken(String appID, String appSceret) 8 { 9 mAppID = appID; 10 mAppSceret = appSceret; 11 12 // 1.確定是否要更新token,無需更新則直接直接返回獲取的token 13 if (updateToken()) 14 { 15 return mToken; 16 } 17 18 // 2. 如需更新 19 if (!getTokenbyhttps(mAppID, mAppSceret)) 20 { 21 System.out.println("獲取失敗!"); 22 return null; 23 } 24 25 return mToken; 26 }
其中明細方法實現為:

1 /** 2 * 獲取Token信息 3 * @return 4 */ 5 private boolean updateToken() 6 { 7 // 查詢數據庫數據,如果有則不用更新,無則需要更新 8 Connection con = null; 9 PreparedStatement stmt = null; 10 ResultSet rs = null; 11 // 判斷當前token是否在有效時間內 12 String sql = " select * from token where appid ='" + mAppID + "' and appsecret ='" + mAppSceret 13 + "' and ( current_timestamp -createtime) <expires_in order by createTime desc limit 0,1"; 14 try 15 { 16 // 創建數據庫鏈接 17 con = DBConnPool.getConnection(); 18 // 創建處理器 19 stmt = con.prepareStatement(sql); 20 // 查詢Token,讀取1條記錄 21 rs = stmt.executeQuery(); 22 if (rs.next()) 23 { 24 mToken.setTokenid(rs.getString("tokenid")); 25 mToken.setToken(rs.getString("token")); 26 mToken.setExpires_in(rs.getInt("expires_in")); 27 mToken.setAppid(rs.getString("appid")); 28 mToken.setAppsecret(rs.getString("appsecret")); 29 } 30 else 31 { 32 System.out.println("未查詢到對應token"); 33 return false; 34 } 35 } 36 catch (Exception e) 37 { 38 // TODO: handle exception 39 return false; 40 } 41 42 System.out.println(mToken.getToken()); 43 44 return true; 45 }
如果需要獲取新的token,則:

1 /** 2 * 通過https請求獲取token 3 * @param appID 4 * @param appSceret 5 * @return 6 */ 7 private boolean getTokenbyhttps(String appID, String appSceret) 8 { 9 String current_time = new Date().getTime() + ""; 10 11 try 12 { 13 // 請求地址 14 String path = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" 15 + appID + "&secret=" + appSceret; 16 17 String strResp = WeChatUtil.doHttpsGet(path, ""); 18 System.out.println(strResp); 19 20 // 解析獲取的token信息 21 Map<String, Object> tMap = WeChatUtil.jsonToMap(strResp); 22 23 System.out.println(tMap.toString()); 24 25 mToken.setTokenid(WeChatUtil.getMaxTokenID()); 26 mToken.setToken((String) tMap.get("access_token")); 27 mToken.setExpires_in(Integer.parseInt((String) tMap.get("expires_in"))); 28 mToken.setAppid(appID); 29 mToken.setAppsecret(appSceret); 30 mToken.setCreatetime(current_time); 31 32 System.out.println(mToken.getToken()); 33 34 } 35 catch (HttpException e) 36 { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } 40 catch (IOException e) 41 { 42 // TODO Auto-generated catch block 43 e.printStackTrace(); 44 } 45 46 // 存儲token至數據庫 47 saveToken(mToken); 48 49 return true; 50 } 51 52 /** 53 * 保存Token信息 54 * @return 55 */ 56 private boolean saveToken(Token token) 57 { 58 PreparedStatement pst = null; 59 Connection conn = null; 60 try 61 { 62 Token tToken = token.clone(); 63 64 System.out.println(tToken.getTokenid() + tToken.getToken()); 65 66 conn = DBConnPool.getConnection(); 67 // 創建預處理器 68 pst = conn.prepareStatement("insert into token(tokenid, token, expires_in,appid, appsecret,createtime) values (?,?,?,?,?,?)"); 69 70 pst.setString(1, tToken.getTokenid()); 71 pst.setString(2, tToken.getToken()); 72 pst.setInt(3, tToken.getExpires_in()); 73 pst.setString(4, tToken.getAppid()); 74 pst.setString(5, tToken.getAppsecret()); 75 long now = new Date().getTime(); 76 pst.setTimestamp(6, new java.sql.Timestamp(now)); 77 pst.execute(); 78 79 } 80 catch (CloneNotSupportedException e) 81 { 82 // TODO Auto-generated catch block 83 e.printStackTrace(); 84 return false; 85 } 86 catch (SQLException e) 87 { 88 // TODO Auto-generated catch block 89 e.printStackTrace(); 90 return false; 91 } 92 catch (Exception e) 93 { 94 // TODO: handle exception 95 System.out.println("出現額外異常"); 96 } 97 return true; 98 }
對於https的GET和POST調用,可以寫2個公共方法,具體實現可參考:

1 /** 2 * HTTPS請求Get方法調用 3 * @param path 4 * @param requestData 5 * @return 6 * @throws HttpException 7 * @throws IOException 8 */ 9 public static String doHttpsGet(String path, String requestData) throws HttpException, IOException 10 { 11 // 創建https請求,未默認證書,可自行添加 12 // 設置編碼 13 HttpClient httpClient = new HttpClient(); 14 GetMethod getMethod = new GetMethod(path); 15 httpClient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8"); 16 17 httpClient.executeMethod(getMethod); 18 19 // 讀取內容 20 byte[] responseBody = getMethod.getResponseBody(); 21 String strResp = new String(responseBody, "UTF-8"); 22 23 System.out.println(strResp); 24 25 getMethod.releaseConnection(); 26 27 return strResp; 28 } 29 30 /** 31 * HTTPS請求Post方法調用 32 * @param path 33 * @param requestData 34 * @return 35 * @throws HttpException 36 * @throws IOException 37 */ 38 public static String doHttpsPost(String path, String requestData) throws HttpException, IOException 39 { 40 // 創建https請求,未默認證書,可自行添加 41 String strResp =""; 42 HttpClient httpClient = new HttpClient(); 43 PostMethod postMethod = new PostMethod(path); 44 // 設置編碼 45 httpClient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8"); 46 47 System.out.println("path:" + path); 48 System.out.println("requestData:" + requestData); 49 50 postMethod.setRequestBody(requestData); 51 52 long start = System.currentTimeMillis(); 53 // 執行getMethod 54 int statusCode = httpClient.executeMethod(postMethod); 55 System.out.println("cost:" + (System.currentTimeMillis() - start)); 56 // 失敗 57 if (statusCode != HttpStatus.SC_OK) 58 { 59 System.out.println("Method failed: " + postMethod.getStatusLine()); 60 // 讀取內容 61 byte[] responseBody = postMethod.getResponseBody(); 62 // 處理內容 63 strResp = new String(responseBody, "UTF-8"); 64 System.out.println(strResp); 65 } 66 else 67 { 68 // 讀取內容 69 byte[] responseBody = postMethod.getResponseBody(); 70 strResp = new String(responseBody, "UTF-8"); 71 System.out.println("服務器返回:" + strResp); 72 } 73 74 postMethod.releaseConnection(); 75 76 return strResp; 77 }

需要加入返回是json,處理json 需要json對應的jar,另外需要用到httpclient 的jar包。
獲取token后,要進行數據存儲,再返回即可。
獲取access_token 這里就結束了,后面的功能接口均需要用到 access_token,這里寫的獲取方法后面可以直接調用,很方便了喲~