专栏首页g歌德aJava微信公众平台开发(六)--微信开发中的token获取

Java微信公众平台开发(六)--微信开发中的token获取

(一)token的介绍

引用:access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效!

(二)token的获取参考文档

获取的流程我们完全可以参考微信官方文档:http://mp.weixin.qq.com/wiki/14/9f9c82c1af308e3b14ba9b973f99a8ba.html 如图:

(三)token获取流程分析

  • 从公众平台获取账号的AppID和AppSecret;
  • token获取并解析存储执行体;
  • 采用任务调度每隔两小时执行一次token获取执行体;

(四)token的获取流程的具体实现

①获取appid和appsecret

微信公众平台接口测试工具中可以查看到我们需要的两个参数:

这里我们将appid 和secret 定义到配置文件【wechat.properties】,在src目录下新建【wechat.properties】文件,大致代码为:

#开发者的appid
appid=wx7e32765bc24XXXX 
#开发者的AppSecret
AppSecret=d58051564fe9d86093f9XXXXX

②token获取并解析存储执行体的代码编写

由于在这里我们需要通过http的get请求向微信服务器获取时效性为7200秒的token,所以我在这里写了一个http请求的工具类HttpUtils,以方便我们的使用,如下:(这里需要导入文末的http协议包)

  1 package com.gede.wechat.util;
  2 import java.io.BufferedInputStream;
  3 import java.io.BufferedReader;
  4 import java.io.IOException;
  5 import java.io.InputStream;
  6 import java.io.InputStreamReader;
  7 import java.io.OutputStreamWriter;
  8 import java.net.MalformedURLException;
  9 import java.net.URI;
 10 import java.net.URL;
 11 import java.net.URLConnection;
 12 import java.util.ArrayList;
 13 import java.util.List;
 14 import java.util.Map;
 15 import java.util.Set;
 16 import java.util.zip.GZIPInputStream;
 17  
 18 import org.apache.http.HttpResponse;
 19 import org.apache.http.NameValuePair;
 20 import org.apache.http.client.ClientProtocolException;
 21 import org.apache.http.client.HttpClient;
 22 import org.apache.http.client.entity.UrlEncodedFormEntity;
 23 import org.apache.http.client.methods.HttpGet;
 24 import org.apache.http.client.methods.HttpPost;
 25 import org.apache.http.entity.StringEntity;
 26 import org.apache.http.impl.client.DefaultHttpClient;
 27 import org.apache.http.message.BasicNameValuePair;
 28 import org.apache.http.protocol.HTTP;
 29 import org.apache.http.util.EntityUtils;
 30 /**
 31 * @author gede
 32 * @version date:2019年5月26日 下午5:43:36
 33 * @description :
 34 */
 35 public class HttpUtils {
 36      
 37     /**
 38      * @Description: http get请求共用方法
 39      * @param @param reqUrl
 40      * @param @param params
 41      * @param @return
 42      * @param @throws Exception
 43      */
 44     @SuppressWarnings("resource")
 45     public static String sendGet(String reqUrl, Map<String, String> params)
 46             throws Exception {
 47         InputStream inputStream = null;
 48         HttpGet request = new HttpGet();
 49         try {
 50             String url = buildUrl(reqUrl, params);
 51             HttpClient client = new DefaultHttpClient();
 52  
 53             request.setHeader("Accept-Encoding", "gzip");
 54             request.setURI(new URI(url));
 55  
 56             HttpResponse response = client.execute(request);
 57  
 58             inputStream = response.getEntity().getContent();
 59             String result = getJsonStringFromGZIP(inputStream);
 60             return result;
 61         } finally {
 62             if (inputStream != null) {
 63                 inputStream.close();
 64             }
 65             request.releaseConnection();
 66         }
 67  
 68     }
 69  
 70     @SuppressWarnings("resource")
 71     public static String sendPost(String reqUrl, Map<String, String> params)
 72             throws Exception {
 73         try {
 74             Set<String> set = params.keySet();
 75             List<NameValuePair> list = new ArrayList<NameValuePair>();
 76             for (String key : set) {
 77                 list.add(new BasicNameValuePair(key, params.get(key)));
 78             }
 79             if (list.size() > 0) {
 80                 try {
 81                     HttpClient client = new DefaultHttpClient();
 82                     HttpPost request = new HttpPost(reqUrl);
 83  
 84                     request.setHeader("Accept-Encoding", "gzip");
 85                     request.setEntity(new UrlEncodedFormEntity(list, HTTP.UTF_8));
 86  
 87                     HttpResponse response = client.execute(request);
 88  
 89                     InputStream inputStream = response.getEntity().getContent();
 90                     try {
 91                         String result = getJsonStringFromGZIP(inputStream);
 92  
 93                         return result;
 94                     } finally {
 95                         inputStream.close();
 96                     }
 97                 } catch (Exception ex) {
 98                     ex.printStackTrace();
 99                     throw new Exception("网络连接失败,请连接网络后再试");
100                 }
101             } else {
102                 throw new Exception("参数不全,请稍后重试");
103             }
104         } catch (Exception ex) {
105             ex.printStackTrace();
106             throw new Exception("发送未知异常");
107         }
108     }
109  
110     public static String sendPostBuffer(String urls, String params)
111             throws ClientProtocolException, IOException {
112         HttpPost request = new HttpPost(urls);
113  
114         StringEntity se = new StringEntity(params, HTTP.UTF_8);
115         request.setEntity(se);
116         // 发送请求
117         @SuppressWarnings("resource")
118         HttpResponse httpResponse = new DefaultHttpClient().execute(request);
119         // 得到应答的字符串,这也是一个 JSON 格式保存的数据
120         String retSrc = EntityUtils.toString(httpResponse.getEntity());
121         request.releaseConnection();
122         return retSrc;
123  
124     }
125  
126     public static String sendXmlPost(String urlStr, String xmlInfo) {
127         // xmlInfo xml具体字符串
128  
129         try {
130             URL url = new URL(urlStr);
131             URLConnection con = url.openConnection();
132             con.setDoOutput(true);
133             con.setRequestProperty("Pragma:", "no-cache");
134             con.setRequestProperty("Cache-Control", "no-cache");
135             con.setRequestProperty("Content-Type", "text/xml");
136             OutputStreamWriter out = new OutputStreamWriter(
137                     con.getOutputStream());
138             out.write(new String(xmlInfo.getBytes("utf-8")));
139             out.flush();
140             out.close();
141             BufferedReader br = new BufferedReader(new InputStreamReader(
142                     con.getInputStream()));
143             String lines = "";
144             for (String line = br.readLine(); line != null; line = br
145                     .readLine()) {
146                 lines = lines + line;
147             }
148             return lines; // 返回请求结果
149         } catch (MalformedURLException e) {
150             e.printStackTrace();
151         } catch (IOException e) {
152             e.printStackTrace();
153         }
154         return "fail";
155     }
156  
157     private static String getJsonStringFromGZIP(InputStream is) {
158         String jsonString = null;
159         try {
160             BufferedInputStream bis = new BufferedInputStream(is);
161             bis.mark(2);
162             // 取前两个字节
163             byte[] header = new byte[2];
164             int result = bis.read(header);
165             // reset输入流到开始位置
166             bis.reset();
167             // 判断是否是GZIP格式
168             int headerData = getShort(header);
169             // Gzip 流 的前两个字节是 0x1f8b
170             if (result != -1 && headerData == 0x1f8b) {
171                 // LogUtil.i("HttpTask", " use GZIPInputStream  ");
172                 is = new GZIPInputStream(bis);
173             } else {
174                 // LogUtil.d("HttpTask", " not use GZIPInputStream");
175                 is = bis;
176             }
177             InputStreamReader reader = new InputStreamReader(is, "utf-8");
178             char[] data = new char[100];
179             int readSize;
180             StringBuffer sb = new StringBuffer();
181             while ((readSize = reader.read(data)) > 0) {
182                 sb.append(data, 0, readSize);
183             }
184             jsonString = sb.toString();
185             bis.close();
186             reader.close();
187         } catch (Exception e) {
188             e.printStackTrace();
189         }
190  
191         return jsonString;
192     }
193  
194     private static int getShort(byte[] data) {
195         return (data[0] << 8) | data[1] & 0xFF;
196     }
197  
198     /**
199      * 构建get方式的url
200      * 
201      * @param reqUrl
202      *            基础的url地址
203      * @param params
204      *            查询参数
205      * @return 构建好的url
206      */
207     public static String buildUrl(String reqUrl, Map<String, String> params) {
208         StringBuilder query = new StringBuilder();
209         Set<String> set = params.keySet();
210         for (String key : set) {
211             query.append(String.format("%s=%s&", key, params.get(key)));
212         }
213         return reqUrl + "?" + query.toString();
214     }
215  
216 }

