package edu.fudan.weixin.utils; import java.net.URLEncoder; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.mongodb.DBObject; import com.mongodb.util.JSON; import edu.fudan.eservice.common.utils.CommonUtil; import edu.fudan.eservice.common.utils.Config; import edu.fudan.eservice.common.utils.ThreadPoolHelper; /** * Access Token工具类,过期时间前20s可自动重新获取。 * * @author wking * */ public class AccessTokenHelper { public static final int WEIXIN = 0; public static final int TAC = 1; private static AccessTokenHelper instance = null; private ScheduledFuture<?>[] schfuture; protected AccessTokenHelper() { Config conf = Config.getInstance(); this.schfuture = new ScheduledFuture[2]; long exp =0; try{ exp=Long.parseLong(conf.get("weixin.token_expires")); }catch(Exception e){} String tk= conf.get("weixin.access_token"); if (exp > (System.currentTimeMillis() + 20000)&&!CommonUtil.isEmpty(tk)) { schfuture[WEIXIN] = ThreadPoolHelper .getInstance() .getSchPool() .schedule(new TokenFetcher(WEIXIN), exp - 20000 - System.currentTimeMillis(), TimeUnit.MILLISECONDS); }else { refetch(WEIXIN); } exp=0; try{ exp = Long.parseLong(conf.get("tac.token_expires")); }catch(Exception e){} tk= conf.get("tac.access_token"); if (exp > (System.currentTimeMillis() + 20000)&&!CommonUtil.isEmpty(tk)) { schfuture[TAC] = ThreadPoolHelper .getInstance() .getSchPool() .schedule(new TokenFetcher(TAC), exp - 20000 - System.currentTimeMillis(), TimeUnit.MILLISECONDS); }else { refetch(TAC); } } /** * 获取单件实例 * * @return */ public synchronized static AccessTokenHelper getInstance() { if (instance == null) instance = new AccessTokenHelper(); return instance; } /** * 获取当前有效的token * * @return */ public String getToken(int authserver) { String tk=""; long exp=0; Config conf=Config.getInstance(); if(authserver==WEIXIN){ tk=conf.get("weixin.access_token"); exp = Long.parseLong(conf.get("weixin.token_expires"));} else{ tk=Config.getInstance().get("tac.access_token"); exp = Long.parseLong(conf.get("tac.token_expires"));} if (CommonUtil.isEmpty(tk)||exp<=(System.currentTimeMillis() + 20) ){ refetch(authserver); if(authserver==WEIXIN) tk=Config.getInstance().get("weixin.access_token"); else tk=Config.getInstance().get("tac.access_token"); } return tk; } /** * 重新获取access_token 只有当确定当前的token无效时才需要调用。 微信限制每天调用次数,绝不可随意调用。 */ public void refetch(int authserver) { new TokenFetcher(authserver).run(); } /** * 能过HTTPS协议获取Access_token,在过期前20s会自动重新获取 * * @author wking * */ public class TokenFetcher implements Runnable { private int authserver; private Log log = LogFactory.getLog(TokenFetcher.class); public TokenFetcher(int authserver) { this.authserver = authserver; } public void run() { Config conf = Config.getInstance(); String urlstr; try { if (this.authserver == WEIXIN) urlstr = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + conf.get("weixin.appid") + "&secret=" + conf.get("weixin.secret"); else urlstr = "https://tac.fudan.edu.cn/oauth2/token.act?client_id=" + conf.get("tac.clientid") + "&client_secret=" + URLEncoder .encode(conf.get("tac.secret"), "utf-8") + "&grant_type=client_credentials"; String ret = CommonUtil.getWebContent(urlstr).toString(); Object o = JSON.parse(ret); if (o instanceof DBObject) { DBObject dbo = (DBObject) o; int exp = Integer .parseInt(dbo.get("expires_in").toString()); String tk= dbo.get("access_token").toString(); if (this.authserver == WEIXIN) { conf.update("weixin.access_token", tk); conf.update("weixin.token_expires", System.currentTimeMillis() + 1000l * exp); } else { conf.update("tac.access_token", tk); conf.update("tac.token_expires", System.currentTimeMillis() + 1000l * exp); } // Token 到期前20s去取Token // 如果有其他的还没有执行的计划取token的任务,那就取消它 if (schfuture[this.authserver] != null && !schfuture[this.authserver].isDone()) schfuture[this.authserver].cancel(true); schfuture[this.authserver] = ThreadPoolHelper .getInstance() .getSchPool() .schedule(new TokenFetcher(this.authserver), exp - 20, TimeUnit.SECONDS); } else { log.error("Access Token Fetch Failed:" + ret + " SERVER:" + this.authserver); } } catch (Exception e) { log.error(e); } } } }