微信公衆號開發(二、access_token管理)轉

access_token管理

在將access_token之前,還有兩個重要參數需要知曉,這兩個參數分別是appID和appsecret,這是在申請公衆號的時候自動分配給公衆號的,相當於公衆號的身份標示,在很多接口中需要這兩個參數,接下來在請求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次,所以不能調用太頻繁;

就此,這裏採用的方案是這樣的,定義一個默認啓動的servlet,在init方法中啓動一個Thread,這個進程中定義一個無限循環的方法,用來獲取access_token,當獲取成功後,此進程休眠7000秒,否則休眠3秒鐘繼續獲取。流程圖如下:

下面正式開始在工程中實現以上思路,因爲返回的數據都是json格式,這裏會用到阿里的fastjson庫,爲構造請求和處理請求後的數據序列化和反序列化提供支持。後續的其它接口也會用到。

1.定義一個AccessToken實體

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public class AccessToken {

    public String getAccessToken() {

        return accessToken;

    }

 

    public void setAccessToken(String accessToken) {

        this.accessToken = accessToken;

    }

 

    public int getExpiresin() {

        return expiresin;

    }

 

    public void setExpiresin(int expiresin) {

        this.expiresin = expiresin;

    }

 

    private String accessToken;

 

    private int expiresin;

}

2.定義一個默認啓動的servlet,在init方法中啓動一個Thread,並在web.xml中將這個servlet設置爲默認自啓動的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

 

/**

 * Created by huzhicheng on 2015/12/8.

 */

@WebServlet(name = "AccessTokenServlet")

public class AccessTokenServlet extends HttpServlet {

 

    public void init() throws ServletException {

        TokenThread.appId = getInitParameter("appid");  //獲取servlet初始參數appid和appsecret

        TokenThread.appSecret = getInitParameter("appsecret");

        System.out.println("appid:"+TokenThread.appId);

        System.out.println("appSecret:"+TokenThread.appSecret);

        new Thread(new TokenThread()).start(); //啓動進程

    }

 

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

 

    }

 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

 

    }

}

在web.xml中設置servlet自啓動,並設置初始化參數appid和appsecret

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<servlet>

        <servlet-name>initAccessTokenServlet</servlet-name>

        <servlet-class>

            org.fengzheng.wechat.accesstoken.AccessTokenServlet

        </servlet-class>

        <init-param>

            <param-name>appid</param-name>

            <param-value>your appid</param-value>

        </init-param>

        <init-param>

            <param-name>appsecret</param-name>

            <param-value>your appsecret</param-value>

        </init-param>

        <load-on-startup>0</load-on-startup>

 </servlet>

3.定義Thread類,在此類中調用access_token獲取接口,並將得到的數據抽象到靜態實體,以便在其它地方使用。接口地址爲https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET,其中grant_type固定寫爲client_credential即可。此請求爲https的get請求,返回的數據格式爲{"access_token":"ACCESS_TOKEN","expires_in":7200}。

進程類實現如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.JSONObject;

import org.fengzheng.wechat.common.NetWorkHelper;

 

/**

 * Created by huzhicheng on 2015/11/5.

 */

public class TokenThread implements Runnable {

    public static String appId = "";

 

    public static String appSecret= "";

<br>  //注意是靜態的

    public static AccessToken accessToken = null;

 

    public void run(){

        while (true){

            try{

                accessToken = this.getAccessToken();

                if(null!=accessToken){

                    System.out.println(accessToken.getAccessToken());

                    Thread.sleep(7000 1000); //獲取到access_token 休眠7000秒

 

                }else{

                    Thread.sleep(1000*3); //獲取的access_token爲空 休眠3秒

                }

            }catch(Exception e){

                System.out.println("發生異常:"+e.getMessage());

                e.printStackTrace();

                try{

                    Thread.sleep(1000*10); //發生異常休眠1秒

                }catch (Exception e1){

 

                }

            }

        }

    }

 

 

    /**

     * 獲取access_token

     * @return

     */

