微信企业号企业号微信令牌维护模块设计(线程模拟) 公众号开发
企业号令牌维护模块设计的原因:
微信对于令牌获取有次数限制;于是系统若想正常运行,2000次申请次数是不满足长期运行的要求的,于是系统需要对齐定期维护更新,将更新下来的令牌存储起来,提供给消费者
模块设计流程图:
模块设计代码功能:
配置系统启动后 令牌维护线程自动启动
<bean id="accessTokenConfig" class="com.dykj.dyoa.action.weixin_qyh.TimerOfAccesstokenConfig" init-method="init"></bean>
线程体维护模块:
//线程监控线程 随系统启动而启动
public class TimerOfAccesstokenConfig {
public void init() {
new runThread().start();
}
}
class runThread extends Thread {
// 获取运行线程
accessTokenTask thread = null;
// 第几个线程
int i = 1;
boolean threadState = false;
public void run() {
if (thread == null) {
thread = new accessTokenTask();
thread.setDaemon(true);
thread.start();
}
while (true) {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadState = thread.isRunning();
// System.out.println("checking " + threadState);
// 线程终止了 发生了异常
if (threadState == false) {
if (thread.isAlive() || thread.isInterrupted()) {
thread.destroy();
}
i++;
System.out.println("获取微信令牌错误,正在尝试链接 ,第 " + i + " 次");
thread = new accessTokenTask();
thread.setDaemon(true);
thread.start();
}
}
}
}
/**
* 访问令牌定时请求微信服务器 同步令牌 , 并将令牌存放到 文件内 accesstoken.txt
*/
class accessTokenTask extends Thread {
private String path = this.getClass().getResource("accesstoken.txt").getFile().toString();
private boolean running = true;
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
while (running) {
File file = new File(path);
try {
System.out.println(new SimpleDateFormat("YYYY-MM-dd hh:mm:ss").format(new Date()));
String newAccessToken = WeixinUtil.getAccessToken(WeixinAction.CorpID, WeixinAction.Secret);
// System.out.println(newAccessToken);
// 将此令牌存入 file内
if (!file.exists()) {
file.createNewFile();
}
if (file.canWrite()) {
FileWriter fw = new FileWriter(file);
fw.write(newAccessToken);
fw.flush();
fw.close();
Thread.sleep(60000 * 2); //2分钟一次
}
} catch (Exception e) {
this.running = false;
}
}
}
}
令牌如何使用呢? 既然搭建的是框架,那么当然需要采用通用的模式来处理令牌数据了, 应用模式为切面模式, 编写过滤器,其内对微信的所有链接进行拦截处理,
下面的代码只是嵌入过滤器的部分代码:
/**
* 存储令牌信息的文件路径地址
*/
private String path = getClass().getResource("accesstoken.txt").getFile().toString();
/**
* 从文件中读取 访问令牌 工具函数
*/
private synchronized String getTokenFromFile() {
File file = new File(path);
if (file.exists() && file.canRead()) {
try {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String token = br.readLine();
br.close();
fr.close();
return token;
} catch (Exception e) {
e.printStackTrace();
return "no";
}
} else {
try {
Thread.sleep(50000);
this.notify();
getTokenFromFile();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "no";
}
//过滤器核心 读取从文件中 读取令牌信息
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
HttpServletRequest hRequest = (HttpServletRequest) request;
// 请求的路径
String contextPath = hRequest.getContextPath();
// 这里读取文件获取 访问权限
String tokenFromFile = this.getTokenFromFile();
// 获取了 token的话, 同步到系统级别的缓存中
if (!"no".equals(tokenFromFile)) {
request.getServletContext().setAttribute("accessToken", tokenFromFile);
// 标记为已经读取
} else {
System.out.println("token from file fail ");
}
}
工具函数:
/**
* 获取AccessToken; 每个secret代表了对应用、通讯录的不同权限;不同的管理组拥有不同的secret。
*
* @param corpid
* 企业Id
* @param corpsecret
* 管理组的凭证密钥
*/
public static String getAccessToken(String corpid, String corpsecret) throws Exception {
String token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + corpid + "&corpsecret="
+ corpsecret;
String access_token = null;
URL url = new URL(token_url);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setRequestMethod("GET");
InputStream inputStream = conn.getInputStream();
Reader in = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(in);
StringBuffer buffer = new StringBuffer();
String str = null;
while ((str = reader.readLine()) != null) {
buffer.append(str);
}
inputStream.close();
in.close();
reader.close();
conn.disconnect();
JSONObject json = JSONObject.fromObject(buffer.toString());
// System.out.println("获取的ACESStoken json str = " + json);
access_token = json.getString("access_token");
if (access_token != null) {
// System.out.println("访问令牌:" + access_token);
} else {
System.out.println("token获取失败!");
}
return access_token;
/* 注:企业号融合过程中该接口输出参数可能略有不同,以下情况均视作获取token成功:
1、能获取到access_token,接口无返回errcode
2、能获取到access_token,接口返回errcode为0, errmsg为空或者"ok"
正确的Json返回结果:
{
"access_token": "accesstoken000001",
"expires_in": 7200
}
b)错误的Json返回示例:
{
"errcode": 43003,
"errmsg": "require https"
}*/
}
如有疑问 请留言 欢迎提供建议
评论已有 0 条