在做微信公众号开发的时候,避免不了要获取accesstoken。
accesstoken有一些限制:
1、accesstoken得到后有一个有效时间限制。
2、accesstoken请求接口有访问次数限制。
为此我们要在accesstoken即将过期的时候去请求新的accesstoken,并将accesstoken保存起来,方便直接使用,而不是每次都要去获取:
Token实体类——保存accessToken跟有限期:
/**
* Token——微信
* @author 胡汉三
*
* 2017年3月31日 下午3:37:18
*/
public class Token {
// 接口访问凭证
private String accessToken;
// 凭证有效期,单位:秒
private int expiresIn;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
}
CommonUtil请求接口的工具类——向微信发送http请求:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yfkj.xfcamp.wechat.pojo.Token;
/**
* http请求工具类
* @author 胡汉三
*
* 2017年3月31日 下午3:46:05
*/
public class CommonUtil {
private static Logger log = LoggerFactory.getLogger(CommonUtil.class);
// 凭证获取(GET)——access_token
public final static String token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
// 微信JSSDK的ticket请求URL地址——jsapi_ticket
public final static String weixin_jssdk_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
/**
* 发送https请求
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return rootNode(通过rootNode.get(key)的方式获取json对象的属性值)
*/
public static JsonNode httpsRequest(String requestUrl, String requestMethod, String outputStr) {
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = null;
StringBuffer buffer = new StringBuffer();
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
if("GET".equalsIgnoreCase(requestMethod)) conn.connect();
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
rootNode = mapper.readTree(buffer.toString());
} catch (ConnectException ce) {
log.error("连接超时:{}", ce);
} catch (Exception e) {
log.error("https请求异常:{}", e);
}
return rootNode;
}
/**
* 获取接口访问凭证
*
* @param appid 凭证
* @param appsecret 密钥
* @return
*/
public static Token getToken(String appid, String appsecret) {
Token token = null;
String requestUrl = token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
// 发起GET请求获取凭证
JsonNode rootNode = httpsRequest(requestUrl, "GET", null);
if (null != rootNode) {
token = new Token();
token.setAccessToken(rootNode.get("access_token").textValue());
token.setExpiresIn(toInt(rootNode.get("expires_in").toString()));
}
return token;
}
/**
* 获取接口访问凭证高级
*
* @param appid 凭证
* @param appsecret 密钥
* @return
*/
public static Token getTokenByOauth(String appid, String appsecret) {
Token token = null;
String requestUrl = token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
// 发起GET请求获取凭证
JsonNode rootNode = httpsRequest(requestUrl, "GET", null);
if (null != rootNode) {
token = new Token();
token.setAccessToken(rootNode.get("access_token").textValue());
token.setExpiresIn(toInt(rootNode.get("expires_in").toString()));
}
return token;
}
/**
* URL编码(utf-8)
*
* @param source
* @return
*/
public static String urlEncodeUTF8(String source) {
String result = source;
try {
result = java.net.URLEncoder.encode(source, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
/**
* 调用微信JS接口的临时票据
*
* @param access_token 接口访问凭证
* @return
*/
public static String getJsApiTicket(String access_token) {
String requestUrl = weixin_jssdk_ticket_url.replace("ACCESS_TOKEN", access_token);
// 发起GET请求获取凭证
JsonNode rootNode = httpsRequest(requestUrl, "GET", null);
String ticket = null;
if (null != rootNode) {
ticket = rootNode.get("ticket").textValue();
}
return ticket;
}
public static Integer toInt(String str){
if(str == null || str.equals("")){
return null;
}
return Integer.valueOf(str);
}
}
MyX509TrustManager——信任管理器:
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
* 信任管理器
* @author 胡汉三
*
* 2017年3月31日 下午3:47:14
*/
public class MyX509TrustManager implements X509TrustManager {
// 检查客户端证书
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 检查服务器端证书
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 返回受信任的X509证书数组
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
TokenThread线程——获取并保存accessToken:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.yfkj.xfcamp.wechat.pojo.Token;
import com.yfkj.xfcamp.wechat.util.CommonUtil;
/**
* 微信Token线程
* @author 胡汉三
*
* 2017年3月31日 下午4:59:53
*/
public class TokenThread implements Runnable{
private static final Log log = LogFactory.getLog(TokenThread.class);
public static String appid= "";
public static String appsecret = "";
public static Token token = null;
public static String jsapi_ticket ="";
@Override
public void run() {
while(true){
try{
token = CommonUtil.getToken(appid, appsecret);
jsapi_ticket = CommonUtil.getJsApiTicket(token.getAccessToken());
if(null!=token){
log.info("获取access_token成功");
log.info("accesstoken初始化成功:"+token.getAccessToken());
System.out.println("accesstoken初始化成功:"+token.getAccessToken());
//有效期(秒)减去200秒,乘以1000(毫秒)——也就是在有效期的200秒前去请求新的token
Thread.sleep((token.getExpiresIn() - 200) * 1000);
}else{
//等待一分钟,在次请求
Thread.sleep(60*1000);
}
}catch(Exception e){
try{
//等待一分钟,在次请求
Thread.sleep(60*1000);
}catch(Exception e1){
log.error(e1);
}
log.error(e);
}
}
}
}
因为是javaWeb项目,需要配置一个Servlet来启动TokenThread
web.xml
<!-- 微信Token -->
<servlet>
<servlet-name>initServlet</servlet-name>
<servlet-class>com.yfkj.xfcamp.wechat.InitAccessTokenServlet</servlet-class>
<init-param>
<param-name>appid</param-name>
<param-value>wx79d605bf256d71ee</param-value>
</init-param>
<init-param>
<param-name>appsecret</param-name>
<param-value>daaf3c82d2b53eb83a82e36f0a76d6f7</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
InitAccessTokenServlet:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 启动定时获取Token线程——Servlet
* @author 胡汉三
*
*/
public class InitAccessTokenServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(InitAccessTokenServlet.class);
public void init() throws ServletException {
//获取web.xml中配置的参数
TokenThread.appid = getInitParameter("appid");
TokenThread.appsecret = getInitParameter("appsecret");
log.info("weixin api appid :"+TokenThread.appid);
log.info("weixin api appsecret:"+ TokenThread.appsecret);
if("".equals(TokenThread.appid) || "".equals(TokenThread.appsecret)){
log.error("appid和appsecret未给出");
}else {
new Thread(new TokenThread()).start();
//System.out.println("accesstoken初始化成功");
}
}
}
在其它地方要用accessToken的时候,直接使用TokenThread.token就OK啦!