一、access_token管理
1.1、access_token介紹
通過前面兩個的學習微信開發學習總結(一)——微信開發環境搭建,
微信開發學習總結(二)——微信開發入門
我們已經將微信的開發環境搭建好,也將測試微信公衆號進行了接入。接下來就是獲取全局唯一接口調用憑據。
關於access_token,在微信公衆平臺開發者文檔上的獲取access_token有比較詳細的介紹:
access_token是公衆號的全局唯一票據,公衆號調用各接口時都需使用access_token,開發者需要妥善保存access_token的存儲至少要保留512個字符空間。access_token的有效期目前爲2個小時,需定時刷新,重複獲取將導致上次獲取的access_token失效。並且每天調用獲取access_token接口的上限是2000次。
總結以上說明,access_token需要做到以下兩點:
1.因爲access_token有2個小時的時效性,要有一個機制保證最長2個小時重新獲取一次。
2.因爲接口調用上限每天2000次,所以不能調用太頻繁。
1.2、獲取access token接口調用請求說明
https請求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
我們可以看到,調用過程中需要傳遞appID和AppSecret,appID和AppSecret是在申請公衆號的時候自動分配給公衆號的,相當於公衆號的身份標示,使用微信公衆號的註冊帳號登錄到騰訊提供的微信公衆號管理後臺就可以看到自己申請的公衆號的AppID和AppSecret
1.3、獲取access_token方案以及具體實現
這裏採用的方案是:在數據庫中將數據保存起來,如下圖所示:
使用定時任務定時執行獲取accesstoken記錄。
具體代碼如下所示:
1、AccessToken類如下所示:
package com.onion.po;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
@Table(name = "wx_accesstoken")
public class AccessToken implements Serializable {
@Id
private String accesstoken;
private Date expirestime;
private Date savetime;
private static final long serialVersionUID = 1L;
/**
* @return accesstoken
*/
public String getAccesstoken() {
return accesstoken;
}
/**
* @param accesstoken
*/
public void setAccesstoken(String accesstoken) {
this.accesstoken = accesstoken;
}
/**
* @return expirestime
*/
public Date getExpirestime() {
return expirestime;
}
/**
* @param expirestime
*/
public void setExpirestime(Date expirestime) {
this.expirestime = expirestime;
}
/**
* @return savetime
*/
public Date getSavetime() {
return savetime;
}
/**
* @param savetime
*/
public void setSavetime(Date savetime) {
this.savetime = savetime;
}
}
2、主要邏輯代碼如下所示:
public AccessToken getAccessToken(){
//1、獲取數據庫記錄
List<AccessToken> list = selectAll(new AccessToken());
AccessToken accessToken = null;
if(list != null && list.size() > 0){
accessToken = list.get(0);
}
//如果數據庫中不存在該值,或者有效時間小於當前時間
if(accessToken == null){
accessToken = getWxAccessToken(null);
insert(accessToken);
}else if(accessToken.getExpirestime().getTime() < (new Date().getTime()) ){
//如果token過期,則先將數據庫中值刪除,在重新獲取
delete(accessToken.getAccesstoken());
accessToken = getWxAccessToken(accessToken.getExpirestime());
insert(accessToken);
}
return accessToken;
}
public AccessToken getWxAccessToken(Date expirestime){
AccessToken accessToken = null;
String url = String.format(WxCommonUrl.ACCESS_TOKEN_URL, appID,appsecret);
//獲取地址
String resultdata = NetWorkUtil.getHttpResponse(WxCommonUrl.GET_METHOD,url );
logger.debug(resultdata);
//解析結果
JSONObject jsonObject = JSONTool.toJSONObject(resultdata);
logger.debug("errorcode ====="+jsonObject.get("errcode"));
Object errcode = jsonObject.get("errcode");
//如果不存在錯誤碼,則代表此次交易正常
if(errcode == null || "0".equals(errcode)){
logger.debug("正常獲取到accessToken");
accessToken = new AccessToken();
//獲取accesstoken
accessToken.setAccesstoken(jsonObject.getString("access_token"));
int expires_in = jsonObject.getInt("expires_in");
//如果有效時間爲空,則當前時間+7200,否則是有效時間+7200
Date exptime = null;
if(expirestime == null){
exptime = new Date(new Date().getTime() + expires_in*1000);
}else{
exptime = new Date(new Date().getTime() + expires_in*1000);
}
accessToken.setExpirestime(exptime);
accessToken.setSavetime(new Date());
}else{
logger.error("當前獲取accesstoken失敗,錯誤碼爲:"+errcode + "錯誤原因爲:"+jsonObject.getString("errmsg"));
}
return accessToken;
}
3、使用的訪問網絡工具類:
package com.onion.network;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import com.onion.utils.JSONTool;
public class NetWorkUtil {
/**
* 調用https方法,
* 1、獲取url連接對象
* 2.獲取https連接對象。3、實現自定義證書。
* 4、設置https相關參數
* @description :
* @date 2017-10-16
* @author liucong
* @param reqMethod
* @param reqUrl
* @return
*
*
*/
public static String getHttpsResponse(String reqMethod,String reqUrl){
URL url = null;
InputStream is = null;
String resultdata = "";
try {
//獲取url鏈接
url = new URL(reqUrl);
//打開連接,獲取https連接對象
HttpsURLConnection conn = (HttpsURLConnection ) url.openConnection();
/**
* 實現https接口訪問是所需的證書
*/
TrustManager[] tm = {new MyX509TrustManager()};
SSLContext sslctx = SSLContext.getInstance("TLS");
sslctx.init(null, tm, null);
//設置證書
conn.setSSLSocketFactory(sslctx.getSocketFactory());
conn.setDoInput(true); //允許輸入流,即允許下載
conn.setDoOutput(false);//允許輸出流,即是否允許上傳。Andriod中必須設置爲false
conn.setUseCaches(false);
//如果請求方法爲空,則默認調用get方法
if(StringUtils.isNotEmpty(reqMethod)){
conn.setRequestMethod(reqMethod);
}else{
conn.setRequestMethod("GET");
}
is = conn.getInputStream();//獲取輸入流,此時https連接真正建立
InputStreamReader isr = new InputStreamReader(is,"utf-8");
BufferedReader br = new BufferedReader(isr);
String inputline = "";
while((inputline = br.readLine()) != null){
resultdata += inputline +"\n";
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//關閉流
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return resultdata;
}
public static String getHttpResponse(String reqMethod,String reqUrl){
URL url = null;
InputStream is = null;
String resultData = "";
try {
url = new URL(reqUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
if(StringUtils.isNotEmpty(reqMethod)){
conn.setRequestMethod(reqMethod);
}else{
conn.setRequestMethod("GET");
}
is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is,"utf-8");
BufferedReader br = new BufferedReader(isr);
String readLine = null;
while((readLine = br.readLine()) != null){
resultData += readLine + "\n";
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return resultData;
}
public static String getJsonFromHttpMethod(String reqMethod,String reqUrl){
URL url = null;
InputStream is = null;
String resultData = new String();
try {
url = new URL(reqUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
if(StringUtils.isNotEmpty(reqMethod)){
conn.setRequestMethod(reqMethod);
}else{
conn.setRequestMethod("GET");
}
is = conn.getInputStream();
/*InputStreamReader isr = new InputStreamReader(is,"UTF-8");
BufferedReader br = new BufferedReader(isr);
String readLine = null;
while((readLine = br.readLine()) != null){
resultData.append(readLine+" ");
}*/
resultData = new String(readStream(is),"UTF-8");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return resultData;
}
/**
* 讀取inputstream流,返回
* @description :
* @date 2017-10-23
* @author liucong
* @param is
* @return
* @throws IOException
*
*
*/
public static byte[] readStream(InputStream is) throws IOException{
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
int readLine = -1;
byte[] buffer = new byte[1024];
if((readLine = is.read(buffer)) != -1){
byteOutStream.write(buffer, 0, readLine);
}
byteOutStream.close();
is.close();
return byteOutStream.toByteArray();
}
/**
* 調用http 接口獲取輸入流
* @description :
* @date 2017-10-23
* @author liucong
* @param reqMethod
* @param reqUrl
* @return
* @throws Exception
*
*
*/
public static InputStream getHttpMethod(String reqMethod,String reqUrl) throws Exception{
URL url = null;
InputStream is = null;
url = new URL(reqUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
if(StringUtils.isNotEmpty(reqMethod)){
conn.setRequestMethod(reqMethod);
}else{
conn.setRequestMethod("GET");
}
is = conn.getInputStream();
return is;
}
}
4、自定義https證書信任,通過實現X509TrustManager信任管理器
package com.onion.network;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
* 自定義https證書信任,通過實現X509TrustManager信任管理器
* @author liuc
*
*/
public class MyX509TrustManager implements X509TrustManager{
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
執行代碼:即可在數據庫中看到Accesstoken數據
到這裏,本次獲取Accesstoken完成結束。在調用其他接口時,有可能遇到accesstoken過期,此時大家需要在代碼中,重新獲取accesstoken。