zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    我爱Java系列之---【SpringBoot打成war包部署】
    279. Perfect Squares
    矩阵dfs--走回路
    112. Path Sum
    542. 01 Matrix
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    Invert Binary Tree
    563 Binary Tree Tilt
    145 Binary Tree Postorder Traversal
  • 原文地址:https://www.cnblogs.com/han108/p/9614898.html
Copyright © 2011-2022 走看看