一、access_token管理
1.1、access_token介绍
通过前面两个的学习微信开发学习总结(一)——微信开发环境搭建,
微信开发学习总结(二)——微信开发入门
我们已经将微信的开发环境搭建好,也将测试微信公众号进行了接入。接下来就是获取全局唯一接口调用凭据。
关于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次,所以不能调用太频繁。
1.2、获取access token接口调用请求说明
https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
我们可以看到,调用过程中需要传递appID和AppSecret,appID和AppSecret是在申请公众号的时候自动分配给公众号的,相当于公众号的身份标示,使用微信公众号的注册帐号登录到腾讯提供的微信公众号管理后台就可以看到自己申请的公众号的AppID和AppSecret
1.3、获取access_token方案以及具体实现
这里采用的方案是:在数据库中将数据保存起来,如下图所示:
使用定时任务定时执行获取accesstoken记录。
具体代码如下所示:
1、AccessToken类如下所示:
package com.onion.po;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
@Table(name = "wx_accesstoken")
public class AccessToken implements Serializable {
@Id
private String accesstoken;
private Date expirestime;
private Date savetime;
private static final long serialVersionUID = 1L;
/** * @return accesstoken */
public String getAccesstoken() {
return accesstoken;
}
/** * @param accesstoken */
public void setAccesstoken(String accesstoken) {
this.accesstoken = accesstoken;
}
/** * @return expirestime */
public Date getExpirestime() {
return expirestime;
}
/** * @param expirestime */
public void setExpirestime(Date expirestime) {
this.expirestime = expirestime;
}
/** * @return savetime */
public Date getSavetime() {
return savetime;
}
/** * @param savetime */
public void setSavetime(Date savetime) {
this.savetime = savetime;
}
}
2、主要逻辑代码如下所示:
public AccessToken getAccessToken(){
//1、获取数据库记录
List<AccessToken> list = selectAll(new AccessToken());
AccessToken accessToken = null;
if(list != null && list.size() > 0){
accessToken = list.get(0);
}
//如果数据库中不存在该值,或者有效时间小于当前时间
if(accessToken == null){
accessToken = getWxAccessToken(null);
insert(accessToken);
}else if(accessToken.getExpirestime().getTime() < (new Date().getTime()) ){
//如果token过期,则先将数据库中值删除,在重新获取
delete(accessToken.getAccesstoken());
accessToken = getWxAccessToken(accessToken.getExpirestime());
insert(accessToken);
}
return accessToken;
}
public AccessToken getWxAccessToken(Date expirestime){
AccessToken accessToken = null;
String url = String.format(WxCommonUrl.ACCESS_TOKEN_URL, appID,appsecret);
//获取地址
String resultdata = NetWorkUtil.getHttpResponse(WxCommonUrl.GET_METHOD,url );
logger.debug(resultdata);
//解析结果
JSONObject jsonObject = JSONTool.toJSONObject(resultdata);
logger.debug("errorcode ====="+jsonObject.get("errcode"));
Object errcode = jsonObject.get("errcode");
//如果不存在错误码,则代表此次交易正常
if(errcode == null || "0".equals(errcode)){
logger.debug("正常获取到accessToken");
accessToken = new AccessToken();
//获取accesstoken
accessToken.setAccesstoken(jsonObject.getString("access_token"));
int expires_in = jsonObject.getInt("expires_in");
//如果有效时间为空,则当前时间+7200,否则是有效时间+7200
Date exptime = null;
if(expirestime == null){
exptime = new Date(new Date().getTime() + expires_in*1000);
}else{
exptime = new Date(new Date().getTime() + expires_in*1000);
}
accessToken.setExpirestime(exptime);
accessToken.setSavetime(new Date());
}else{
logger.error("当前获取accesstoken失败,错误码为:"+errcode + "错误原因为:"+jsonObject.getString("errmsg"));
}
return accessToken;
}
3、使用的访问网络工具类:
package com.onion.network;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import com.onion.utils.JSONTool;
public class NetWorkUtil {
/** * 调用https方法, * 1、获取url连接对象 * 2.获取https连接对象。3、实现自定义证书。 * 4、设置https相关参数 * @description : * @date 2017-10-16 * @author liucong * @param reqMethod * @param reqUrl * @return * * */
public static String getHttpsResponse(String reqMethod,String reqUrl){
URL url = null;
InputStream is = null;
String resultdata = "";
try {
//获取url链接
url = new URL(reqUrl);
//打开连接,获取https连接对象
HttpsURLConnection conn = (HttpsURLConnection ) url.openConnection();
/** * 实现https接口访问是所需的证书 */
TrustManager[] tm = {new MyX509TrustManager()};
SSLContext sslctx = SSLContext.getInstance("TLS");
sslctx.init(null, tm, null);
//设置证书
conn.setSSLSocketFactory(sslctx.getSocketFactory());
conn.setDoInput(true); //允许输入流,即允许下载
conn.setDoOutput(false);//允许输出流,即是否允许上传。Andriod中必须设置为false
conn.setUseCaches(false);
//如果请求方法为空,则默认调用get方法
if(StringUtils.isNotEmpty(reqMethod)){
conn.setRequestMethod(reqMethod);
}else{
conn.setRequestMethod("GET");
}
is = conn.getInputStream();//获取输入流,此时https连接真正建立
InputStreamReader isr = new InputStreamReader(is,"utf-8");
BufferedReader br = new BufferedReader(isr);
String inputline = "";
while((inputline = br.readLine()) != null){
resultdata += inputline +"\n";
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//关闭流
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return resultdata;
}
public static String getHttpResponse(String reqMethod,String reqUrl){
URL url = null;
InputStream is = null;
String resultData = "";
try {
url = new URL(reqUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
if(StringUtils.isNotEmpty(reqMethod)){
conn.setRequestMethod(reqMethod);
}else{
conn.setRequestMethod("GET");
}
is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is,"utf-8");
BufferedReader br = new BufferedReader(isr);
String readLine = null;
while((readLine = br.readLine()) != null){
resultData += readLine + "\n";
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return resultData;
}
public static String getJsonFromHttpMethod(String reqMethod,String reqUrl){
URL url = null;
InputStream is = null;
String resultData = new String();
try {
url = new URL(reqUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
if(StringUtils.isNotEmpty(reqMethod)){
conn.setRequestMethod(reqMethod);
}else{
conn.setRequestMethod("GET");
}
is = conn.getInputStream();
/*InputStreamReader isr = new InputStreamReader(is,"UTF-8"); BufferedReader br = new BufferedReader(isr); String readLine = null; while((readLine = br.readLine()) != null){ resultData.append(readLine+" "); }*/
resultData = new String(readStream(is),"UTF-8");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return resultData;
}
/** * 读取inputstream流,返回 * @description : * @date 2017-10-23 * @author liucong * @param is * @return * @throws IOException * * */
public static byte[] readStream(InputStream is) throws IOException{
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
int readLine = -1;
byte[] buffer = new byte[1024];
if((readLine = is.read(buffer)) != -1){
byteOutStream.write(buffer, 0, readLine);
}
byteOutStream.close();
is.close();
return byteOutStream.toByteArray();
}
/** * 调用http 接口获取输入流 * @description : * @date 2017-10-23 * @author liucong * @param reqMethod * @param reqUrl * @return * @throws Exception * * */
public static InputStream getHttpMethod(String reqMethod,String reqUrl) throws Exception{
URL url = null;
InputStream is = null;
url = new URL(reqUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
if(StringUtils.isNotEmpty(reqMethod)){
conn.setRequestMethod(reqMethod);
}else{
conn.setRequestMethod("GET");
}
is = conn.getInputStream();
return is;
}
}
4、自定义https证书信任,通过实现X509TrustManager信任管理器
package com.onion.network;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/** * 自定义https证书信任,通过实现X509TrustManager信任管理器 * @author liuc * */
public class MyX509TrustManager implements X509TrustManager{
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
执行代码:即可在数据库中看到Accesstoken数据
到这里,本次获取Accesstoken完成结束。在调用其他接口时,有可能遇到accesstoken过期,此时大家需要在代码中,重新获取accesstoken。