• 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

  • 相关阅读:
    第一部分 Linux的规划与安装
    第二部分 Linux 文件、目录与磁盘格式
    for in 遍历对象
    时间
    javaScript模块化
    Hbuilder将移动app或者web项目打包
    echarts的通用属性的介绍
    echart的x轴或y轴区间标签如何从大到小排列
    数组的sort()排序
    解决vscode下载很慢的问题
  • 原文地址:https://www.cnblogs.com/han108/p/9614898.html
Copyright © 2020-2023  润新知