我们在做http请求的时候需要目标服务器的url,这里在项目中为了方便对url的管理我们src目录下建立了interface_url.properties用于存放目标url,这里我们将请求token的url存入:

#获取token的url
tokenUrl=https://api.weixin.qq.com/cgi-bin/token

我们需要将我们配置的配置文件在项目初始化后能得到启动,所以我在这里加入一个项目初始化的代码InterfaceUrlIntiServlet来实现,用于项目启动初始化interface_url.properties和wechat.properties中的配置:

 1 package com.gede.web.start;
 2 import javax.servlet.ServletConfig;
 3 import javax.servlet.ServletException;
 4 import javax.servlet.http.HttpServlet;
 5 /**
 6 * @author gede
 7 * @version date:2019年5月26日 下午7:42:14
 8 * @description :
 9 */
10 public class InterfaceUrlIntiServlet extends HttpServlet {
11      
12     private static final long serialVersionUID = 1L;
13  
14     @Override
15     public void init(ServletConfig config) throws ServletException {
16         InterfaceUrlInti.init();
17     }
18 }

初始化的具体实现,将初始化过后的方法都存入到GlobalConstants中方便项目中随意调用,如下:

 1 package com.gede.web.start;
 2 import java.io.IOException;
 3 import java.io.InputStream;
 4 import java.util.Properties;
 5 import com.gede.web.util.GlobalConstants;
 6 /**
 7 * @author gede
 8 * @version date:2019年5月26日 下午7:42:37
 9 * @description :
10 */
11 public class InterfaceUrlInti {
12      
13     public synchronized static void init(){
14         ClassLoader cl = Thread.currentThread().getContextClassLoader();
15         Properties props = new Properties();
16         if(GlobalConstants.interfaceUrlProperties==null){
17             GlobalConstants.interfaceUrlProperties = new Properties();
18         }
19         InputStream in = null;
20         try {
21             in = cl.getResourceAsStream("interface_url.properties");
22             props.load(in);
23             for(Object key : props.keySet()){
24                 GlobalConstants.interfaceUrlProperties.put(key, props.get(key));
25             }
26              
27             props = new Properties();
28             in = cl.getResourceAsStream("wechat.properties");
29             props.load(in);
30             for(Object key : props.keySet()){
31                 GlobalConstants.interfaceUrlProperties.put(key, props.get(key));
32             }
33              
34         } catch (IOException e) {
35             e.printStackTrace();
36         }finally{
37             if(in!=null){
38                 try {
39                     in.close();
40                 } catch (IOException e) {
41                     e.printStackTrace();
42                 }
43             }
44         }
45         return;
46     }
47  
48 }

