From 5948e909e3cbee044c995a745e5b16996a84245a Mon Sep 17 00:00:00 2001 From: chengn Date: Fri, 30 Jan 2015 12:45:06 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9js-sdk=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81=EF=BC=8C=E6=8F=90=E4=BE=9Bjsapi=5Fticket?= =?UTF-8?q?=E7=9A=84=E8=8E=B7=E5=8F=96=E5=92=8C=E4=B8=AD=E6=8E=A7=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/org/sword/wechat4j/common/Config.java | 7 + .../sword/wechat4j/message/CustomerMsg.java | 4 +- .../sword/wechat4j/message/TemplateMsg.java | 4 +- src/org/sword/wechat4j/token/AccessToken.java | 102 ++---------- .../wechat4j/token/AccessTokenProxy.java | 31 ---- .../wechat4j/token/AccessTokenServer.java | 46 ------ .../wechat4j/token/DbAccessTokenServer.java | 32 ---- .../wechat4j/token/IAccessTokenServer.java | 19 --- src/org/sword/wechat4j/token/Ticket.java | 58 +++++++ src/org/sword/wechat4j/token/TicketType.java | 13 ++ src/org/sword/wechat4j/token/Token.java | 145 ++++++++++++++++++ ...sTokenListener.java => TokenListener.java} | 16 +- src/org/sword/wechat4j/token/TokenProxy.java | 42 +++++ .../wechat4j/token/server/AbsServer.java | 76 +++++++++ .../AccessTokenMemServer.java} | 20 ++- .../token/server/AccessTokenServer.java | 33 ++++ .../wechat4j/token/server/CustomerServer.java | 31 ++++ .../sword/wechat4j/token/server/IServer.java | 20 +++ .../token/server/JsApiTicketMemServer.java | 62 ++++++++ .../token/server/JsApiTicketServer.java | 40 +++++ .../wechat4j/token/server/TicketServer.java | 13 ++ .../wechat4j/token/server/TokenServer.java | 16 ++ .../token/{ => timer}/AccessTokenTimer.java | 8 +- .../token/timer/JsApiTicketTimer.java | 39 +++++ src/org/sword/wechat4j/user/UserManager.java | 4 +- test/log4j.properties | 16 ++ .../wechat4j/token/AccessTokenServerTest.java | 20 +++ .../sword/wechat4j/token/AccessTokenTest.java | 3 +- test/org/sword/wechat4j/token/TicketTest.java | 14 ++ .../sword/wechat4j/token/TokenProxyTest.java | 33 ++++ 30 files changed, 729 insertions(+), 238 deletions(-) delete mode 100644 src/org/sword/wechat4j/token/AccessTokenProxy.java delete mode 100644 src/org/sword/wechat4j/token/AccessTokenServer.java delete mode 100644 src/org/sword/wechat4j/token/DbAccessTokenServer.java delete mode 100644 src/org/sword/wechat4j/token/IAccessTokenServer.java create mode 100644 src/org/sword/wechat4j/token/Ticket.java create mode 100644 src/org/sword/wechat4j/token/TicketType.java create mode 100644 src/org/sword/wechat4j/token/Token.java rename src/org/sword/wechat4j/token/{AccessTokenListener.java => TokenListener.java} (63%) create mode 100644 src/org/sword/wechat4j/token/TokenProxy.java create mode 100644 src/org/sword/wechat4j/token/server/AbsServer.java rename src/org/sword/wechat4j/token/{MemAccessTokenServer.java => server/AccessTokenMemServer.java} (74%) create mode 100644 src/org/sword/wechat4j/token/server/AccessTokenServer.java create mode 100644 src/org/sword/wechat4j/token/server/CustomerServer.java create mode 100644 src/org/sword/wechat4j/token/server/IServer.java create mode 100644 src/org/sword/wechat4j/token/server/JsApiTicketMemServer.java create mode 100644 src/org/sword/wechat4j/token/server/JsApiTicketServer.java create mode 100644 src/org/sword/wechat4j/token/server/TicketServer.java create mode 100644 src/org/sword/wechat4j/token/server/TokenServer.java rename src/org/sword/wechat4j/token/{ => timer}/AccessTokenTimer.java (74%) create mode 100644 src/org/sword/wechat4j/token/timer/JsApiTicketTimer.java create mode 100644 test/log4j.properties create mode 100644 test/org/sword/wechat4j/token/AccessTokenServerTest.java create mode 100644 test/org/sword/wechat4j/token/TicketTest.java create mode 100644 test/org/sword/wechat4j/token/TokenProxyTest.java diff --git a/src/org/sword/wechat4j/common/Config.java b/src/org/sword/wechat4j/common/Config.java index 4b3a78e..90d3fb0 100644 --- a/src/org/sword/wechat4j/common/Config.java +++ b/src/org/sword/wechat4j/common/Config.java @@ -25,6 +25,7 @@ public class Config { private String appid; private String appSecret; private String accessTokenServer; + private String jsApiTicketServer; private static Config config = new Config(); private Config(){ @@ -42,6 +43,7 @@ private Config(){ this.appid = p.getProperty("wechat.appid"); this.appSecret = p.getProperty("wechat.appsecret"); this.accessTokenServer = p.getProperty("wechat.accessToken.server.class"); + this.jsApiTicketServer = p.getProperty("wechat.ticket.jsapi.server.class"); inStream.close(); } catch (IOException e) { logger.error("load wechat4j.properties error,class根目录下找不到wechat4j.properties文件"); @@ -74,5 +76,10 @@ public String getEncodingAESKey() { public String getAccessTokenServer(){ return accessTokenServer; } + + public String getJsApiTicketServer() { + return jsApiTicketServer; + } + } diff --git a/src/org/sword/wechat4j/message/CustomerMsg.java b/src/org/sword/wechat4j/message/CustomerMsg.java index 1820a3f..cf5a3f4 100644 --- a/src/org/sword/wechat4j/message/CustomerMsg.java +++ b/src/org/sword/wechat4j/message/CustomerMsg.java @@ -15,7 +15,7 @@ import org.sword.wechat4j.response.MusicResponse; import org.sword.wechat4j.response.VideoResponse; import org.sword.wechat4j.token.AccessToken; -import org.sword.wechat4j.token.AccessTokenProxy; +import org.sword.wechat4j.token.TokenProxy; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -56,7 +56,7 @@ public CustomerMsg(String toUserOpenId){ * @param msgBody */ private void send(){ - String accessToken = AccessTokenProxy.token(); + String accessToken = TokenProxy.accessToken(); if(StringUtils.isBlank(this.toUserOpenId)) return; //token不存在则重新刷新token diff --git a/src/org/sword/wechat4j/message/TemplateMsg.java b/src/org/sword/wechat4j/message/TemplateMsg.java index c0e5687..1484ce4 100644 --- a/src/org/sword/wechat4j/message/TemplateMsg.java +++ b/src/org/sword/wechat4j/message/TemplateMsg.java @@ -8,7 +8,7 @@ import org.sword.lang.HttpUtils; import org.sword.wechat4j.message.template.TemplateMsgBody; import org.sword.wechat4j.message.template.TemplateMsgData; -import org.sword.wechat4j.token.AccessTokenProxy; +import org.sword.wechat4j.token.TokenProxy; import com.alibaba.fastjson.JSONObject; @@ -31,7 +31,7 @@ public class TemplateMsg { private String accessToken; public TemplateMsg(){ - this.accessToken = AccessTokenProxy.token(); + this.accessToken = TokenProxy.accessToken(); } /** diff --git a/src/org/sword/wechat4j/token/AccessToken.java b/src/org/sword/wechat4j/token/AccessToken.java index 8fe6047..c7fad3a 100644 --- a/src/org/sword/wechat4j/token/AccessToken.java +++ b/src/org/sword/wechat4j/token/AccessToken.java @@ -3,120 +3,42 @@ */ package org.sword.wechat4j.token; -import java.util.Date; -import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; -import org.sword.lang.HttpUtils; import org.sword.wechat4j.common.Config; -import com.alibaba.fastjson.JSONObject; /** * Access token实体模型 * @author ChengNing * @date 2014年12月12日 */ -public class AccessToken { +public class AccessToken extends Token { private static Logger logger = Logger.getLogger(AccessToken.class); private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"; - private String accessToken; //token - private long expires; //token有效时间 - private long tokenTime; //token产生时间 - - private int redundance = 10*1000; //冗余时间,提前10秒就去请求新的token - - /** - * 请求信的access token - * http请求方式: GET - https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET - {"access_token":"ACCESS_TOKEN","expires_in":7200} - {"errcode":40013,"errmsg":"invalid appid"} - * @return - */ - public boolean request(){ - String url = accessTokenUrl(); - String result = HttpUtils.get(url); - if(StringUtils.isBlank(result)) - return false; - JSONObject jsonObject = JSONObject.parseObject(result); - String accessToken = jsonObject.get("access_token").toString(); - if(StringUtils.isBlank(accessToken)){ - logger.error("access_token获取失败,获取结果" + result); - return false; - } - this.accessToken = accessToken; - this.tokenTime = (new Date()).getTime(); - String expiresIn = jsonObject.get("expires_in").toString(); - if(StringUtils.isBlank(expiresIn)){ - logger.error("access_token获取失败,获取结果" + expiresIn); - return false; - } - else{ - this.expires = Long.valueOf(expiresIn); - } - logger.info("access_token获取成功"); - return true; - } - - /** - * 得到access token - * @return - */ - public String getAccessToken(){ - return this.accessToken; + + @Override + protected String tokenName() { + return "access_token"; } - - /** - * 得到有效时间 - * @return - */ - public long getExpires() { - return expires; + + @Override + protected String expiresInName() { + return "expires_in"; } /** * 组织accesstoken的请求utl - * @return */ - private String accessTokenUrl(){ + @Override + protected String accessTokenUrl() { String appid = Config.instance().getAppid(); String appsecret = Config.instance().getAppSecret(); String url = ACCESS_TOKEN_URL + "&appid=" + appid + "&secret=" + appsecret; + logger.info("创建获取access_token url"); return url; - - } - - /** - * accessToken 是否有效 - * @return true:有效,false: 无效 - */ - public boolean isValid(){ - //黑名单判定法 - if(StringUtils.isBlank(this.accessToken)) - return false; - if(this.expires <= 0) - return false; - //过期 - if(isExpire()) - return false; - return true; - } - - /** - * 是否过期 - * @return true 过期 false:有效 - */ - private boolean isExpire(){ - Date currentDate = new Date(); - long currentTime = currentDate.getTime(); - long expiresTime = expires * 1000 - redundance; - //判断是否过期 - if((tokenTime + expiresTime) > currentTime) - return false; - return true; } diff --git a/src/org/sword/wechat4j/token/AccessTokenProxy.java b/src/org/sword/wechat4j/token/AccessTokenProxy.java deleted file mode 100644 index 3621cf3..0000000 --- a/src/org/sword/wechat4j/token/AccessTokenProxy.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * - */ -package org.sword.wechat4j.token; - - -/** - * AccessToken代理 - * 所有获取accessToken的地方都通过此代理获得 - * 获得方法String token = AccessTokenProxy.token() - * @author ChengNing - * @date 2015年1月9日 - */ -public class AccessTokenProxy { - - /** - * 通过代理得到accessToken的串 - * @return - */ - public static String token(){ - AccessTokenServer accessTokenServer = new AccessTokenServer(); - if(accessTokenServer.isCustomer()) - return accessTokenServer.customerServer().getAccessToken(); - - return accessTokenServer.defaultServer().getAccessToken(); - } - - - - -} diff --git a/src/org/sword/wechat4j/token/AccessTokenServer.java b/src/org/sword/wechat4j/token/AccessTokenServer.java deleted file mode 100644 index e2c1c66..0000000 --- a/src/org/sword/wechat4j/token/AccessTokenServer.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * - */ -package org.sword.wechat4j.token; - -import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.Logger; -import org.sword.wechat4j.common.Config; - -/** - * accessToken中控服务器 - * @author ChengNing - * @date 2015年1月9日 - */ -public class AccessTokenServer { - - private static Logger logger = Logger.getLogger(AccessTokenServer.class); - - public IAccessTokenServer defaultServer(){ - return MemAccessTokenServer.instance(); - } - - public IAccessTokenServer customerServer(){ - String className = Config.instance().getAccessTokenServer(); - IAccessTokenServer customerServer = null; - try { - Class clazz = Class.forName(className); - customerServer = (IAccessTokenServer)clazz.newInstance(); - } catch (Exception e) { - logger.error("系统找不到" + className); - logger.error("自定义accesstoken server实例化失败," + e.getMessage()); - e.printStackTrace(); - } - return customerServer; - } - - /** - * 如果配置文件中配置了AccessTokenServer,那么使用客户自定义server - * @return - */ - public boolean isCustomer(){ - if(StringUtils.isBlank(Config.instance().getAccessTokenServer())) - return false; - return true; - } -} diff --git a/src/org/sword/wechat4j/token/DbAccessTokenServer.java b/src/org/sword/wechat4j/token/DbAccessTokenServer.java deleted file mode 100644 index 7401c17..0000000 --- a/src/org/sword/wechat4j/token/DbAccessTokenServer.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * - */ -package org.sword.wechat4j.token; - -/** - * 数据库管理access token - * 这是一个抽象类,需要由使用者自己去继承此类,并且实现自己的数据库操作 - * @author ChengNing - * @date 2015年1月8日 - */ -public abstract class DbAccessTokenServer implements IAccessTokenServer{ - - @Override - public String getAccessToken() { - return find(); - } - - /** - * 保存或者更新accesstoken到数据库 - * 由客户自己实现数据库插入或者更新操作 - * @return - */ - public abstract boolean save(AccessToken accessToken); - /** - * 从数据库得到accessToken - * 由客户自己实现数据库的查询操作 - * @return - */ - public abstract String find(); - -} diff --git a/src/org/sword/wechat4j/token/IAccessTokenServer.java b/src/org/sword/wechat4j/token/IAccessTokenServer.java deleted file mode 100644 index 63dc142..0000000 --- a/src/org/sword/wechat4j/token/IAccessTokenServer.java +++ /dev/null @@ -1,19 +0,0 @@ -/** - * - */ -package org.sword.wechat4j.token; - - -/** - * - * @author ChengNing - * @date 2015年1月7日 - */ -public interface IAccessTokenServer { - - /** - * - * @return - */ - public String getAccessToken(); -} diff --git a/src/org/sword/wechat4j/token/Ticket.java b/src/org/sword/wechat4j/token/Ticket.java new file mode 100644 index 0000000..bf41a80 --- /dev/null +++ b/src/org/sword/wechat4j/token/Ticket.java @@ -0,0 +1,58 @@ +/** + * + */ +package org.sword.wechat4j.token; + +import org.apache.log4j.Logger; + + +/** + * 微信ticket操作类 + * ticket和token的逻辑在腾讯是差不多的,所以继承抽象类token + * @author ChengNing + * @date 2015年1月29日 + */ +public class Ticket extends Token { + + private static Logger logger = Logger.getLogger(Ticket.class); + + private static final String TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?"; + private static final String TICKET_NAME = "ticket"; + private static final String EXPIRESIN_NAME = "expires_in"; + + private String type; + + public Ticket(TicketType ticketType){ + super(); + this.type = ticketType.name(); + } + + /* (non-Javadoc) + * @see org.sword.wechat4j.token.Token#accessTokenUrl() + */ + @Override + protected String accessTokenUrl() { + String access_token = TokenProxy.accessToken(); + String url = TICKET_URL + "access_token=" + access_token + "&type=" + this.type; + logger.info("获取ticket,ticket类型" + this.type); + return url; + } + + /* (non-Javadoc) + * @see org.sword.wechat4j.token.Token#tokenName() + */ + @Override + protected String tokenName() { + return TICKET_NAME; + } + + /* (non-Javadoc) + * @see org.sword.wechat4j.token.Token#expiresInName() + */ + @Override + protected String expiresInName() { + return EXPIRESIN_NAME; + } + + +} diff --git a/src/org/sword/wechat4j/token/TicketType.java b/src/org/sword/wechat4j/token/TicketType.java new file mode 100644 index 0000000..a6de791 --- /dev/null +++ b/src/org/sword/wechat4j/token/TicketType.java @@ -0,0 +1,13 @@ +/** + * + */ +package org.sword.wechat4j.token; + +/** + * @author ChengNing + * @date 2015年1月29日 + */ +public enum TicketType { + jsapi + +} diff --git a/src/org/sword/wechat4j/token/Token.java b/src/org/sword/wechat4j/token/Token.java new file mode 100644 index 0000000..241a3c4 --- /dev/null +++ b/src/org/sword/wechat4j/token/Token.java @@ -0,0 +1,145 @@ +/** + * + */ +package org.sword.wechat4j.token; + +import java.util.Date; + +import org.apache.commons.lang3.StringUtils; +import org.apache.log4j.Logger; +import org.sword.lang.HttpUtils; + + +import com.alibaba.fastjson.JSONObject; + +/** + * @author ChengNing + * @date 2015年1月29日 + */ +public abstract class Token { + private static Logger logger = Logger.getLogger(Token.class); + + private String token; //token + private long expires; //token有效时间 + + private long tokenTime; //token产生时间 + private int redundance = 10*1000; //冗余时间,提前10秒就去请求新的token + + /** + * 得到access token + * @return + */ + public String getToken(){ + return this.token; + } + + /** + * 得到有效时间 + * @return + */ + public long getExpires() { + return expires; + } + + /** + * 请求信的access token + * http请求方式: GET + https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET + {"access_token":"ACCESS_TOKEN","expires_in":7200} + {"errcode":40013,"errmsg":"invalid appid"} + * @return + */ + public boolean request(){ + String url = accessTokenUrl(); + String result = HttpUtils.get(url); + if(StringUtils.isBlank(result)) + return false; + if(!parseData(result)){ + return false; + } + logger.info("token获取成功"); + return true; + } + + /** + * 解析token数据 + * @param data + * @return + */ + private boolean parseData(String data){ + JSONObject jsonObject = JSONObject.parseObject(data); + String tokenName = tokenName(); + String expiresInName = expiresInName(); + try { + String token = jsonObject.get(tokenName).toString(); + if(StringUtils.isBlank(token)){ + logger.error("token获取失败,获取结果" + data); + return false; + } + this.token = token; + this.tokenTime = (new Date()).getTime(); + String expiresIn = jsonObject.get(expiresInName).toString(); + if(StringUtils.isBlank(expiresIn)){ + logger.error("token获取失败,获取结果" + expiresIn); + return false; + } + else{ + this.expires = Long.valueOf(expiresIn); + } + } catch (Exception e) { + logger.error("token 结果解析失败,token参数名称: " + tokenName + + "有效期参数名称:" + expiresInName + + "token请求结果:" + data); + e.printStackTrace(); + return false; + } + return true; + } + + /** + * token的参数名称 + * @return + */ + protected abstract String tokenName(); + /** + * expireIn的参数名称 + * @return + */ + protected abstract String expiresInName(); + + /** + * 组织accesstoken的请求utl + * @return + */ + protected abstract String accessTokenUrl(); + + /** + * accessToken 是否有效 + * @return true:有效,false: 无效 + */ + public boolean isValid(){ + //黑名单判定法 + if(StringUtils.isBlank(this.token)) + return false; + if(this.expires <= 0) + return false; + //过期 + if(isExpire()) + return false; + return true; + } + + /** + * 是否过期 + * @return true 过期 false:有效 + */ + private boolean isExpire(){ + Date currentDate = new Date(); + long currentTime = currentDate.getTime(); + long expiresTime = expires * 1000 - redundance; + //判断是否过期 + if((tokenTime + expiresTime) > currentTime) + return false; + return true; + } +} diff --git a/src/org/sword/wechat4j/token/AccessTokenListener.java b/src/org/sword/wechat4j/token/TokenListener.java similarity index 63% rename from src/org/sword/wechat4j/token/AccessTokenListener.java rename to src/org/sword/wechat4j/token/TokenListener.java index 740e32d..517ad1f 100644 --- a/src/org/sword/wechat4j/token/AccessTokenListener.java +++ b/src/org/sword/wechat4j/token/TokenListener.java @@ -9,6 +9,8 @@ import javax.servlet.ServletContextListener; import org.apache.log4j.Logger; +import org.sword.wechat4j.token.timer.AccessTokenTimer; +import org.sword.wechat4j.token.timer.JsApiTicketTimer; /** @@ -16,9 +18,9 @@ * @author ChengNing * @date 2015年1月8日 */ -public class AccessTokenListener implements ServletContextListener{ +public class TokenListener implements ServletContextListener{ - private static Logger log = Logger.getLogger(AccessTokenListener.class); + private static Logger log = Logger.getLogger(TokenListener.class); private Timer timer = null; @@ -28,6 +30,8 @@ public void contextInitialized(ServletContextEvent arg0) { timer = new Timer(true); //注册定时任务 registeAccessTokenTimer(); + //注册jsapi_ticket定时器 + registeJsApiTicketTimer(); } @Override @@ -44,4 +48,12 @@ private void registeAccessTokenTimer(){ log.info("accessToken定时器注册成功,执行间隔为" + AccessTokenTimer.PERIOD); } + /** + * 注册jsapi_ticket定时器 + */ + private void registeJsApiTicketTimer(){ + JsApiTicketTimer jsApiTicketTimer = new JsApiTicketTimer(); + timer.schedule(jsApiTicketTimer, JsApiTicketTimer.DELAY,JsApiTicketTimer.PERIOD); + } + } diff --git a/src/org/sword/wechat4j/token/TokenProxy.java b/src/org/sword/wechat4j/token/TokenProxy.java new file mode 100644 index 0000000..623b34c --- /dev/null +++ b/src/org/sword/wechat4j/token/TokenProxy.java @@ -0,0 +1,42 @@ +/** + * + */ +package org.sword.wechat4j.token; + +import org.sword.wechat4j.token.server.AccessTokenServer; +import org.sword.wechat4j.token.server.JsApiTicketServer; +import org.sword.wechat4j.token.server.TicketServer; +import org.sword.wechat4j.token.server.TokenServer; + + +/** + * AccessToken代理 + * 所有获取accessToken的地方都通过此代理获得 + * 获得方法String token = AccessTokenProxy.token() + * @author ChengNing + * @date 2015年1月9日 + */ +public class TokenProxy { + + /** + * 通过代理得到accessToken的串 + * @return + */ + public static String accessToken(){ + TokenServer accessTokenServer = new AccessTokenServer(); + return accessTokenServer.token(); + } + + /** + * 通过代理得到jsapi_ticket + * @return + */ + public static String jsApiTicket(){ + TicketServer ticketServer = new JsApiTicketServer(); + return ticketServer.ticket(); + } + + + + +} diff --git a/src/org/sword/wechat4j/token/server/AbsServer.java b/src/org/sword/wechat4j/token/server/AbsServer.java new file mode 100644 index 0000000..3b8fd73 --- /dev/null +++ b/src/org/sword/wechat4j/token/server/AbsServer.java @@ -0,0 +1,76 @@ +/** + * + */ +package org.sword.wechat4j.token.server; + +import org.apache.commons.lang3.StringUtils; +import org.apache.log4j.Logger; + +/** + * @author ChengNing + * @date 2015年1月29日 + */ +public abstract class AbsServer implements IServer{ + + private static Logger logger = Logger.getLogger(AbsServer.class); + + protected String customerServerClass; + + public AbsServer(){ + this.customerServerClass = getCustomerServerClass(); + } + + @Override + public String token(){ + return server().token(); + } + /** + * 得到系统可用的中控服务器 + * @return + */ + public IServer server(){ + if(isCustomer()) + return customerServer(); + return defaultServer(); + } + + /** + * 加载自定义中控服务器 + * @return + */ + public IServer customerServer(){ + String className = customerServerClass; + IServer customerServer = null; + try { + Class clazz = Class.forName(className); + customerServer = (IServer)clazz.newInstance(); + } catch (Exception e) { + logger.error("系统找不到" + className); + logger.error("自定义server实例化失败," + e.getMessage()); + e.printStackTrace(); + } + return customerServer; + } + + /** + * 如果配置文件中配置了AccessTokenServer,那么使用客户自定义server + * @return + */ + public boolean isCustomer(){ + if(StringUtils.isBlank(customerServerClass)) + return false; + return true; + } + + /** + * 指定的默认中控服务器 + * @return + */ + public abstract IServer defaultServer() ; + + /** + * 自定义服务器的类 + * @return + */ + protected abstract String getCustomerServerClass(); +} diff --git a/src/org/sword/wechat4j/token/MemAccessTokenServer.java b/src/org/sword/wechat4j/token/server/AccessTokenMemServer.java similarity index 74% rename from src/org/sword/wechat4j/token/MemAccessTokenServer.java rename to src/org/sword/wechat4j/token/server/AccessTokenMemServer.java index 44b0271..a8d1481 100644 --- a/src/org/sword/wechat4j/token/MemAccessTokenServer.java +++ b/src/org/sword/wechat4j/token/server/AccessTokenMemServer.java @@ -1,7 +1,11 @@ /** * */ -package org.sword.wechat4j.token; +package org.sword.wechat4j.token.server; + +import org.sword.wechat4j.token.AccessToken; +import org.sword.wechat4j.token.Ticket; +import org.sword.wechat4j.token.TicketType; /** * 内存中控服务器 @@ -14,17 +18,19 @@ * @author ChengNing * @date 2015年1月8日 */ -public class MemAccessTokenServer implements IAccessTokenServer{ +public class AccessTokenMemServer implements IServer{ - private static MemAccessTokenServer tokenServer = new MemAccessTokenServer(); + private static AccessTokenMemServer tokenServer = new AccessTokenMemServer(); + private AccessToken accessToken = new AccessToken(); + private int requestTimes = 1;//token请求失败后重新请求的次数 /** * 私有构造 */ - private MemAccessTokenServer(){ + private AccessTokenMemServer(){ //获取新的token refresh(); } @@ -33,7 +39,7 @@ private MemAccessTokenServer(){ * token中控服务器实例 * @return */ - public static MemAccessTokenServer instance(){ + public static AccessTokenMemServer instance(){ return tokenServer; } @@ -53,8 +59,8 @@ private AccessToken accessToken(){ * 通过中控服务器得到accessToken * @return */ - public String getAccessToken(){ - return accessToken().getAccessToken(); + public String token(){ + return accessToken().getToken(); } /** diff --git a/src/org/sword/wechat4j/token/server/AccessTokenServer.java b/src/org/sword/wechat4j/token/server/AccessTokenServer.java new file mode 100644 index 0000000..9919c26 --- /dev/null +++ b/src/org/sword/wechat4j/token/server/AccessTokenServer.java @@ -0,0 +1,33 @@ +/** + * + */ +package org.sword.wechat4j.token.server; + +import org.sword.wechat4j.common.Config; + +/** + * 适配器 + * @author ChengNing + * @date 2015年1月30日 + */ +public class AccessTokenServer extends AbsServer implements TokenServer { + + + /** + * + */ + public String token(){ + return super.token(); + } + + @Override + protected String getCustomerServerClass() { + return Config.instance().getAccessTokenServer(); + } + + @Override + public IServer defaultServer() { + return AccessTokenMemServer.instance(); + } + +} diff --git a/src/org/sword/wechat4j/token/server/CustomerServer.java b/src/org/sword/wechat4j/token/server/CustomerServer.java new file mode 100644 index 0000000..0b46a16 --- /dev/null +++ b/src/org/sword/wechat4j/token/server/CustomerServer.java @@ -0,0 +1,31 @@ +/** + * + */ +package org.sword.wechat4j.token.server; + +import org.sword.wechat4j.token.Token; + +/** + * @author ChengNing + * @date 2015年1月30日 + */ +public abstract class CustomerServer implements IServer { + + public String token(){ + return find(); + } + + /** + * 保存或者更新accesstoken到数据库 + * 由客户自己实现数据库插入或者更新操作 + * @return + */ + public abstract boolean save(Token token); + /** + * 从数据库得到accessToken + * 由客户自己实现数据库的查询操作 + * @return + */ + protected abstract String find(); + +} diff --git a/src/org/sword/wechat4j/token/server/IServer.java b/src/org/sword/wechat4j/token/server/IServer.java new file mode 100644 index 0000000..8f735de --- /dev/null +++ b/src/org/sword/wechat4j/token/server/IServer.java @@ -0,0 +1,20 @@ +/** + * + */ +package org.sword.wechat4j.token.server; + + +/** + * + * @author ChengNing + * @date 2015年1月7日 + */ +public interface IServer { + + public String token(); +// +// public IServer server(); +// +// public IServer customerServer(); +// +} diff --git a/src/org/sword/wechat4j/token/server/JsApiTicketMemServer.java b/src/org/sword/wechat4j/token/server/JsApiTicketMemServer.java new file mode 100644 index 0000000..854b6ca --- /dev/null +++ b/src/org/sword/wechat4j/token/server/JsApiTicketMemServer.java @@ -0,0 +1,62 @@ +/** + * + */ +package org.sword.wechat4j.token.server; + +import org.sword.wechat4j.token.Ticket; +import org.sword.wechat4j.token.TicketType; + +/** + * 内存控制单例 + * @author ChengNing + * @date 2015年1月29日 + */ +public class JsApiTicketMemServer implements IServer{ + + private static JsApiTicketMemServer ticketServer = new JsApiTicketMemServer(); + + private Ticket jsApiTicket = new Ticket(TicketType.jsapi); + + private int requestTimes = 1;//token请求失败后重新请求的次数 + + /** + * 私有构造 + */ + private JsApiTicketMemServer(){ + //获取新的token + refresh(); + } + + /** + * token中控服务器实例 + * @return + */ + public static JsApiTicketMemServer instance(){ + return ticketServer; + } + + + /** + * 通过中控服务器得到accessToken + * @return + */ + public String token(){ + //没有可用的token,则去刷新 + if(!this.jsApiTicket.isValid()){ + refresh(); + } + return this.jsApiTicket.getToken(); + } + + /** + * 服务器刷新token + */ + private void refresh(){ + for(int i=0;i Date: Fri, 30 Jan 2015 12:50:57 +0800 Subject: [PATCH 2/2] modify wechat4j.properties --- META-INF/wechat4j.properties.sample | 11 ++++++++--- src/wechat4j.properties.sample | 11 ++++++++--- test/wechat4j.properties | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 test/wechat4j.properties diff --git a/META-INF/wechat4j.properties.sample b/META-INF/wechat4j.properties.sample index 81ceeb9..2108c4a 100644 --- a/META-INF/wechat4j.properties.sample +++ b/META-INF/wechat4j.properties.sample @@ -9,9 +9,14 @@ wechat.encodingaeskey= #wechat appid wechat.appid=appid #wechat app secret -wechat.appsecret=secret +wechat.appsecret=appsecret #wechat access token server ,when you save in db,must implement you server class -#this class must extend org.sword.wechat4j.token.DbAccessTokenServer -#if no this property,then token server is default memery accesstoken server() +#this class must extend org.sword.wechat4j.token.server.CustomerServer +#if no this property,then token server is default memery accesstoken server wechat.accessToken.server.class= + +#jsapi_ticket customer server class name, +#this class must extend org.sword.wechat4j.token.server.CustomerServer +#if no this property,then ticket server is default memery ticket server +wechat.ticket.jsapi.server.class= \ No newline at end of file diff --git a/src/wechat4j.properties.sample b/src/wechat4j.properties.sample index 81ceeb9..2108c4a 100644 --- a/src/wechat4j.properties.sample +++ b/src/wechat4j.properties.sample @@ -9,9 +9,14 @@ wechat.encodingaeskey= #wechat appid wechat.appid=appid #wechat app secret -wechat.appsecret=secret +wechat.appsecret=appsecret #wechat access token server ,when you save in db,must implement you server class -#this class must extend org.sword.wechat4j.token.DbAccessTokenServer -#if no this property,then token server is default memery accesstoken server() +#this class must extend org.sword.wechat4j.token.server.CustomerServer +#if no this property,then token server is default memery accesstoken server wechat.accessToken.server.class= + +#jsapi_ticket customer server class name, +#this class must extend org.sword.wechat4j.token.server.CustomerServer +#if no this property,then ticket server is default memery ticket server +wechat.ticket.jsapi.server.class= \ No newline at end of file diff --git a/test/wechat4j.properties b/test/wechat4j.properties new file mode 100644 index 0000000..2108c4a --- /dev/null +++ b/test/wechat4j.properties @@ -0,0 +1,22 @@ + +#you server url +wechat.url= +#you wechat token +wechat.token=token +#message secret key,if don't set then message is cleartext +wechat.encodingaeskey= + +#wechat appid +wechat.appid=appid +#wechat app secret +wechat.appsecret=appsecret + +#wechat access token server ,when you save in db,must implement you server class +#this class must extend org.sword.wechat4j.token.server.CustomerServer +#if no this property,then token server is default memery accesstoken server +wechat.accessToken.server.class= + +#jsapi_ticket customer server class name, +#this class must extend org.sword.wechat4j.token.server.CustomerServer +#if no this property,then ticket server is default memery ticket server +wechat.ticket.jsapi.server.class= \ No newline at end of file