微信官方参考文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183
基本说明:
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
调用方式:
公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。
特别说明:建议公众号开发者使用中控服务器统一获取和刷新Access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务;
了解这些信息后,我们需要理解确定如下几点:
1、统一token调用方法,其他地方需用到token均采用本方法获取;
2、请求获取token信息接口的实现;
3、token数据存储至本地数据库;
4、判断是否需要重新获取token还是直接从本地数据库中查询;
下面来进行具体的实现:
首先看一下整体的类图:
那么在获取token时,可以根据appid和appsecret来获取,其中判断是否需要更新的方法为:
能否获取到当前仍有效的token:查询SQL如下:
对应表结构参考如下:
对应的java代码如下: 如果能获取到,那么直接返回:
/**
* 通过参数获取Token信息
* @param appID
* @param appSceret
* @return
*/
public Token getToken(String appID, String appSceret)
{
mAppID = appID;
mAppSceret = appSceret; // 1.确定是否要更新token,无需更新则直接直接返回获取的token
if (updateToken())
{
return mToken;
} // 2. 如需更新
if (!getTokenbyhttps(mAppID, mAppSceret))
{
System.out.println("获取失败!");
return null;
} return mToken;
}
其中明细方法实现为:
/**
* 获取Token信息
* @return
*/
private boolean updateToken()
{
// 查询数据库数据,如果有则不用更新,无则需要更新
Connection con = null;
PreparedStatement stmt = null;
ResultSet rs = null;
// 判断当前token是否在有效时间内
String sql = " select * from token where appid ='" + mAppID + "' and appsecret ='" + mAppSceret
+ "' and ( current_timestamp -createtime) <expires_in order by createTime desc limit 0,1";
try
{
// 创建数据库链接
con = DBConnPool.getConnection();
// 创建处理器
stmt = con.prepareStatement(sql);
// 查询Token,读取1条记录
rs = stmt.executeQuery();
if (rs.next())
{
mToken.setTokenid(rs.getString("tokenid"));
mToken.setToken(rs.getString("token"));
mToken.setExpires_in(rs.getInt("expires_in"));
mToken.setAppid(rs.getString("appid"));
mToken.setAppsecret(rs.getString("appsecret"));
}
else
{
System.out.println("未查询到对应token");
return false;
}
}
catch (Exception e)
{
// TODO: handle exception
return false;
} System.out.println(mToken.getToken()); return true;
}
如果需要获取新的token,则:
/**
* 通过https请求获取token
* @param appID
* @param appSceret
* @return
*/
private boolean getTokenbyhttps(String appID, String appSceret)
{
String current_time = new Date().getTime() + ""; try
{
// 请求地址
String path = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
+ appID + "&secret=" + appSceret; String strResp = WeChatUtil.doHttpsGet(path, "");
System.out.println(strResp); // 解析获取的token信息
Map<String, Object> tMap = WeChatUtil.jsonToMap(strResp); System.out.println(tMap.toString()); mToken.setTokenid(WeChatUtil.getMaxTokenID());
mToken.setToken((String) tMap.get("access_token"));
mToken.setExpires_in(Integer.parseInt((String) tMap.get("expires_in")));
mToken.setAppid(appID);
mToken.setAppsecret(appSceret);
mToken.setCreatetime(current_time); System.out.println(mToken.getToken()); }
catch (HttpException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} // 存储token至数据库
saveToken(mToken); return true;
} /**
* 保存Token信息
* @return
*/
private boolean saveToken(Token token)
{
PreparedStatement pst = null;
Connection conn = null;
try
{
Token tToken = token.clone(); System.out.println(tToken.getTokenid() + tToken.getToken()); conn = DBConnPool.getConnection();
// 创建预处理器
pst = conn.prepareStatement("insert into token(tokenid, token, expires_in,appid, appsecret,createtime) values (?,?,?,?,?,?)"); pst.setString(1, tToken.getTokenid());
pst.setString(2, tToken.getToken());
pst.setInt(3, tToken.getExpires_in());
pst.setString(4, tToken.getAppid());
pst.setString(5, tToken.getAppsecret());
long now = new Date().getTime();
pst.setTimestamp(6, new java.sql.Timestamp(now));
pst.execute(); }
catch (CloneNotSupportedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
catch (Exception e)
{
// TODO: handle exception
System.out.println("出现额外异常");
}
return true;
}
对于https的GET和POST调用,可以写2个公共方法,具体实现可参考:
/**
* HTTPS请求Get方法调用
* @param path
* @param requestData
* @return
* @throws HttpException
* @throws IOException
*/
public static String doHttpsGet(String path, String requestData) throws HttpException, IOException
{
// 创建https请求,未默认证书,可自行添加
// 设置编码
HttpClient httpClient = new HttpClient();
GetMethod getMethod = new GetMethod(path);
httpClient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8"); httpClient.executeMethod(getMethod); // 读取内容
byte[] responseBody = getMethod.getResponseBody();
String strResp = new String(responseBody, "UTF-8"); System.out.println(strResp); getMethod.releaseConnection(); return strResp;
} /**
* HTTPS请求Post方法调用
* @param path
* @param requestData
* @return
* @throws HttpException
* @throws IOException
*/
public static String doHttpsPost(String path, String requestData) throws HttpException, IOException
{
// 创建https请求,未默认证书,可自行添加
String strResp ="";
HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod(path);
// 设置编码
httpClient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8"); System.out.println("path:" + path);
System.out.println("requestData:" + requestData); postMethod.setRequestBody(requestData); long start = System.currentTimeMillis();
// 执行getMethod
int statusCode = httpClient.executeMethod(postMethod);
System.out.println("cost:" + (System.currentTimeMillis() - start));
// 失败
if (statusCode != HttpStatus.SC_OK)
{
System.out.println("Method failed: " + postMethod.getStatusLine());
// 读取内容
byte[] responseBody = postMethod.getResponseBody();
// 处理内容
strResp = new String(responseBody, "UTF-8");
System.out.println(strResp);
}
else
{
// 读取内容
byte[] responseBody = postMethod.getResponseBody();
strResp = new String(responseBody, "UTF-8");
System.out.println("服务器返回:" + strResp);
} postMethod.releaseConnection(); return strResp;
}
需要加入返回是json,处理json 需要json对应的jar,另外需要用到httpclient 的jar包。
获取token后,要进行数据存储,再返回即可。
获取access_token 这里就结束了,后面的功能接口均需要用到 access_token,这里写的获取方法后面可以直接调用,很方便了哟~