这里用到的GlobalConstants,我们新建在web.util包里面,代码如下:

package com.gede.web.util;
import java.util.Properties;
/**
* @author gede
* @version date:2019年5月26日 下午7:45:27
* @description :
*/
public class GlobalConstants {
    public static Properties interfaceUrlProperties;

/**
 * @Description: TODO
 * @param @param key
 * @param @return   
 */
    public static String getInterfaceUrl(String key) {
        return (String) interfaceUrlProperties.get(key);
    }
}

当我们把所有的准备工作都做好了之后我们可以开始真正的去获取token了,这里我们将获取到的token解析之后依然存储到GlobalConstants中方便使用,简单代码如下:(这里需要导入我们附件中的json包)

 1 package com.gede.wechat.common;
 2 import java.text.SimpleDateFormat;
 3 import java.util.Date;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 
 7 import com.gede.web.util.GlobalConstants;
 8 import com.gede.wechat.util.HttpUtils;
 9 
10 import net.sf.json.JSONObject;
11 /**
12 * @author gede
13 * @version date:2019年5月26日 下午7:50:38
14 * @description :
15 */
16 public class WeChatTask {
17     /**
18      * @Description: 任务执行体
19      * @param @throws Exception
20      */
21     public void getToken_getTicket() throws Exception {
22         Map<String, String> params = new HashMap<String, String>();
23         params.put("grant_type", "client_credential");
24         params.put("appid", GlobalConstants.getInterfaceUrl("appid"));
25         params.put("secret", GlobalConstants.getInterfaceUrl("AppSecret"));
26         String jstoken = HttpUtils.sendGet(
27                 GlobalConstants.getInterfaceUrl("tokenUrl"), params);
28         String access_token = JSONObject.fromObject(jstoken).getString(
29                 "access_token"); // 获取到token并赋值保存
30         GlobalConstants.interfaceUrlProperties.put("access_token", access_token);
31                 System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"token为=============================="+access_token);
32     }
33  
34 }

