转自:http://www.cuiyongzhi.com/post/44.html

(一)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

在微信公众平台【开发】——>【基本配置】中可以查看到我们需要的两个参数:

这里我们将他们定义到我们的配置文件【wechat.properties】中,大致代码为:

1
2
3
4
#获取到的appid
appid=wx7e32765bc24XXXX 
#获取到的AppSecret
AppSecret=d58051564fe9d86093f9XXXXX

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

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

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
package com.cuiyongzhi.wechat.util;
 
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
 
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
 
/**
 * ClassName: HttpUtils
 
 * @Description: http请求工具类
 * @author dapengniao
 * @date 2016年3月10日 下午3:57:14
 */
@SuppressWarnings("deprecation")
public class HttpUtils {
 
    /**
     * @Description: http get请求共用方法
     * @param @param reqUrl
     * @param @param params
     * @param @return
     * @param @throws Exception
     * @author dapengniao
     * @date 2016年3月10日 下午3:57:39
     */
    @SuppressWarnings("resource")
    public static String sendGet(String reqUrl, Map<String, String> params)
            throws Exception {
        InputStream inputStream = null;
        HttpGet request = new HttpGet();
        try {
            String url = buildUrl(reqUrl, params);
            HttpClient client = new DefaultHttpClient();
 
            request.setHeader("Accept-Encoding""gzip");
            request.setURI(new URI(url));
 
            HttpResponse response = client.execute(request);
 
            inputStream = response.getEntity().getContent();
            String result = getJsonStringFromGZIP(inputStream);
            return result;
        finally {
            if (inputStream != null) {
                inputStream.close();
            }
            request.releaseConnection();
        }
 
    }
 
    /**
     * @Description: http post请求共用方法
     * @param @param reqUrl
     * @param @param params
     * @param @return
     * @param @throws Exception
     * @author dapengniao
     * @date 2016年3月10日 下午3:57:53
     */
    @SuppressWarnings("resource")
    public static String sendPost(String reqUrl, Map<String, String> params)
            throws Exception {
        try {
            Set<String> set = params.keySet();
            List<NameValuePair> list = new ArrayList<NameValuePair>();
            for (String key : set) {
                list.add(new BasicNameValuePair(key, params.get(key)));
            }
            if (list.size() > 0) {
                try {
                    HttpClient client = new DefaultHttpClient();
                    HttpPost request = new HttpPost(reqUrl);
 
                    request.setHeader("Accept-Encoding""gzip");
                    request.setEntity(new UrlEncodedFormEntity(list, HTTP.UTF_8));
 
                    HttpResponse response = client.execute(request);
 
                    InputStream inputStream = response.getEntity().getContent();
                    try {
                        String result = getJsonStringFromGZIP(inputStream);
 
                        return result;
                    finally {
                        inputStream.close();
                    }
                catch (Exception ex) {
                    ex.printStackTrace();
                    throw new Exception("网络连接失败,请连接网络后再试");
                }
            else {
                throw new Exception("参数不全,请稍后重试");
            }
        catch (Exception ex) {
            ex.printStackTrace();
            throw new Exception("发送未知异常");
        }
    }
 
    /**
     * @Description: http post请求json数据
     * @param @param urls
     * @param @param params
     * @param @return
     * @param @throws ClientProtocolException
     * @param @throws IOException
     * @author dapengniao
     * @date 2016年3月10日 下午3:58:15
     */
    public static String sendPostBuffer(String urls, String params)
            throws ClientProtocolException, IOException {
        HttpPost request = new HttpPost(urls);
 
        StringEntity se = new StringEntity(params, HTTP.UTF_8);
        request.setEntity(se);
        // 发送请求
        @SuppressWarnings("resource")
        HttpResponse httpResponse = new DefaultHttpClient().execute(request);
        // 得到应答的字符串,这也是一个 JSON 格式保存的数据
        String retSrc = EntityUtils.toString(httpResponse.getEntity());
        request.releaseConnection();
        return retSrc;
 
    }
 
    /**
     * @Description: http请求发送xml内容
     * @param @param urlStr
     * @param @param xmlInfo
     * @param @return
     * @author dapengniao
     * @date 2016年3月10日 下午3:58:32
     */
    public static String sendXmlPost(String urlStr, String xmlInfo) {
        // xmlInfo xml具体字符串
 
        try {
            URL url = new URL(urlStr);
            URLConnection con = url.openConnection();
            con.setDoOutput(true);
            con.setRequestProperty("Pragma:""no-cache");
            con.setRequestProperty("Cache-Control""no-cache");
            con.setRequestProperty("Content-Type""text/xml");
            OutputStreamWriter out = new OutputStreamWriter(
                    con.getOutputStream());
            out.write(new String(xmlInfo.getBytes("utf-8")));
            out.flush();
            out.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    con.getInputStream()));
            String lines = "";
            for (String line = br.readLine(); line != null; line = br
                    .readLine()) {
                lines = lines + line;
            }
            return lines; // 返回请求结果
        catch (MalformedURLException e) {
            e.printStackTrace();
        catch (IOException e) {
            e.printStackTrace();
        }
        return "fail";
    }
 
    private static String getJsonStringFromGZIP(InputStream is) {
        String jsonString = null;
        try {
            BufferedInputStream bis = new BufferedInputStream(is);
            bis.mark(2);
            // 取前两个字节
            byte[] header = new byte[2];
            int result = bis.read(header);
            // reset输入流到开始位置
            bis.reset();
            // 判断是否是GZIP格式
            int headerData = getShort(header);
            // Gzip 流 的前两个字节是 0x1f8b
            if (result != -1 && headerData == 0x1f8b) {
                // LogUtil.i("HttpTask", " use GZIPInputStream  ");
                is = new GZIPInputStream(bis);
            else {
                // LogUtil.d("HttpTask", " not use GZIPInputStream");
                is = bis;
            }
            InputStreamReader reader = new InputStreamReader(is, "utf-8");
            char[] data = new char[100];
            int readSize;
            StringBuffer sb = new StringBuffer();
            while ((readSize = reader.read(data)) > 0) {
                sb.append(data, 0, readSize);
            }
            jsonString = sb.toString();
            bis.close();
            reader.close();
        catch (Exception e) {
            e.printStackTrace();
        }
 
        return jsonString;
    }
 
    private static int getShort(byte[] data) {
        return (data[0] << 8) | data[1] & 0xFF;
    }
 
    /**
     * 构建get方式的url
     
     * @param reqUrl
     *            基础的url地址
     * @param params
     *            查询参数
     * @return 构建好的url
     */
    public static String buildUrl(String reqUrl, Map<String, String> params) {
        StringBuilder query = new StringBuilder();
        Set<String> set = params.keySet();
        for (String key : set) {
            query.append(String.format("%s=%s&", key, params.get(key)));
        }
        return reqUrl + "?" + query.toString();
    }
 
}

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

1
2
#获取token的url

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.cuiyongzhi.web.start;
 
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
 
/**
 * ClassName: InterfaceUrlIntiServlet
 * @Description: 项目启动初始化servlet
 * @author dapengniao
 * @date 2016年3月10日 下午4:08:43
 */
public class InterfaceUrlIntiServlet extends HttpServlet {
 
    private static final long serialVersionUID = 1L;
 
    @Override
    public void init(ServletConfig config) throws ServletException {
        InterfaceUrlInti.init();
    }
 
}

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

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
package com.cuiyongzhi.web.start;
 
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
 
import com.cuiyongzhi.web.util.GlobalConstants;
 
/**
 * ClassName: InterfaceUrlInti
 * @Description: 项目启动初始化方法
 * @author dapengniao
 * @date 2016年3月10日 下午4:08:21
 */
public class InterfaceUrlInti {
 
    public synchronized static void init(){
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        Properties props = new Properties();
        if(GlobalConstants.interfaceUrlProperties==null){
            GlobalConstants.interfaceUrlProperties = new Properties();
        }
        InputStream in = null;
        try {
            in = cl.getResourceAsStream("interface_url.properties");
            props.load(in);
            for(Object key : props.keySet()){
                GlobalConstants.interfaceUrlProperties.put(key, props.get(key));
            }
             
            props = new Properties();
            in = cl.getResourceAsStream("wechat.properties");
            props.load(in);
            for(Object key : props.keySet()){
                GlobalConstants.interfaceUrlProperties.put(key, props.get(key));
            }
             
        catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(in!=null){
                try {
                    in.close();
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return;
    }
 
}

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

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
package com.cuiyongzhi.wechat.common;
 
import java.util.HashMap;
import java.util.Map;
 
import net.sf.json.JSONObject;
 
import com.cuiyongzhi.web.util.GlobalConstants;
import com.cuiyongzhi.wechat.util.HttpUtils;
 
/**
 * ClassName: WeChatTask
 * @Description: 微信两小时定时任务体
 * @author dapengniao
 * @date 2016年3月10日 下午1:42:29
 */
public class WeChatTask {
    /**
     * @Description: 任务执行体
     * @param @throws Exception
     * @author dapengniao
     * @date 2016年3月10日 下午2:04:37
     */
    public void getToken_getTicket() throws Exception {
        Map<String, String> params = new HashMap<String, String>();
        params.put("grant_type""client_credential");
        params.put("appid", GlobalConstants.getInterfaceUrl("appid"));
        params.put("secret", GlobalConstants.getInterfaceUrl("AppSecret"));
        String jstoken = HttpUtils.sendGet(
                GlobalConstants.getInterfaceUrl("tokenUrl"), params);
        String access_token = JSONObject.fromObject(jstoken).getString(
                "access_token"); // 获取到token并赋值保存
        GlobalConstants.interfaceUrlProperties.put("access_token", access_token);
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"token为=============================="+access_token);
    }
 
}

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

我们阅读过微信的文档会发现我们的token获取的接口每天是有调用次数限制的,为了防止我们业务量比较大的情况下token的直接调用的接口次数不够用,所以我们需要根据token的时效性(7200s)在自己的业务服务器上做到token的缓存并定时获取,我这里用到的任务调度的方式是采用quartz,有关quartz的使用可以参考文章 http://cuiyongzhi.com/?tags=%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1 ,下面具体代码的实现:

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
package com.cuiyongzhi.wechat.quartz;
 
import org.apache.log4j.Logger;
 
import com.cuiyongzhi.wechat.common.WeChatTask;
 
public class QuartzJob{
    private static Logger logger = Logger.getLogger(QuartzJob.class);
    /**
     * @Description: 任务执行获取token
     * @param    
     * @author dapengniao
     * @date 2016年3月10日 下午4:34:26
     */
    public void workForToken() {
        try {
            WeChatTask timer = new WeChatTask();
            timer.getToken_getTicket();
        catch (Exception e) {
            logger.error(e, e);
        }
    }
 
 
}

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

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
    <!-- 要调用的工作类 -->
    <bean id="quartzJob" class="com.cuiyongzhi.wechat.quartz.QuartzJob"></bean>
     
    <!-- 定义调用对象和调用对象的方法 -->
    <bean id="jobtaskForToken"
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!-- 调用的类 -->
        <property name="targetObject">
            <ref bean="quartzJob" />
        </property>
        <!-- 调用类中的方法 -->
        <property name="targetMethod">
            <value>workForToken</value>
        </property>
 
    </bean>
    <!-- 定义触发时间 -->
    <bean id="doTimeForToken" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail">
            <ref bean="jobtaskForToken" />
        </property>
        <!-- cron表达式 -->
        <property name="cronExpression">
            <value>0 0/1 * * * ?</value>
        </property>
    </bean>
 
 
    <!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序 -->
    <bean id="startQuertz" lazy-init="false" autowire="no"
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="doTimeForToken" />
            </list>
        </property>
    </bean>
 
</beans>

这里我为了测试将执行间隔时间设置成了1分钟一次,根据需要可以自行修改执行时间;最后我们需要在我们的web.xml启动项中开启quartz的使用:

1
2
3
4
5
<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring.xml,classpath:spring-mybatis.xml,classpath:spring-quartz.xml</param-value>
        <!-- ,classpath:spring-quartz.xml 用于做任务调度 任务定时都可以 -->
    </context-param>

当这一切都准备完毕之后我们启动项目,会发现每间隔一分钟就会有token获取到,这里我是将其存储在项目变量中,但是如果需要考虑到项目横向扩展这里建议将token存储到缓存中;运行结果如下:

那么到这里token的获取和保存就基本讲完了,下一篇将讲述【多媒体消息的回复】,感谢你的翻阅,如果有需要源码或有疑问可以留言!

Java微信公众平台开发(六)--微信开发中的token获取的更多相关文章

  1. 微信公众平台开放JS-SDK(微信内网页开发工具包)

    微信公众平台开放JS-SDK(微信内网页开发工具包),这次开放接口是质的飞跃,是对开发者和广大用户一个利好的消息.未来的公众号图文消息会更丰富多彩,准备脑洞大开吧!(第三方平台正式支持接入微信公众平台 ...

  2. 微信公众平台自定义菜单PHP开发

    微信公众平台自定义菜单PHP开发,微信公众平台自定义菜单是如何实现的呢?其实很简单,首先在微信公众平台升级为服务号,获取appid和appsecret,然后根据这2个参数获取access_token, ...

  3. 微信公众平台Php版php开发(转)

    http://www.1990c.com/?p=932 近在做微信公众平台开发,一口气写了二十几个功能,挺有意思的-  今天来分享一下开发经验~微信公众平台提供的接口很简单,先看看消息交互流程:  说 ...

  4. odoo发送信息到微信公众平台、企业微信

    目录 odoo发送信息到微信 @(odoo client.message.send_text) odoo发送信息到微信 在odoo平台中进行项目开发的时候有时会用到跟其他平台对接发送信息. 这里我写一 ...

  5. 运用Java对微信公众平台二次开发技术——开发者模式接入

    当初我在这碰到了很多问题,市面上以及网络上的资料特别少,所以当初碰了很多壁,所以现在跟大家分享一下,如何用Java,对微信公众平台进行二次开发. 一.开发预备知识: 最基本的JavaSE与JavaWe ...

  6. asp.net微信公众平台开发

    http://mp.weixin.qq.com/wiki/index.php?title=%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3%E6%8C%87%E5%8D%97 ...

  7. PHP语言开发微信公众平台(订阅号)之注册

    1.百度搜索"微信公众平台" 2.选择微信公众平台官网并单击打开 3.进入官网页面,单击 "立即注册" 进入注册页面 4.进入注册页面,单击订阅号 5.进入订阅 ...

  8. PHP语言开发微信公众平台(订阅号)之注册(1)

    1.百度搜索"微信公众平台" 2.选择微信公众平台官网并单击打开 3.进入官网页面,单击 "立即注册" 进入注册页面 4.进入注册页面,单击订阅号 5.进入订阅 ...

  9. 微信公众平台消息接口开发(12)消息接口Bug

    微信公众平台开发模式 微信公众平台消息接口 微信公众平台API 微信开发模式 Bug 方倍工作室 原文:http://www.cnblogs.com/txw1958/archive/2013/03/1 ...

  10. JAVA折腾微信公众平台(Token验证)[转]

    JAVA折腾微信公众平台(Token验证) BAE的JAVA还在内测的时候,抱着好奇的态度发邮件申请了内测权限,当时折腾了一天,然后就没折腾了.现在BAE的JAVA都已经正式开放使用了,我又蛋疼的想写 ...

随机推荐

  1. ndk+opencv安装+各种错误分析(新版安装,编译不需要Cygwin 和Sequoyah了)

    鼓捣了两三天,终于成功算跑通了一个简单的程序.下面说说具体的安装: 因为从同学那里拷过来的eclipse 就有adt cdt 的插件.所以这两个就不用再安装了.(需要的话自己安装) 具体说下安装过程: ...

  2. 【scala】应用程序和App特性

    一.应用程序 要运行一个Scala对象,必须提供一个独立对象的名称.这个独立对象需要包含一个main方法,该方法接受一个Array[String]作为参数,结果类型为Unit. import Chec ...

  3. ionic2常见问题——启动后白屏问题

    问题描述 app启动后大概有几秒白屏,才会显示首页. 解决方案 图 1-最初config.xml配置 图 2-更改后的splash配置 代码: <preference name="Sh ...

  4. python基础之模块一

    一 time模块 时间表示形式 在Python中,通常有这三种方式来表示时间:时间戳.元组(struct_time).格式化的时间字符串:(1)时间戳(timestamp) :通常来说,时间戳表示的是 ...

  5. LeetCode OJ:Recover Binary Search Tree(恢复二叉搜索树)

    Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing ...

  6. form表单的提交地址一定要是完整的绝对地址

    <form action="<%=path%>/servlet/DologinServlet" =<form action="<%=requ ...

  7. 用 WEKA 进行数据挖掘 ——第一章:简介

    1.简介数据挖掘.机器学习这些字眼,在一些人看来,是门槛很高的东西.诚然,如果做算法实现甚至算法优化,确实需要很多背景知识.但事实是,绝大多数数据挖掘工程师,不需要去做算法层面的东西.他们的精力,集中 ...

  8. 开源一款远程控制软件 —— pcshare

    这里开放一款远程控制软件的源码--pcshare,该软件分为被控制端和控制端.部分界面如下: 控制端通过寄生在被控制端的后台程序来实现控制,可以对被控制台进行文件管理.屏幕监控.键盘监控.监控管理.查 ...

  9. ng 指令的自定义、使用

    1.创建和使用var app = angular.module('myApp',['ng']);app.directive('指令名称',func); 自定义指令的命名:驼峰式,有两部分构成,前缀一般 ...

  10. POJ 1265 Area (pick定理)

    题目大意:已知机器人行走步数及每一步的坐标变化量,求机器人所走路径围成的多边形的面积.多边形边上和内部的点的数量. 思路:叉积求面积,pick定理求点. pick定理:面积=内部点数+边上点数/2-1 ...