weixin4j-qy:新增第三方应用多个API接口

This commit is contained in:
jinyu 2015-06-22 17:12:40 +08:00
parent dd1fcaa598
commit 66bc364b33
19 changed files with 641 additions and 222 deletions

View File

@ -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<T> {
/**
* 查找缓存中的对象
*
* @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;
}

View File

@ -20,27 +20,29 @@ import com.foxinmy.weixin4j.xml.XmlStream;
*/ */
public class FileTokenStorager implements TokenStorager { public class FileTokenStorager implements TokenStorager {
private final String tokenPath; private final String cachePath;
public FileTokenStorager() { public FileTokenStorager() {
this(ConfigUtil.getValue("token_path")); this(ConfigUtil.getValue("token_path"));
} }
public FileTokenStorager(String tokenPath) { public FileTokenStorager(String cachePath) {
this.tokenPath = tokenPath; this.cachePath = cachePath;
} }
@Override @Override
public Token lookupToken(String cacheKey) throws WeixinException { public Token lookup(String cacheKey) throws WeixinException {
File token_file = new File(String.format("%s/%s.xml", tokenPath, File token_file = new File(String.format("%s/%s.xml", cachePath,
cacheKey)); cacheKey));
try { try {
if (token_file.exists()) { if (token_file.exists()) {
Token token = XmlStream.fromXML( Token token = XmlStream.fromXML(
new FileInputStream(token_file), Token.class); new FileInputStream(token_file), Token.class);
long expire_time = token.getTime() if (token.getTime() < 0) {
+ (token.getExpiresIn() * 1000) - 2; return token;
if (expire_time > System.currentTimeMillis()) { }
if ((token.getTime() + (token.getExpiresIn() * 1000l) - 2) > System
.currentTimeMillis()) {
return token; return token;
} }
} }
@ -51,13 +53,12 @@ public class FileTokenStorager implements TokenStorager {
} }
@Override @Override
public void cachingToken(String cacheKey, Token token) public void caching(String cacheKey, Token token) throws WeixinException {
throws WeixinException {
try { try {
XmlStream.toXML( XmlStream.toXML(
token, token,
new FileOutputStream(new File(String.format("%s/%s.xml", new FileOutputStream(new File(String.format("%s/%s.xml",
tokenPath, cacheKey)))); cachePath, cacheKey))));
} catch (IOException e) { } catch (IOException e) {
throw new WeixinException(e.getMessage()); throw new WeixinException(e.getMessage());
} }

View File

@ -44,10 +44,10 @@ public final class TokenHolder {
*/ */
public Token getToken() throws WeixinException { public Token getToken() throws WeixinException {
String cacheKey = tokenCreator.getCacheKey(); String cacheKey = tokenCreator.getCacheKey();
Token token = tokenStorager.lookupToken(cacheKey); Token token = tokenStorager.lookup(cacheKey);
if (token == null) { if (token == null) {
token = tokenCreator.createToken(); token = tokenCreator.createToken();
tokenStorager.cachingToken(cacheKey, token); tokenStorager.caching(cacheKey, token);
} }
return token; return token;
} }

View File

@ -1,6 +1,5 @@
package com.foxinmy.weixin4j.token; package com.foxinmy.weixin4j.token;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token; 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.FileTokenStorager
* @see com.foxinmy.weixin4j.token.RedisTokenStorager * @see com.foxinmy.weixin4j.token.RedisTokenStorager
*/ */
public interface TokenStorager { public interface TokenStorager extends CacheStorager<Token> {
/**
* 查找缓存的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;
} }

View File

@ -24,6 +24,8 @@ weixin4j-qy
* BatchApi `批量操作API` * BatchApi `批量操作API`
* OauthApi `oauth授权登陆API` * OauthApi `oauth授权登陆API`
* SuiteApi `第三方应用API`
如何使用 如何使用
-------- --------

View File

@ -65,7 +65,7 @@ public class AgentApi extends QyApi {
* 设置企业应用的选项设置信息地理位置上报等 * 设置企业应用的选项设置信息地理位置上报等
* *
* @param agentSet * @param agentSet
* 设置参数 * 设置信息
* @see com.foxinmy.weixin4j.qy.model.AgentSetter * @see com.foxinmy.weixin4j.qy.model.AgentSetter
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E4%BC%81%E4%B8%9A%E5%8F%B7%E5%BA%94%E7%94%A8">设置企业号信息</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E4%BC%81%E4%B8%9A%E5%8F%B7%E5%BA%94%E7%94%A8">设置企业号信息</a>
@ -81,7 +81,7 @@ public class AgentApi extends QyApi {
return response.getAsJsonResult(); return response.getAsJsonResult();
} }
private static ValueFilter typeFilter; public static ValueFilter typeFilter;
static { static {
typeFilter = new ValueFilter() { typeFilter = new ValueFilter() {
@Override @Override

View File

@ -4,11 +4,9 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.model.Consts; import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.qy.model.Corpinfo;
import com.foxinmy.weixin4j.qy.model.OUserInfo; import com.foxinmy.weixin4j.qy.model.OUserInfo;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
@ -83,26 +81,7 @@ public class OauthApi extends QyApi {
WeixinResponse response = weixinClient.post( WeixinResponse response = weixinClient.post(
String.format(oauth_logininfo_uri, providerToken), String.format(oauth_logininfo_uri, providerToken),
String.format("{\"auth_code\":\"%s\"}", authCode)); String.format("{\"auth_code\":\"%s\"}", authCode));
return JSON.parseObject(response.getAsString(), OUserInfo.class, 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());
}
}
}
});
} }
/** /**

View File

@ -5,8 +5,6 @@ import java.util.ResourceBundle;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.api.BaseApi; import com.foxinmy.weixin4j.api.BaseApi;
import com.foxinmy.weixin4j.qy.model.WeixinQyAccount; 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; import com.foxinmy.weixin4j.util.ConfigUtil;
/** /**
@ -26,17 +24,12 @@ public class QyApi extends BaseApi {
* 默认使用weixin4j.properties文件中的企业号信息 * 默认使用weixin4j.properties文件中的企业号信息
*/ */
public final static WeixinQyAccount DEFAULT_WEIXIN_ACCOUNT; public final static WeixinQyAccount DEFAULT_WEIXIN_ACCOUNT;
/**
* 默认使用File的方法读取套件ticket
*/
public final static SuiteTicketProcessor DEFAULT_TICKET_PROCESSOR;
static { static {
WEIXIN_BUNDLE = ResourceBundle WEIXIN_BUNDLE = ResourceBundle
.getBundle("com/foxinmy/weixin4j/qy/api/weixin"); .getBundle("com/foxinmy/weixin4j/qy/api/weixin");
DEFAULT_WEIXIN_ACCOUNT = JSON.parseObject( DEFAULT_WEIXIN_ACCOUNT = JSON.parseObject(
ConfigUtil.getValue("account"), WeixinQyAccount.class); ConfigUtil.getValue("account"), WeixinQyAccount.class);
DEFAULT_TICKET_PROCESSOR = new FileTicketProcessor();
} }
@Override @Override

View File

@ -1,12 +1,23 @@
package com.foxinmy.weixin4j.qy.api; package com.foxinmy.weixin4j.qy.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.JsonResult;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse; 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.WeixinSuitePreCodeCreator;
import com.foxinmy.weixin4j.qy.suite.WeixinSuiteTokenCreator; 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.TokenHolder;
import com.foxinmy.weixin4j.token.TokenStorager; 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">第三方应用授权</a> * 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">第三方应用授权</a>
*/ */
public class SuiteApi extends QyApi { public class SuiteApi extends QyApi {
/** /**
* 应用套件token * 应用套件token
*/ */
private final TokenHolder suiteTokenHolder; 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 { public SuiteApi() throws WeixinException {
this(DEFAULT_WEIXIN_ACCOUNT.getSuiteId(), DEFAULT_WEIXIN_ACCOUNT 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 { public SuiteApi(String suiteId, String suiteSecret) throws WeixinException {
this(suiteId, suiteSecret, DEFAULT_TICKET_PROCESSOR, this(suiteId, suiteSecret, DEFAULT_TOKEN_STORAGER);
DEFAULT_TOKEN_STORAGER);
} }
/** /**
@ -44,19 +72,23 @@ public class SuiteApi extends QyApi {
* 应用ID * 应用ID
* @param suiteSecret * @param suiteSecret
* 应用secret * 应用secret
* @param ticketReader * @param ticketStorager
* 应用ticket读取器 * 应用ticket存储器(用于读取)
* @param tokenStorager * @param tokenStorager
* 应用token存储器 * 应用token存储器
* @throws WeixinException * @throws WeixinException
*/ */
public SuiteApi(String suiteId, String suiteSecret, public SuiteApi(String suiteId, String suiteSecret,
SuiteTicketProcessor ticketReader, TokenStorager tokenStorager) TokenStorager tokenStorager) throws WeixinException {
throws WeixinException { this.suiteTicketHolder = new SuiteTicketHolder(tokenStorager);
this.suiteTokenHolder = new TokenHolder(new WeixinSuiteTokenCreator( this.suiteTokenHolder = new TokenHolder(new WeixinSuiteTokenCreator(
suiteId, suiteSecret, ticketReader), tokenStorager); suiteId, suiteSecret, suiteTicketHolder), tokenStorager);
this.suiteTicketHolder = new TokenHolder(new WeixinSuitePreCodeCreator( this.suitePreCodeHolder = new TokenHolder(
suiteTokenHolder, suiteId), tokenStorager); 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 * @return
*/ */
public TokenHolder getTicketHolder() { public SuiteTicketHolder getTicketHolder() {
return this.suiteTicketHolder; 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如123 * 允许进行授权的应用id如123
* @return 处理结果 * @return 处理结果
* @throws WeixinException * @throws WeixinException
* <a href= * @see <a 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%A5%E5%8F%A3%E8%AF%B4%E6%98%8E#.E8.AE.BE.E7.BD.AE.E6.8E.88.E6.9D.83.E9.85.8D.E7.BD.AE" * "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%A5%E5%8F%A3%E8%AF%B4%E6%98%8E#.E8.AE.BE.E7.BD.AE.E6.8E.88.E6.9D.83.E9.85.8D.E7.BD.AE"
* >设置套件授权配置</a> * >设置套件授权配置</a>
*/ */
public JsonResult setSuiteSession(int... appids) throws WeixinException { public JsonResult setSuiteSession(int... appids) throws WeixinException {
String suite_set_session_uri = getRequestUri("suite_set_session_uri"); String suite_set_session_uri = getRequestUri("suite_set_session_uri");
JSONObject para = new JSONObject(); JSONObject para = new JSONObject();
para.put("pre_auth_code", suiteTicketHolder.getAccessToken()); para.put("pre_auth_code", suiteTicketHolder.lookup(suiteId));
para.put("session_info", appids); para.put("session_info", appids);
WeixinResponse response = weixinClient WeixinResponse response = weixinClient
.post(String.format(suite_set_session_uri, .post(String.format(suite_set_session_uri,
suiteTokenHolder.getAccessToken()), para.toJSONString()); suiteTokenHolder.getAccessToken()), para.toJSONString());
return response.getAsJsonResult(); return response.getAsJsonResult();
} }
/**
* 获取企业号的永久授权码
*
* @param authCode
* 临时授权码会在授权成功时附加在redirect_uri中跳转回应用提供商网站
* @return 授权得到的信息
* @throws WeixinException
* @see com.foxinmy.weixin4j.qy.model.OUserInfo
* @see <a 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%A5%E5%8F%A3%E8%AF%B4%E6%98%8E#.E8.8E.B7.E5.8F.96.E4.BC.81.E4.B8.9A.E5.8F.B7.E7.9A.84.E6.B0.B8.E4.B9.85.E6.8E.88.E6.9D.83.E7.A0.81"
* >获取企业号的永久授权码</a>
*/
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 <a
* 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%A5%E5%8F%A3%E8%AF%B4%E6%98%8E#.E8.8E.B7.E5.8F.96.E4.BC.81.E4.B8.9A.E5.8F.B7.E7.9A.84.E6.8E.88.E6.9D.83.E4.BF.A1.E6.81.AF">获取企业号的授权信息</a>
*/
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<OUserInfo>() {
});
}
/**
* 获取企业号应用
*
* @param authCorpid
* 授权方corpid
* @param agentid
* 授权方应用id
* @return 应用信息
* @see com.foxinmy.weixin4j.qy.model.AgentInfo
* @see <a
* 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%A5%E5%8F%A3%E8%AF%B4%E6%98%8E#.E8.8E.B7.E5.8F.96.E4.BC.81.E4.B8.9A.E5.8F.B7.E5.BA.94.E7.94.A8">获取企业号应用</a>
* @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 <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E4%BC%81%E4%B8%9A%E5%8F%B7%E5%BA%94%E7%94%A8">设置企业号信息</a>
* @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();
}
} }

View File

@ -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 # \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 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 # \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 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

View File

@ -1,5 +1,7 @@
package com.foxinmy.weixin4j.qy.model; package com.foxinmy.weixin4j.qy.model;
import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.qy.type.CorpType; import com.foxinmy.weixin4j.qy.type.CorpType;
@ -12,13 +14,28 @@ import com.foxinmy.weixin4j.qy.type.CorpType;
* @since JDK 1.7 * @since JDK 1.7
* @see * @see
*/ */
public class Corpinfo extends AgentOverview { public class Corpinfo implements Serializable {
private static final long serialVersionUID = 1251033124778972419L; private static final long serialVersionUID = 1251033124778972419L;
/** /**
* 授权方企业号id * 授权方企业号id
*/ */
private String corpid; 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") @JSONField(name = "corp_user_max")
private int corpUserMax; private int userMax;
/** /**
* 授权方企业号应用规模 * 授权方企业号应用规模
*/ */
@JSONField(name = "corp_agent_max") @JSONField(name = "corp_agent_max")
private int corpAgentMax; private int agentMax;
/** /**
* 授权方企业号二维码 * 授权方企业号二维码
*/ */
@JSONField(name = "corp_wxqrcode") @JSONField(name = "corp_wxqrcode")
private String corpWxqrcode; private String wxqrcode;
public String getCorpid() { public String getCorpid() {
return corpid; return corpid;
@ -56,35 +73,60 @@ public class Corpinfo extends AgentOverview {
this.corpType = corpType; this.corpType = corpType;
} }
public int getCorpUserMax() { public String getCorpName() {
return corpUserMax; return corpName;
} }
public void setCorpUserMax(int corpUserMax) { public void setCorpName(String corpName) {
this.corpUserMax = corpUserMax; this.corpName = corpName;
} }
public int getCorpAgentMax() { public String getSquareLogoUrl() {
return corpAgentMax; return squareLogoUrl;
} }
public void setCorpAgentMax(int corpAgentMax) { public void setSquareLogoUrl(String squareLogoUrl) {
this.corpAgentMax = corpAgentMax; this.squareLogoUrl = squareLogoUrl;
} }
public String getCorpWxqrcode() { public String getRoundLogoUrl() {
return corpWxqrcode; return roundLogoUrl;
} }
public void setCorpWxqrcode(String corpWxqrcode) { public void setRoundLogoUrl(String roundLogoUrl) {
this.corpWxqrcode = corpWxqrcode; 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 @Override
public String toString() { public String toString() {
return "Corpinfo [corpid=" + corpid + ", corpType=" + corpType return "Corpinfo [corpid=" + corpid + ", corpName=" + corpName
+ ", corpUserMax=" + corpUserMax + ", corpAgentMax=" + ", squareLogoUrl=" + squareLogoUrl + ", roundLogoUrl="
+ corpAgentMax + ", corpWxqrcode=" + corpWxqrcode + ", " + roundLogoUrl + ", corpType=" + corpType + ", userMax="
+ super.toString() + "]"; + userMax + ", agentMax=" + agentMax + ", wxqrcode=" + wxqrcode
+ "]";
} }
} }

View File

@ -3,12 +3,11 @@ package com.foxinmy.weixin4j.qy.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.qy.type.AgentAuthType; import com.foxinmy.weixin4j.qy.type.AgentAuthType;
/** /**
* oauth授权登陆信息 * 企业号oauth授权登陆信息&第三方应用授权信息
* *
* @className OUserInfo * @className OUserInfo
* @author jy * @author jy
@ -48,7 +47,7 @@ public class OUserInfo implements Serializable {
* 该管理员拥有的通讯录权限 * 该管理员拥有的通讯录权限
*/ */
@JSONField(name = "auth_info") @JSONField(name = "auth_info")
private JSONObject authInfo; private AuthInfo authInfo;
public boolean isSysAdmin() { public boolean isSysAdmin() {
return isSysAdmin; return isSysAdmin;
@ -90,11 +89,11 @@ public class OUserInfo implements Serializable {
this.agentInfo = agentInfo; this.agentInfo = agentInfo;
} }
public JSONObject getAuthInfo() { public AuthInfo getAuthInfo() {
return authInfo; return authInfo;
} }
public void setAuthInfo(JSONObject authInfo) { public void setAuthInfo(AuthInfo authInfo) {
this.authInfo = authInfo; this.authInfo = authInfo;
} }
@ -106,24 +105,78 @@ public class OUserInfo implements Serializable {
+ authInfo + "]"; + 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<AgentItem> agentItems;
/**
* 授权的通讯录部门
*/
@JSONField(name = "department")
private List<DepartmentItem> departmentItems;
public List<AgentItem> getAgentItems() {
return agentItems;
}
public void setAgentItems(List<AgentItem> agentItems) {
this.agentItems = agentItems;
}
public List<DepartmentItem> getDepartmentItems() {
return departmentItems;
}
public void setDepartmentItems(List<DepartmentItem> 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") @JSONField(name = "auth_type")
private AgentAuthType authType; private AgentAuthType authType;
/**
public int getAgentid() { * 服务商套件中的对应应用id
return agentid; */
} private String appid;
/**
public void setAgentid(int agentid) { * 授权方应用敏感权限组目前仅有get_location表示是否有权限设置应用获取地理位置的开关
this.agentid = agentid; */
} @JSONField(name = "api_group")
private List<String> apiGroup;
public AgentAuthType getAuthType() { public AgentAuthType getAuthType() {
return authType; return authType;
@ -138,10 +191,59 @@ public class OUserInfo implements Serializable {
this.authType = null; this.authType = null;
} }
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public List<String> getApiGroup() {
return apiGroup;
}
public void setApiGroup(List<String> apiGroup) {
this.apiGroup = apiGroup;
}
@Override @Override
public String toString() { 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() + "]";
} }
} }
} }

View File

@ -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());
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -24,7 +24,7 @@ public class WeixinSuiteTokenCreator implements TokenCreator {
private final WeixinHttpClient httpClient; private final WeixinHttpClient httpClient;
private final String suiteId; private final String suiteId;
private final String suiteSecret; private final String suiteSecret;
private final SuiteTicketProcessor ticketProcessor; private final SuiteTicketHolder ticketHolder;
/** /**
* *
@ -32,14 +32,14 @@ public class WeixinSuiteTokenCreator implements TokenCreator {
* 套件ID * 套件ID
* @param suiteSecret * @param suiteSecret
* 套件secret * 套件secret
* @param ticketReader * @param stringStorager
* 套件ticket取器 * 套件ticket取器
*/ */
public WeixinSuiteTokenCreator(String suiteId, String suiteSecret, public WeixinSuiteTokenCreator(String suiteId, String suiteSecret,
SuiteTicketProcessor ticketProcessor) { SuiteTicketHolder ticketHolder) {
this.suiteId = suiteId; this.suiteId = suiteId;
this.suiteSecret = suiteSecret; this.suiteSecret = suiteSecret;
this.ticketProcessor = ticketProcessor; this.ticketHolder = ticketHolder;
this.httpClient = new WeixinHttpClient(); this.httpClient = new WeixinHttpClient();
} }
@ -53,7 +53,7 @@ public class WeixinSuiteTokenCreator implements TokenCreator {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("suite_id", suiteId); obj.put("suite_id", suiteId);
obj.put("suite_secret", suiteSecret); 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, WeixinResponse response = httpClient.post(URLConsts.SUITE_TOKEN_URL,
obj.toJSONString()); obj.toJSONString());
obj = response.getAsJson(); obj = response.getAsJson();

View File

@ -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 <a
* 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%A5%E5%8F%A3%E8%AF%B4%E6%98%8E#.E8.8E.B7.E5.8F.96.E4.BC.81.E4.B8.9A.E5.8F.B7access_token">获取企业号access_token</a>
* @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;
}
}

View File

@ -40,4 +40,10 @@ public final class URLConsts {
*/ */
public static final String SUITE_PRE_CODE_URL = BASE_URL public static final String SUITE_PRE_CODE_URL = BASE_URL
+ "/service/get_pre_auth_code?suite_access_token=%s"; + "/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";
} }