(三)采用任务调度每隔两小时执行一次token获取执行体

我们阅读过微信的文档会发现我们的token获取的接口每天是有调用次数限制的,为了防止我们业务量比较大的情况下token的直接调用的接口次数不够用,所以我们需要根据token的时效性(7200s)在自己的业务服务器上做到token的缓存并定时获取,我这里用到的任务调度的方式是采用quartz,下面具体代码的实现:

 1 package com.gede.wechat.quartz;
 2 import org.apache.log4j.Logger;
 3 import com.gede.wechat.common.WeChatTask;
 4 
 5 /**
 6 * @author gede
 7 * @version date:2019年5月26日 下午8:00:43
 8 * @description :
 9 */
10 public class QuartzJob{
11     private static Logger logger = Logger.getLogger(QuartzJob.class);
12     /**
13      * @Description: 任务执行获取token
14      * @param    
15      */
16     public void workForToken() {
17         try {
18             WeChatTask timer = new WeChatTask();
19             timer.getToken_getTicket();
20         } catch (Exception e) {
21             logger.error(e, e);
22         }
23     }
24 }

这里新建配置文件spring-quartz.xml以方便quartz任务的管理和启用,这里将我们需要用到的workForToken()加入到执行任务中:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 3 
 4 <beans>
 5     <!-- 要调用的工作类 -->
 6     <bean id="quartzJob" class="com.gede.wechat.quartz.QuartzJob"></bean>
 7     <!-- 定义调用对象和调用对象的方法 -->
 8     <bean id="jobtaskForToken"
 9         class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
10         <!-- 调用的类 -->
11         <property name="targetObject">
12             <ref bean="quartzJob" />
13         </property>
14         <!-- 调用类中的方法 -->
15         <property name="targetMethod">
16             <value>workForToken</value>
17         </property>
18     </bean>
19     <!-- 定义触发时间 -->
20     <bean id="doTimeForToken" class="org.springframework.scheduling.quartz.CronTriggerBean">
21         <property name="jobDetail">
22             <ref bean="jobtaskForToken" />
23         </property>
24         <!-- cron表达式 -->
25         <property name="cronExpression">
26             <value>0 0/1 * * * ?</value>
27         </property>
28     </bean>
29     <!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序 -->
30     <bean id="startQuertz" lazy-init="false" autowire="no"
31         class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
32         <property name="triggers">
33             <list>
34                 <ref bean="doTimeForToken" />
35             </list>
36         </property>
37     </bean>
38 </beans>

这里我为了测试将执行间隔时间设置成了1分钟一次,根据需要可以自行修改执行时间。

