From 66bc364b33d5f4e4d77e919629a85d71bbc19738 Mon Sep 17 00:00:00 2001 From: jinyu Date: Mon, 22 Jun 2015 17:12:40 +0800 Subject: [PATCH] =?UTF-8?q?weixin4j-qy:=E6=96=B0=E5=A2=9E=E7=AC=AC?= =?UTF-8?q?=E4=B8=89=E6=96=B9=E5=BA=94=E7=94=A8=E5=A4=9A=E4=B8=AAAPI?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../foxinmy/weixin4j/token/CacheStorager.java | 36 +++ .../weixin4j/token/FileTokenStorager.java | 23 +- .../foxinmy/weixin4j/token/TokenHolder.java | 4 +- .../foxinmy/weixin4j/token/TokenStorager.java | 25 +- weixin4j-qy/README.md | 2 + .../com/foxinmy/weixin4j/qy/api/AgentApi.java | 4 +- .../com/foxinmy/weixin4j/qy/api/OauthApi.java | 23 +- .../com/foxinmy/weixin4j/qy/api/QyApi.java | 7 - .../com/foxinmy/weixin4j/qy/api/SuiteApi.java | 222 ++++++++++++++++-- .../foxinmy/weixin4j/qy/api/weixin.properties | 8 +- .../foxinmy/weixin4j/qy/model/Corpinfo.java | 82 +++++-- .../foxinmy/weixin4j/qy/model/OUserInfo.java | 138 +++++++++-- .../qy/suite/FileTicketProcessor.java | 61 ----- .../weixin4j/qy/suite/SuitePerCodeHolder.java | 58 +++++ .../weixin4j/qy/suite/SuiteTicketHolder.java | 56 +++++ .../qy/suite/SuiteTicketProcessor.java | 31 --- .../qy/suite/WeixinSuiteTokenCreator.java | 12 +- .../qy/suite/WeixinTokenSuiteCreator.java | 65 +++++ .../foxinmy/weixin4j/qy/type/URLConsts.java | 6 + 19 files changed, 641 insertions(+), 222 deletions(-) create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/CacheStorager.java delete mode 100644 weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/FileTicketProcessor.java create mode 100644 weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuitePerCodeHolder.java create mode 100644 weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketHolder.java delete mode 100644 weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketProcessor.java create mode 100644 weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinTokenSuiteCreator.java diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/CacheStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/CacheStorager.java new file mode 100644 index 00000000..15920c92 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/CacheStorager.java @@ -0,0 +1,36 @@ +package com.foxinmy.weixin4j.token; + +import com.foxinmy.weixin4j.exception.WeixinException; + +/** + * cache存储 + * + * @className CacheStorager + * @author jy + * @date 2015年6月22日 + * @since JDK 1.7 + * @see + */ +public interface CacheStorager { + /** + * 查找缓存中的对象 + * + * @param cacheKey + * 缓存名称 + * @return + * @throws WeixinException + */ + T lookup(String cacheKey) throws WeixinException; + + /** + * 缓存新的对象 + * + * @param cacheKey + * 缓存名称 + * + * @param t + * 将要缓存的对象 + * @throws WeixinException + */ + void caching(String cacheKey, T t) throws WeixinException; +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java index d91b1126..f44124cb 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java @@ -20,27 +20,29 @@ import com.foxinmy.weixin4j.xml.XmlStream; */ public class FileTokenStorager implements TokenStorager { - private final String tokenPath; + private final String cachePath; public FileTokenStorager() { this(ConfigUtil.getValue("token_path")); } - public FileTokenStorager(String tokenPath) { - this.tokenPath = tokenPath; + public FileTokenStorager(String cachePath) { + this.cachePath = cachePath; } @Override - public Token lookupToken(String cacheKey) throws WeixinException { - File token_file = new File(String.format("%s/%s.xml", tokenPath, + public Token lookup(String cacheKey) throws WeixinException { + File token_file = new File(String.format("%s/%s.xml", cachePath, cacheKey)); try { if (token_file.exists()) { Token token = XmlStream.fromXML( new FileInputStream(token_file), Token.class); - long expire_time = token.getTime() - + (token.getExpiresIn() * 1000) - 2; - if (expire_time > System.currentTimeMillis()) { + if (token.getTime() < 0) { + return token; + } + if ((token.getTime() + (token.getExpiresIn() * 1000l) - 2) > System + .currentTimeMillis()) { return token; } } @@ -51,13 +53,12 @@ public class FileTokenStorager implements TokenStorager { } @Override - public void cachingToken(String cacheKey, Token token) - throws WeixinException { + public void caching(String cacheKey, Token token) throws WeixinException { try { XmlStream.toXML( token, new FileOutputStream(new File(String.format("%s/%s.xml", - tokenPath, cacheKey)))); + cachePath, cacheKey)))); } catch (IOException e) { throw new WeixinException(e.getMessage()); } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenHolder.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenHolder.java index 5cbe26f1..cbbe6bcb 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenHolder.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenHolder.java @@ -44,10 +44,10 @@ public final class TokenHolder { */ public Token getToken() throws WeixinException { String cacheKey = tokenCreator.getCacheKey(); - Token token = tokenStorager.lookupToken(cacheKey); + Token token = tokenStorager.lookup(cacheKey); if (token == null) { token = tokenCreator.createToken(); - tokenStorager.cachingToken(cacheKey, token); + tokenStorager.caching(cacheKey, token); } return token; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenStorager.java index c2e0dacf..9bc36913 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenStorager.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenStorager.java @@ -1,6 +1,5 @@ package com.foxinmy.weixin4j.token; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.model.Token; /** @@ -14,27 +13,5 @@ import com.foxinmy.weixin4j.model.Token; * @see com.foxinmy.weixin4j.token.FileTokenStorager * @see com.foxinmy.weixin4j.token.RedisTokenStorager */ -public interface TokenStorager { - /** - * 查找缓存的token - * - * @param cacheKey - * 缓存的名称 - * @return 查找结果 - * @throws WeixinException - */ - public Token lookupToken(String cacheKey) throws WeixinException; - - /** - * 缓存新的token - * - * @param cacheKey - * 缓存的名称 - * - * @param token - * 新产生的token - * @throws WeixinException - */ - public void cachingToken(String cacheKey, Token token) - throws WeixinException; +public interface TokenStorager extends CacheStorager { } diff --git a/weixin4j-qy/README.md b/weixin4j-qy/README.md index 33bc0f67..fba59a5d 100644 --- a/weixin4j-qy/README.md +++ b/weixin4j-qy/README.md @@ -24,6 +24,8 @@ weixin4j-qy * BatchApi `批量操作API` * OauthApi `oauth授权登陆API` + + * SuiteApi `第三方应用API` 如何使用 -------- diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/AgentApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/AgentApi.java index 97bd34df..d0d5ac64 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/AgentApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/AgentApi.java @@ -65,7 +65,7 @@ public class AgentApi extends QyApi { * 设置企业应用的选项设置信息,如:地理位置上报等 * * @param agentSet - * 设置参数 + * 设置信息 * @see com.foxinmy.weixin4j.qy.model.AgentSetter * @see 设置企业号信息 @@ -81,7 +81,7 @@ public class AgentApi extends QyApi { return response.getAsJsonResult(); } - private static ValueFilter typeFilter; + public static ValueFilter typeFilter; static { typeFilter = new ValueFilter() { @Override diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java index a25d1286..a61acc81 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java @@ -4,11 +4,9 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.parser.deserializer.ExtraProcessor; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Consts; -import com.foxinmy.weixin4j.qy.model.Corpinfo; import com.foxinmy.weixin4j.qy.model.OUserInfo; import com.foxinmy.weixin4j.util.ConfigUtil; @@ -83,26 +81,7 @@ public class OauthApi extends QyApi { WeixinResponse response = weixinClient.post( String.format(oauth_logininfo_uri, providerToken), String.format("{\"auth_code\":\"%s\"}", authCode)); - return JSON.parseObject(response.getAsString(), OUserInfo.class, - new ExtraProcessor() { - - @Override - public void processExtra(Object object, String key, - Object value) { - if (object instanceof Corpinfo) { - Corpinfo corpinfo = (Corpinfo) object; - if (key.equalsIgnoreCase("corp_name")) { - corpinfo.setName(value.toString()); - } else if (key - .equalsIgnoreCase("corp_round_logo_url")) { - corpinfo.setRoundLogoUrl(value.toString()); - } else if (key - .equalsIgnoreCase("corp_square_logo_url")) { - corpinfo.setSquareLogoUrl(value.toString()); - } - } - } - }); + return JSON.parseObject(response.getAsString(), OUserInfo.class); } /** diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java index a3a8295c..03d95403 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java @@ -5,8 +5,6 @@ import java.util.ResourceBundle; import com.alibaba.fastjson.JSON; import com.foxinmy.weixin4j.api.BaseApi; import com.foxinmy.weixin4j.qy.model.WeixinQyAccount; -import com.foxinmy.weixin4j.qy.suite.FileTicketProcessor; -import com.foxinmy.weixin4j.qy.suite.SuiteTicketProcessor; import com.foxinmy.weixin4j.util.ConfigUtil; /** @@ -26,17 +24,12 @@ public class QyApi extends BaseApi { * 默认使用weixin4j.properties文件中的企业号信息 */ public final static WeixinQyAccount DEFAULT_WEIXIN_ACCOUNT; - /** - * 默认使用File的方法读取套件ticket - */ - public final static SuiteTicketProcessor DEFAULT_TICKET_PROCESSOR; static { WEIXIN_BUNDLE = ResourceBundle .getBundle("com/foxinmy/weixin4j/qy/api/weixin"); DEFAULT_WEIXIN_ACCOUNT = JSON.parseObject( ConfigUtil.getValue("account"), WeixinQyAccount.class); - DEFAULT_TICKET_PROCESSOR = new FileTicketProcessor(); } @Override diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java index 6654fd3f..c47339fb 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java @@ -1,12 +1,23 @@ package com.foxinmy.weixin4j.qy.api; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; -import com.foxinmy.weixin4j.qy.suite.SuiteTicketProcessor; +import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.qy.model.AgentInfo; +import com.foxinmy.weixin4j.qy.model.AgentSetter; +import com.foxinmy.weixin4j.qy.model.OUserInfo; +import com.foxinmy.weixin4j.qy.model.User; +import com.foxinmy.weixin4j.qy.suite.SuitePerCodeHolder; +import com.foxinmy.weixin4j.qy.suite.SuiteTicketHolder; import com.foxinmy.weixin4j.qy.suite.WeixinSuitePreCodeCreator; import com.foxinmy.weixin4j.qy.suite.WeixinSuiteTokenCreator; +import com.foxinmy.weixin4j.qy.suite.WeixinTokenSuiteCreator; +import com.foxinmy.weixin4j.qy.token.WeixinTokenCreator; +import com.foxinmy.weixin4j.token.TokenCreator; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenStorager; @@ -21,12 +32,30 @@ import com.foxinmy.weixin4j.token.TokenStorager; * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8%E6%8E%88%E6%9D%83">第三方应用授权 */ public class SuiteApi extends QyApi { - /** * 应用套件token */ private final TokenHolder suiteTokenHolder; - private final TokenHolder suiteTicketHolder; + /** + * 应用套件ticket + */ + private final SuiteTicketHolder suiteTicketHolder; + /** + * 应用套件永久授权码 + */ + private final SuitePerCodeHolder suitePerCodeHolder; + /** + * 应用套件pre_code + */ + private final TokenHolder suitePreCodeHolder; + /** + * 应用套件的存储策略 + */ + private final TokenStorager tokenStorager; + /** + * 应用套件ID + */ + private final String suiteId; public SuiteApi() throws WeixinException { this(DEFAULT_WEIXIN_ACCOUNT.getSuiteId(), DEFAULT_WEIXIN_ACCOUNT @@ -34,8 +63,7 @@ public class SuiteApi extends QyApi { } public SuiteApi(String suiteId, String suiteSecret) throws WeixinException { - this(suiteId, suiteSecret, DEFAULT_TICKET_PROCESSOR, - DEFAULT_TOKEN_STORAGER); + this(suiteId, suiteSecret, DEFAULT_TOKEN_STORAGER); } /** @@ -44,19 +72,23 @@ public class SuiteApi extends QyApi { * 应用ID * @param suiteSecret * 应用secret - * @param ticketReader - * 应用ticket读取器 + * @param ticketStorager + * 应用ticket存储器(用于读取) * @param tokenStorager * 应用token存储器 * @throws WeixinException */ public SuiteApi(String suiteId, String suiteSecret, - SuiteTicketProcessor ticketReader, TokenStorager tokenStorager) - throws WeixinException { + TokenStorager tokenStorager) throws WeixinException { + this.suiteTicketHolder = new SuiteTicketHolder(tokenStorager); this.suiteTokenHolder = new TokenHolder(new WeixinSuiteTokenCreator( - suiteId, suiteSecret, ticketReader), tokenStorager); - this.suiteTicketHolder = new TokenHolder(new WeixinSuitePreCodeCreator( - suiteTokenHolder, suiteId), tokenStorager); + suiteId, suiteSecret, suiteTicketHolder), tokenStorager); + this.suitePreCodeHolder = new TokenHolder( + new WeixinSuitePreCodeCreator(suiteTokenHolder, suiteId), + tokenStorager); + this.suitePerCodeHolder = new SuitePerCodeHolder(tokenStorager); + this.tokenStorager = tokenStorager; + this.suiteId = suiteId; } /** @@ -73,10 +105,40 @@ public class SuiteApi extends QyApi { * * @return */ - public TokenHolder getTicketHolder() { + public SuiteTicketHolder getTicketHolder() { return this.suiteTicketHolder; } + /** + * 应用套件永久授权码 + * + * @return + */ + public SuitePerCodeHolder getPerCodeHolder() { + return this.suitePerCodeHolder; + } + + /** + * 应用套件pre_code + * + * @return + */ + public TokenHolder getPreCodeHolder() { + return this.suitePreCodeHolder; + } + + /** + * 获取企业号access_token(永久授权码) + * + * @param authCorpid + * 授权方corpid + * @return 企业号token + */ + public TokenHolder crateTokenHolder(String authCorpid) { + return new TokenHolder(new WeixinTokenSuiteCreator(suiteId, authCorpid, + suitePerCodeHolder), tokenStorager); + } + /** * 设置套件授权配置:如果需要对某次授权进行配置,则调用本接口,目前仅可以设置哪些应用可以授权,不调用则默认允许所有应用进行授权。 * @@ -84,18 +146,144 @@ public class SuiteApi extends QyApi { * 允许进行授权的应用id,如1、2、3 * @return 处理结果 * @throws WeixinException - * 设置套件授权配置 + * @see 设置套件授权配置 */ public JsonResult setSuiteSession(int... appids) throws WeixinException { String suite_set_session_uri = getRequestUri("suite_set_session_uri"); JSONObject para = new JSONObject(); - para.put("pre_auth_code", suiteTicketHolder.getAccessToken()); + para.put("pre_auth_code", suiteTicketHolder.lookup(suiteId)); para.put("session_info", appids); WeixinResponse response = weixinClient .post(String.format(suite_set_session_uri, suiteTokenHolder.getAccessToken()), para.toJSONString()); return response.getAsJsonResult(); } + + /** + * 获取企业号的永久授权码 + * + * @param authCode + * 临时授权码会在授权成功时附加在redirect_uri中跳转回应用提供商网站。 + * @return 授权得到的信息 + * @throws WeixinException + * @see com.foxinmy.weixin4j.qy.model.OUserInfo + * @see 获取企业号的永久授权码 + */ + public OUserInfo exchangePermanentCode(String authCode) + throws WeixinException { + String suite_get_permanent_uri = getRequestUri("suite_get_permanent_uri"); + JSONObject obj = new JSONObject(); + obj.put("suite_id", suiteId); + obj.put("auth_code", authCode); + WeixinResponse response = weixinClient.post( + String.format(suite_get_permanent_uri, + suiteTokenHolder.getAccessToken()), obj.toJSONString()); + obj = response.getAsJson(); + obj.put("corp_info", obj.remove("auth_corp_info")); + obj.put("user_info", obj.remove("auth_user_info")); + OUserInfo oInfo = JSON.toJavaObject(obj, OUserInfo.class); + // 缓存微信企业号access_token + TokenCreator tokenCreator = new WeixinTokenCreator(oInfo.getCorpinfo() + .getCorpid(), null); + Token token = new Token(obj.getString("access_token")); + token.setExpiresIn(obj.getIntValue("expires_in")); + token.setTime(System.currentTimeMillis()); + tokenStorager.caching(tokenCreator.getCacheKey(), token); + // 缓存微信企业号永久授权码 + suitePerCodeHolder.caching(suiteId, obj.getString("permanent_code")); + return oInfo; + } + + /** + * 获取企业号的授权信息 + * + * @param authCorpid + * 授权方corpid + * @return 授权方信息 + * @throws WeixinException + * @see com.foxinmy.weixin4j.qy.model.OUserInfo + * @see 获取企业号的授权信息 + */ + public OUserInfo getOAuthInfo(String authCorpid) throws WeixinException { + String suite_get_authinfo_uri = getRequestUri("suite_get_authinfo_uri"); + JSONObject obj = new JSONObject(); + obj.put("suite_id", suiteId); + obj.put("auth_corpid", authCorpid); + obj.put("permanent_code", suitePerCodeHolder.lookup(suiteId)); + WeixinResponse response = weixinClient.post( + String.format(suite_get_authinfo_uri, + suiteTokenHolder.getAccessToken()), obj.toJSONString()); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 获取企业号应用 + * + * @param authCorpid + * 授权方corpid + * @param agentid + * 授权方应用id + * @return 应用信息 + * @see com.foxinmy.weixin4j.qy.model.AgentInfo + * @see 获取企业号应用 + * @throws WeixinException + */ + public AgentInfo getAgent(String authCorpid, int agentid) + throws WeixinException { + String suite_get_agent_uri = getRequestUri("suite_get_agent_uri"); + JSONObject obj = new JSONObject(); + obj.put("suite_id", suiteId); + obj.put("auth_corpid", authCorpid); + obj.put("permanent_code", suitePerCodeHolder.lookup(suiteId)); + obj.put("agentid", agentid); + WeixinResponse response = weixinClient.post(String.format( + suite_get_agent_uri, suiteTokenHolder.getAccessToken(), + obj.toJSONString())); + JSONObject jsonObj = response.getAsJson(); + AgentInfo agent = JSON.toJavaObject(jsonObj, AgentInfo.class); + agent.setAllowUsers(JSON.parseArray( + jsonObj.getJSONObject("allow_userinfos").getString("user"), + User.class)); + agent.setAllowPartys(JSON.parseArray( + jsonObj.getJSONObject("allow_partys").getString("partyid"), + Integer.class)); + agent.setAllowTags(JSON.parseArray(jsonObj.getJSONObject("allow_tags") + .getString("tagid"), Integer.class)); + return agent; + } + + /** + * 设置企业应用的选项设置信息,如:地理位置上报等 + * + * @param authCorpid + * 授权方corpid + * @param agentSet + * 设置信息 + * @see com.foxinmy.weixin4j.qy.model.AgentSetter + * @see 设置企业号信息 + * @return 处理结果 + * @throws WeixinException + */ + public JsonResult setAgent(String authCorpid, AgentSetter agentSet) + throws WeixinException { + String suite_set_agent_uri = getRequestUri("suite_set_agent_uri"); + JSONObject obj = new JSONObject(); + obj.put("suite_id", suiteId); + obj.put("auth_corpid", authCorpid); + obj.put("permanent_code", suitePerCodeHolder.lookup(suiteId)); + obj.put("agent", agentSet); + WeixinResponse response = weixinClient.post( + String.format(suite_set_agent_uri, + suiteTokenHolder.getAccessToken()), + JSON.toJSONString(obj, AgentApi.typeFilter)); + return response.getAsJsonResult(); + } } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties index 1973f049..43fc813d 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties @@ -89,4 +89,10 @@ suite_oauth_uri=https://qy.weixin.qq.com/cgi-bin/loginpage?suite_id=%s&pre_auth_ # \u5e94\u7528\u5957\u4ef6\u8bbe\u7f6e\u6388\u6743\u914d\u7f6e suite_set_session_uri={api_base_url}/service/set_session_info?suite_access_token=%s # \u83b7\u53d6\u4f01\u4e1a\u53f7\u7684\u6c38\u4e45\u6388\u6743\u7801 -suite_get_permanent_uri={api_base_url}/service/get_permanent_code?suite_access_token=%s \ No newline at end of file +suite_get_permanent_uri={api_base_url}/service/get_permanent_code?suite_access_token=%s +# \u83b7\u53d6\u4f01\u4e1a\u53f7\u7684\u6388\u6743\u4fe1\u606f +suite_get_authinfo_uri={api_base_url}/service/get_auth_info?suite_access_token=%s +# \u83b7\u53d6\u4f01\u4e1a\u53f7\u5e94\u7528 +suite_get_agent_uri={api_base_url}/service/get_agent?suite_access_token=%s +# \u8bbe\u7f6e\u4f01\u4e1a\u53f7\u5e94\u7528 +suite_set_agent_uri={api_base_url}/service/set_agent?suite_access_token=%s \ No newline at end of file diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/Corpinfo.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/Corpinfo.java index 9306b319..b1b1a2d1 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/Corpinfo.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/Corpinfo.java @@ -1,5 +1,7 @@ package com.foxinmy.weixin4j.qy.model; +import java.io.Serializable; + import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.qy.type.CorpType; @@ -12,13 +14,28 @@ import com.foxinmy.weixin4j.qy.type.CorpType; * @since JDK 1.7 * @see */ -public class Corpinfo extends AgentOverview { +public class Corpinfo implements Serializable { private static final long serialVersionUID = 1251033124778972419L; /** * 授权方企业号id */ private String corpid; + /** + * 授权方企业号名称 + */ + @JSONField(name = "corp_name") + private String corpName; + /** + * 企业方形头像 + */ + @JSONField(name = "corp_square_logo_url") + private String squareLogoUrl; + /** + * 企业圆形头像 + */ + @JSONField(name = "corp_round_logo_url") + private String roundLogoUrl; /** * 授权方企业号类型 */ @@ -28,17 +45,17 @@ public class Corpinfo extends AgentOverview { * 授权方企业号用户规模 */ @JSONField(name = "corp_user_max") - private int corpUserMax; + private int userMax; /** * 授权方企业号应用规模 */ @JSONField(name = "corp_agent_max") - private int corpAgentMax; + private int agentMax; /** * 授权方企业号二维码 */ @JSONField(name = "corp_wxqrcode") - private String corpWxqrcode; + private String wxqrcode; public String getCorpid() { return corpid; @@ -56,35 +73,60 @@ public class Corpinfo extends AgentOverview { this.corpType = corpType; } - public int getCorpUserMax() { - return corpUserMax; + public String getCorpName() { + return corpName; } - public void setCorpUserMax(int corpUserMax) { - this.corpUserMax = corpUserMax; + public void setCorpName(String corpName) { + this.corpName = corpName; } - public int getCorpAgentMax() { - return corpAgentMax; + public String getSquareLogoUrl() { + return squareLogoUrl; } - public void setCorpAgentMax(int corpAgentMax) { - this.corpAgentMax = corpAgentMax; + public void setSquareLogoUrl(String squareLogoUrl) { + this.squareLogoUrl = squareLogoUrl; } - public String getCorpWxqrcode() { - return corpWxqrcode; + public String getRoundLogoUrl() { + return roundLogoUrl; } - public void setCorpWxqrcode(String corpWxqrcode) { - this.corpWxqrcode = corpWxqrcode; + public void setRoundLogoUrl(String roundLogoUrl) { + this.roundLogoUrl = roundLogoUrl; + } + + public int getUserMax() { + return userMax; + } + + public void setUserMax(int userMax) { + this.userMax = userMax; + } + + public int getAgentMax() { + return agentMax; + } + + public void setAgentMax(int agentMax) { + this.agentMax = agentMax; + } + + public String getWxqrcode() { + return wxqrcode; + } + + public void setWxqrcode(String wxqrcode) { + this.wxqrcode = wxqrcode; } @Override public String toString() { - return "Corpinfo [corpid=" + corpid + ", corpType=" + corpType - + ", corpUserMax=" + corpUserMax + ", corpAgentMax=" - + corpAgentMax + ", corpWxqrcode=" + corpWxqrcode + ", " - + super.toString() + "]"; + return "Corpinfo [corpid=" + corpid + ", corpName=" + corpName + + ", squareLogoUrl=" + squareLogoUrl + ", roundLogoUrl=" + + roundLogoUrl + ", corpType=" + corpType + ", userMax=" + + userMax + ", agentMax=" + agentMax + ", wxqrcode=" + wxqrcode + + "]"; } } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/OUserInfo.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/OUserInfo.java index f9b3b37f..ae52c97e 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/OUserInfo.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/OUserInfo.java @@ -3,12 +3,11 @@ package com.foxinmy.weixin4j.qy.model; import java.io.Serializable; import java.util.List; -import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.qy.type.AgentAuthType; /** - * oauth授权登陆信息 + * 企业号oauth授权登陆信息&第三方应用授权信息 * * @className OUserInfo * @author jy @@ -48,7 +47,7 @@ public class OUserInfo implements Serializable { * 该管理员拥有的通讯录权限 */ @JSONField(name = "auth_info") - private JSONObject authInfo; + private AuthInfo authInfo; public boolean isSysAdmin() { return isSysAdmin; @@ -90,11 +89,11 @@ public class OUserInfo implements Serializable { this.agentInfo = agentInfo; } - public JSONObject getAuthInfo() { + public AuthInfo getAuthInfo() { return authInfo; } - public void setAuthInfo(JSONObject authInfo) { + public void setAuthInfo(AuthInfo authInfo) { this.authInfo = authInfo; } @@ -106,24 +105,78 @@ public class OUserInfo implements Serializable { + authInfo + "]"; } - public static class AgentItem { + /** + * 授权信息 + * + * @className AuthInfo + * @author jy + * @date 2015年6月22日 + * @since JDK 1.7 + * @see + */ + public static class AuthInfo implements Serializable { + + private static final long serialVersionUID = -4290240764958942370L; /** - * 应用id + * 授权的应用信息 */ - private int agentid; + @JSONField(name = "agent") + private List agentItems; + /** + * 授权的通讯录部门 + */ + @JSONField(name = "department") + private List departmentItems; + + public List getAgentItems() { + return agentItems; + } + + public void setAgentItems(List agentItems) { + this.agentItems = agentItems; + } + + public List getDepartmentItems() { + return departmentItems; + } + + public void setDepartmentItems(List departmentItems) { + this.departmentItems = departmentItems; + } + + @Override + public String toString() { + return "AuthInfo [agentItems=" + agentItems + ", departmentItems=" + + departmentItems + "]"; + } + } + + /** + * 授权的应用信息 + * + * @className AgentItem + * @author jy + * @date 2015年6月22日 + * @since JDK 1.7 + * @see + */ + public static class AgentItem extends AgentOverview { + + private static final long serialVersionUID = -1188968391623633559L; /** * 管理员对应用的权限 */ @JSONField(name = "auth_type") private AgentAuthType authType; - - public int getAgentid() { - return agentid; - } - - public void setAgentid(int agentid) { - this.agentid = agentid; - } + /** + * 服务商套件中的对应应用id + */ + private String appid; + /** + * 授权方应用敏感权限组,目前仅有get_location,表示是否有权限设置应用获取地理位置的开关 + */ + @JSONField(name = "api_group") + private List apiGroup; public AgentAuthType getAuthType() { return authType; @@ -138,10 +191,59 @@ public class OUserInfo implements Serializable { this.authType = null; } + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public List getApiGroup() { + return apiGroup; + } + + public void setApiGroup(List apiGroup) { + this.apiGroup = apiGroup; + } + @Override public String toString() { - return "AgentItem [agentid=" + agentid + ", authType=" + authType - + "]"; + return "AgentItem [authType=" + authType + ", appid=" + appid + + ", apiGroup=" + apiGroup + ", " + super.toString() + "]"; + } + } + + /** + * 授权的通讯录部门 + * + * @className DepartmentItem + * @author jy + * @date 2015年6月22日 + * @since JDK 1.7 + * @see + */ + public static class DepartmentItem extends Party { + + private static final long serialVersionUID = 556556672204642407L; + + /** + * 是否具有该部门的写权限 + */ + private boolean writable; + + public boolean isWritable() { + return writable; + } + + public void setWritable(boolean writable) { + this.writable = writable; + } + + @Override + public String toString() { + return "DepartmentItem [writable=" + writable + ", " + + super.toString() + "]"; } } } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/FileTicketProcessor.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/FileTicketProcessor.java deleted file mode 100644 index b4bcf9e9..00000000 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/FileTicketProcessor.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.foxinmy.weixin4j.qy.suite; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; - -import com.foxinmy.weixin4j.exception.WeixinException; -import com.foxinmy.weixin4j.util.ConfigUtil; -import com.foxinmy.weixin4j.xml.XmlStream; - -/** - * 用file存储ticket - * - * @className FileTicketProcessor - * @author jy - * @date 2015年6月21日 - * @since JDK 1.7 - * @see - */ -public class FileTicketProcessor implements SuiteTicketProcessor { - - private final String ticketPath; - - public FileTicketProcessor() { - this.ticketPath = ConfigUtil.getValue("ticket_path"); - } - - public FileTicketProcessor(String ticketPath) { - this.ticketPath = ticketPath; - } - - @Override - public void write(SuiteTicketMessage suiteTicket) throws WeixinException { - try { - XmlStream - .toXML(suiteTicket, - new FileOutputStream(new File(String.format( - "%s/%s.xml", ticketPath, - getCacheKey(suiteTicket.getSuiteId()))))); - } catch (IOException e) { - throw new WeixinException(e.getMessage()); - } - } - - private String getCacheKey(String suiteId) { - return String.format("qy_suite_ticket_%s", suiteId); - } - - @Override - public SuiteTicketMessage read(String suiteId) throws WeixinException { - File ticket_file = new File(String.format("%s/%s.xml", ticketPath, - getCacheKey(suiteId))); - try { - return XmlStream.fromXML(new FileInputStream(ticket_file), - SuiteTicketMessage.class); - } catch (IOException e) { - throw new WeixinException(e.getMessage()); - } - } -} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuitePerCodeHolder.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuitePerCodeHolder.java new file mode 100644 index 00000000..6d5b486b --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuitePerCodeHolder.java @@ -0,0 +1,58 @@ +package com.foxinmy.weixin4j.qy.suite; + +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.token.TokenStorager; + +/** + * 应用套件永久授权码的存取 + * + * @className SuitePerCodeHolder + * @author jy + * @date 2015年6月22日 + * @since JDK 1.7 + * @see + */ +public class SuitePerCodeHolder { + + public final TokenStorager tokenStorager; + + public SuitePerCodeHolder(TokenStorager tokenStorager) { + this.tokenStorager = tokenStorager; + } + + /** + * 缓存永久授权码 + * + * @param suiteId + * @param permanentCode + * @throws WeixinException + */ + public void caching(String suiteId, String permanentCode) + throws WeixinException { + Token token = new Token(permanentCode); + token.setExpiresIn(-1); + tokenStorager.caching(getCacheKey(suiteId), token); + } + + /** + * 获取永久授权码的key + * + * @param suiteId + * @return + */ + private String getCacheKey(String suiteId) { + return String.format("qy_suite_percode_%s", suiteId); + } + + /** + * 查找永久二维码 + * + * @param suiteId + * @return + * @throws WeixinException + */ + public String lookup(String suiteId) throws WeixinException { + return tokenStorager.lookup(getCacheKey(suiteId)).getAccessToken(); + } +} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketHolder.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketHolder.java new file mode 100644 index 00000000..334e40cb --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketHolder.java @@ -0,0 +1,56 @@ +package com.foxinmy.weixin4j.qy.suite; + +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.token.TokenStorager; + +/** + * 应用套件ticket的存取 + * + * @className SuiteTicketHolder + * @author jy + * @date 2015年6月22日 + * @since JDK 1.7 + * @see + */ +public class SuiteTicketHolder { + + public final TokenStorager tokenStorager; + + public SuiteTicketHolder(TokenStorager tokenStorager) { + this.tokenStorager = tokenStorager; + } + + /** + * 查找ticket + * + * @param suiteId + * @return + * @throws WeixinException + */ + public String lookup(String suiteId) throws WeixinException { + return tokenStorager.lookup(getCacheKey(suiteId)).getAccessToken(); + } + + /** + * 获取ticket的key + * + * @param suiteId + * @return + */ + private String getCacheKey(String suiteId) { + return String.format("qy_suite_ticket_%s", suiteId); + } + + /** + * 缓存ticket + * + * @param suiteTicket + * @throws WeixinException + */ + public void caching(SuiteTicketMessage suiteTicket) throws WeixinException { + Token token = new Token(suiteTicket.getSuiteTicket()); + token.setExpiresIn(-1); + tokenStorager.caching(getCacheKey(suiteTicket.getSuiteId()), token); + } +} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketProcessor.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketProcessor.java deleted file mode 100644 index 538f7413..00000000 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.foxinmy.weixin4j.qy.suite; - -import com.foxinmy.weixin4j.exception.WeixinException; - -/** - * 对套件ticket的处理:写入与读取 - * - * @className SuiteTicketProcessor - * @author jy - * @date 2015年6月18日 - * @since JDK 1.7 - * @see - */ -public interface SuiteTicketProcessor { - /** - * 写入微信推送过来的suite_ticket - * - * @param suiteTicket - * @throws WeixinException - */ - public void write(SuiteTicketMessage suiteTicket) throws WeixinException; - - /** - * 读取最新的suite_ticket - * - * @param suiteId - * @return 最新的ticket - * @throws WeixinException - */ - public SuiteTicketMessage read(String suiteId) throws WeixinException; -} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuiteTokenCreator.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuiteTokenCreator.java index 2356df0f..67720c9e 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuiteTokenCreator.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuiteTokenCreator.java @@ -24,7 +24,7 @@ public class WeixinSuiteTokenCreator implements TokenCreator { private final WeixinHttpClient httpClient; private final String suiteId; private final String suiteSecret; - private final SuiteTicketProcessor ticketProcessor; + private final SuiteTicketHolder ticketHolder; /** * @@ -32,14 +32,14 @@ public class WeixinSuiteTokenCreator implements TokenCreator { * 套件ID * @param suiteSecret * 套件secret - * @param ticketReader - * 套件ticket读取器 + * @param stringStorager + * 套件ticket存取器 */ public WeixinSuiteTokenCreator(String suiteId, String suiteSecret, - SuiteTicketProcessor ticketProcessor) { + SuiteTicketHolder ticketHolder) { this.suiteId = suiteId; this.suiteSecret = suiteSecret; - this.ticketProcessor = ticketProcessor; + this.ticketHolder = ticketHolder; this.httpClient = new WeixinHttpClient(); } @@ -53,7 +53,7 @@ public class WeixinSuiteTokenCreator implements TokenCreator { JSONObject obj = new JSONObject(); obj.put("suite_id", suiteId); obj.put("suite_secret", suiteSecret); - obj.put("suite_ticket", ticketProcessor.read(suiteId).getSuiteTicket()); + obj.put("suite_ticket", ticketHolder.lookup(suiteId)); WeixinResponse response = httpClient.post(URLConsts.SUITE_TOKEN_URL, obj.toJSONString()); obj = response.getAsJson(); diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinTokenSuiteCreator.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinTokenSuiteCreator.java new file mode 100644 index 00000000..5a3f86f5 --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinTokenSuiteCreator.java @@ -0,0 +1,65 @@ +package com.foxinmy.weixin4j.qy.suite; + +import com.alibaba.fastjson.JSONObject; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.WeixinHttpClient; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.qy.type.URLConsts; +import com.foxinmy.weixin4j.token.TokenCreator; + +/** + * 微信企业号token创建(永久授权码) + * + * @className WeixinTokenSuiteCreator + * @author jy + * @date 2015年6月17日 + * @since JDK 1.7 + * @see 获取企业号access_token + * @see com.foxinmy.weixin4j.model.Token + */ +public class WeixinTokenSuiteCreator implements TokenCreator { + + private final WeixinHttpClient httpClient; + private final String suiteId; + private final String authCorpid; + private final SuitePerCodeHolder perCodeHolder; + + /** + * + * @param suiteId + * 应用套件ID + * @param suiteSecret + * 授权方corpid + * @param perCodeHolder + * 永久授权码 + */ + public WeixinTokenSuiteCreator(String suiteId, String authCorpid, + SuitePerCodeHolder perCodeHolder) { + this.suiteId = suiteId; + this.authCorpid = authCorpid; + this.perCodeHolder = perCodeHolder; + this.httpClient = new WeixinHttpClient(); + } + + @Override + public String getCacheKey() { + return String.format("qy_token_suite_%s", suiteId); + } + + @Override + public Token createToken() throws WeixinException { + JSONObject obj = new JSONObject(); + obj.put("suite_id", suiteId); + obj.put("auth_corpid", authCorpid); + obj.put("permanent_code", perCodeHolder.lookup(suiteId)); + WeixinResponse response = httpClient.post(URLConsts.TOKEN_SUITE_URL, + obj.toJSONString()); + obj = response.getAsJson(); + Token token = new Token(obj.getString("access_token")); + token.setExpiresIn(obj.getIntValue("expires_in")); + token.setTime(System.currentTimeMillis()); + return token; + } +} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/type/URLConsts.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/type/URLConsts.java index 60c3d277..28061638 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/type/URLConsts.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/type/URLConsts.java @@ -40,4 +40,10 @@ public final class URLConsts { */ public static final String SUITE_PRE_CODE_URL = BASE_URL + "/service/get_pre_auth_code?suite_access_token=%s"; + + /** + * 企业号第三方应用套件获取企业号access_token的url + */ + public static final String TOKEN_SUITE_URL = BASE_URL + + "/service/get_corp_token?suite_access_token=%s"; }