    private AccessToken getAccessToken(){

        NetWorkHelper netHelper = new NetWorkHelper();

        String Url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",this.appId,this.appSecret);

        String result = netHelper.getHttpsResponse(Url,"");

        System.out.println(result);

        //response.getWriter().println(result);

        JSONObject json = JSON.parseObject(result);

        AccessToken token = new AccessToken();

        token.setAccessToken(json.getString("access_token"));

        token.setExpiresin(json.getInteger("expires_in"));

        return token;

    }

}

其中NetWorkHelper中getHttpsResponse方法是請求一個https地址,參數requestMethod爲字符串“GET”或者“POST”,傳null或者“”默認爲get方式。

實現如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

public String getHttpsResponse(String hsUrl,String requestMethod) {

        URL url;

        InputStream is = null;

        String resultData = "";

        try {

            url = new URL(hsUrl);

            HttpsURLConnection con = (HttpsURLConnection) url.openConnection();

            TrustManager[] tm = {xtm};

 

            SSLContext ctx = SSLContext.getInstance("TLS");

            ctx.init(null, tm, null);

 

            con.setSSLSocketFactory(ctx.getSocketFactory());

            con.setHostnameVerifier(new HostnameVerifier() {

                @Override

                public boolean verify(String arg0, SSLSession arg1) {

                    return true;

                }

            });

 

 

            con.setDoInput(true); //允許輸入流,即允許下載

 

            //在android中必須將此項設置爲false

            con.setDoOutput(false); //允許輸出流,即允許上傳

            con.setUseCaches(false); //不使用緩衝

            if(null!=requestMethod && !requestMethod.equals("")) {

                con.setRequestMethod(requestMethod); //使用指定的方式

            }

            else{

                con.setRequestMethod("GET"); //使用get請求

            }

            is = con.getInputStream();   //獲取輸入流,此時才真正建立鏈接

            InputStreamReader isr = new InputStreamReader(is);

            BufferedReader bufferReader = new BufferedReader(isr);

            String inputLine = "";

            while ((inputLine = bufferReader.readLine()) != null) {

                resultData += inputLine + "\n";

            }

            System.out.println(resultData);

 

            

            Certificate[] certs = con.getServerCertificates();

 

            int certNum = 1;

 

            for (Certificate cert : certs) {

                X509Certificate xcert = (X509Certificate) cert;

            }

 

        catch (Exception e) {

            e.printStackTrace();

        }

        return resultData;

    }

 

X509TrustManager xtm = new X509TrustManager() {

        @Override

        public X509Certificate[] getAcceptedIssuers() {

            // TODO Auto-generated method stub

            return null;

        }

 

        @Override

        public void checkServerTrusted(X509Certificate[] arg0, String arg1)

                throws CertificateException {

            // TODO Auto-generated method stub

 

        }

 

        @Override

        public void checkClientTrusted(X509Certificate[] arg0, String arg1)

                throws CertificateException {

            // TODO Auto-generated method stub

 

        }

    };

至此代碼實現完畢,將項目部署,看到控制檯輸出如下:

  

爲方面看效果,可以把休眠時間設置短一點,比如30秒獲取一次,然後將access_token輸出。下面做一個測試jsp頁面,並把休眠時間設置爲30秒,這樣過30秒刷新頁面,就可以看到變化,順便演示一下在其它地方如何拿到access_token

1

2

3

4

5

6

7

8

9

10

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@ page import="org.fengzheng.wechat.accesstoken.TokenThread" %>

<html>

  <head>

    <title></title>

  </head>

  <body>

  access_token爲:<%=TokenThread.accessToken.getAccessToken()%>

  </body>

</html>

這樣在瀏覽器上瀏覽這個頁面,顯示效果如下:

30秒後刷新,這個值發生了變化:

  

代碼已上傳至github,倉庫會隨時更新,目前只有本篇所講的代碼。

歡迎關注公衆號「gushidefengzheng」古時的風箏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章