好了到这里我们就已经大功告成,就差初始化加载InterfaceUrlIntiServlet和开启quartz的使用:修改web.xml ,加入相关语句,代码如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
 3   <display-name>mychat</display-name>
 4   <listener>
 5     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 6   </listener>
 7  <context-param>
 8     <param-name>contextConfigLocation</param-name>
 9     <param-value>classpath:applicationContext.xml,classpath:spring-quartz.xml</param-value>
10   </context-param>
11   
12   <servlet>
13       <servlet-name>appServlet</servlet-name>
14         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
15         <init-param>
16             <param-name>contextConfigLocation</param-name>
17             <param-value>
18             classpath:appServlet.xml
19             </param-value>
20         </init-param>
21       <load-on-startup>1</load-on-startup>
22   </servlet>
23   
24   <context-param>
25         <param-name>log4jConfigLocation</param-name>
26         <param-value>classpath:log4j.properties</param-value>
27     </context-param>
28     <listener>
29         <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
30   </listener>
31   
32   <servlet>
33         <servlet-name>interface_url-init_servlet</servlet-name>
34         <servlet-class>com.gede.web.start.InterfaceUrlIntiServlet</servlet-class>
35         <load-on-startup>1</load-on-startup>
36   </servlet>
37   
38   <servlet-mapping>
39       <servlet-name>appServlet</servlet-name>
40       <url-pattern>/</url-pattern>
41   </servlet-mapping>
42 </web-app>

当这一切都准备完毕之后我们启动项目,会发现每间隔一分钟就会有token获取到,这里我是将其存储在项目变量中,这里看一下我们的效果图和项目总的目录结构:

附件:今天需要导入的包有很多,最后我就给大家打一个压缩包,大家在运行之前将包全部导入即可。点击下载

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring------自动化装配Bean(二) 一、在soundsystem 中新建JavaConfig2

    上一篇是基于 @ComponentScan自动装配Bean的实现,这一篇将通过java手动装配bean来实现。

    用户2417870
  • Java微信公众平台开发(七)--多媒体消息回复之图片回复

    之前我们在做消息回复的时候我们对回复的消息简单做了分类,前面也有讲述如何回复【普通消息类型消息】,这里将讲述多媒体消息的回复方法,【多媒体消息】包含回复图片消息...

    用户2417870
  • Java微信公众平台开发(十二)--微信JSSDK的使用 (一)修改我们的menue。(二)测试

    在前面的文章中有介绍到我们在微信web开发过程中常常用到的 【微信JSSDK中Config配置】 ,但是我们在真正的使用中我们不仅仅只是为了配置Config而已...

    用户2417870
  • koa框架生成微信公众号二维码

    demo的github地址:https://github.com/xuedingmiaojun/koa-demo.git

    薛定喵君
  • 哭晕!不懂搜索盲目造轮子:Golang打印请求体,大神2行搞定!

    在Golang与其他web服务(包括发送和接收)的接口调试,一直是一个痛点。将所有的值都放入fmt也挺麻烦的。

    程序员小助手
  • 广告小程序后端开发(14.个人中心:获取我的消息,将我的消息标记为已读,删除我的消息)

    玩蛇的胖纸
  • 微信小程序模板消息详解

    先放代码 wxml: <form name='pushMsgFm' report-submit bindsubmit='orderSign'> <vi...

    李文杨
  • 微信小程序云存储秘籍

    很长时间没写过文章了,前段时间参加了腾讯云物联网的一个应用创新比赛获得了个二等奖,真感谢腾讯云同学和其他大牛的支持及帮助。经过这次比赛发现物联网控制跟微信小程序...

    谭广健
  • python抓取数据构建词云

    词云图,也叫文字云,是对文本中出现频率较高的“关键词”予以视觉化的展现,词云图过滤掉大量的低频低质的文本信息,使得浏览者只要一眼扫过文本就可领略文本的主旨。

    周小董
  • 微信小程序发送模版消息(事例)

    honey缘木鱼

扫码关注云+社区

领取腾讯云代金券