主要新增了企业号的第三方应用API

This commit is contained in:
jinyu
2015-06-21 22:20:19 +08:00
parent 692a2b8129
commit dd1fcaa598
44 changed files with 850 additions and 250 deletions
@@ -8,7 +8,6 @@ import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.JsonResult;
import com.foxinmy.weixin4j.model.Button;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.qy.api.AgentApi;
import com.foxinmy.weixin4j.qy.api.BatchApi;
import com.foxinmy.weixin4j.qy.api.HelperApi;
@@ -16,6 +15,7 @@ import com.foxinmy.weixin4j.qy.api.MediaApi;
import com.foxinmy.weixin4j.qy.api.MenuApi;
import com.foxinmy.weixin4j.qy.api.NotifyApi;
import com.foxinmy.weixin4j.qy.api.PartyApi;
import com.foxinmy.weixin4j.qy.api.QyApi;
import com.foxinmy.weixin4j.qy.api.TagApi;
import com.foxinmy.weixin4j.qy.api.UserApi;
import com.foxinmy.weixin4j.qy.message.NotifyMessage;
@@ -31,11 +31,9 @@ import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.qy.token.WeixinTokenCreator;
import com.foxinmy.weixin4j.qy.type.InviteType;
import com.foxinmy.weixin4j.qy.type.UserStatus;
import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 微信企业号接口实现
@@ -47,6 +45,7 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
* @see <a href="http://qydev.weixin.qq.com/wiki/index.php">api文档</a>
*/
public class WeixinProxy {
private final MediaApi mediaApi;
private final MenuApi menuApi;
private final NotifyApi notifyApi;
@@ -57,20 +56,24 @@ public class WeixinProxy {
private final AgentApi agentApi;
private final BatchApi batchApi;
private final TokenHolder tokenHolder;
/**
* 默认使用文件方式保存token、使用weixin4j.properties配置的账号信息
*/
public WeixinProxy() {
this(new FileTokenStorager());
this(QyApi.DEFAULT_TOKEN_STORAGER);
}
/**
* 默认使用weixin4j.properties配置的账号信息
*
* @param tokenStorager token存储策略
* @param tokenStorager
* token存储策略
*/
public WeixinProxy(TokenStorager tokenStorager) {
this(tokenStorager, ConfigUtil.getWeixinAccount());
this(QyApi.DEFAULT_WEIXIN_ACCOUNT.getId(), QyApi.DEFAULT_WEIXIN_ACCOUNT
.getSecret(), tokenStorager);
}
/**
@@ -80,19 +83,22 @@ public class WeixinProxy {
* @param corpsecret
*/
public WeixinProxy(String corpid, String corpsecret) {
this(new FileTokenStorager(), new WeixinAccount(corpid, corpsecret));
this(corpid, corpsecret, QyApi.DEFAULT_TOKEN_STORAGER);
}
/**
*
* @param corpid
* 企业号ID
* @param corpsecret
* 企业号secret
* @param tokenStorager
* token存储策略
* @param weixinAccount
* 企业号账号信息
* 企业号token存储
*/
public WeixinProxy(TokenStorager tokenStorager, WeixinAccount weixinAccount) {
TokenHolder tokenHolder = new TokenHolder(new WeixinTokenCreator(
weixinAccount), tokenStorager);
public WeixinProxy(String corpid, String corpsecret,
TokenStorager tokenStorager) {
this.tokenHolder = new TokenHolder(new WeixinTokenCreator(corpid,
corpsecret), tokenStorager);
this.partyApi = new PartyApi(tokenHolder);
this.userApi = new UserApi(tokenHolder);
this.tagApi = new TagApi(tokenHolder);
@@ -104,6 +110,10 @@ public class WeixinProxy {
this.mediaApi = new MediaApi(tokenHolder);
}
public TokenHolder getTokenHolder() {
return this.tokenHolder;
}
/**
* 发送消息(需要管理员对应用有使用权限,对收件人touser、toparty、totag有查看权限,否则本次调用失败)
* <p>
@@ -10,11 +10,6 @@ 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.qy.model.WeixinQyAccount;
import com.foxinmy.weixin4j.qy.token.WeixinProviderTokenCreator;
import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
@@ -26,63 +21,26 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
* @since JDK 1.7
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E5%8F%B7%E7%99%BB%E5%BD%95%E6%8E%88%E6%9D%83">企业号登录授权说明</a>
* @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%88%E6%9D%83">第三方应用授权说明</a>
*/
public class OauthApi extends QyApi {
private final TokenHolder providerTokenHolder;
/**
* 默认使用文件方式保存token、使用weixin4j.properties配置的账号信息
*/
public OauthApi() {
this(new FileTokenStorager());
}
/**
* 默认使用weixin4j.properties配置的账号信息
* 企业号登陆授权
*
* @param tokenStorager
*/
public OauthApi(TokenStorager tokenStorager) {
this(tokenStorager, JSON.parseObject(ConfigUtil.getValue("account"),
WeixinQyAccount.class));
}
/**
*
* @param appid
* @param appsecret
*/
public OauthApi(String corpid, String providerSecret) {
providerTokenHolder = new TokenHolder(new WeixinProviderTokenCreator(
corpid, providerSecret), new FileTokenStorager());
}
/**
*
* @param tokenStorager
* token存储策略
* @param weixinAccount
* 公众号账号信息
*/
public OauthApi(TokenStorager tokenStorager, WeixinQyAccount qyAccount) {
providerTokenHolder = new TokenHolder(new WeixinProviderTokenCreator(
qyAccount), tokenStorager);
}
/**
* @see {@link com.foxinmy.weixin4j.qy.api.OauthApi#getAuthorizeURL(String, String,String)}
*
* @return 请求授权的URL
*/
public String getAuthorizeURL() {
String corpId = ConfigUtil.getWeixinAccount().getId();
String corpId = DEFAULT_WEIXIN_ACCOUNT.getId();
String redirectUri = ConfigUtil.getValue("redirect_uri");
return getAuthorizeURL(corpId, redirectUri, "state");
}
/**
* oauth授权
* 企业号登陆授权
*
* @param corpId
* 企业号(提供商)的corpid
@@ -91,6 +49,8 @@ public class OauthApi extends QyApi {
* @param state
* 用于保持请求和回调的状态,授权请求后原样带回给第三方
* @return 请求授权的URL
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E5%8F%B7%E7%99%BB%E5%BD%95%E6%8E%88%E6%9D%83">企业号登陆授权</a>
*/
public String getAuthorizeURL(String corpId, String redirectUri,
String state) {
@@ -107,6 +67,8 @@ public class OauthApi extends QyApi {
/**
* 获取企业号管理员登录信息
*
* @param providerToken
* 提供商的token
* @param authCode
* oauth2.0授权企业号管理员登录产生的code
* @return 登陆信息
@@ -115,12 +77,12 @@ public class OauthApi extends QyApi {
* @see com.foxinmy.weixin4j.qy.model.OUserInfo
* @throws WeixinException
*/
public OUserInfo getOUserInfo(String authCode) throws WeixinException {
public OUserInfo getOUserInfo(String providerToken, String authCode)
throws WeixinException {
String oauth_logininfo_uri = getRequestUri("oauth_logininfo_uri");
WeixinResponse response = weixinClient.post(String.format(
oauth_logininfo_uri, providerTokenHolder.getToken()
.getAccessToken()), String.format(
"{\"auth_code\":\"%s\"}", authCode));
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() {
@@ -142,4 +104,44 @@ public class OauthApi extends QyApi {
}
});
}
/**
* @see {@link com.foxinmy.weixin4j.qy.api.OauthApi#getSuiteAuthorizeURL(String,String, String,String)}
* @param preAuthCode
* 预授权码
* @return
*/
public String getSuiteAuthorizeURL(String preAuthCode) {
String suiteId = DEFAULT_WEIXIN_ACCOUNT.getSuiteId();
String redirectUri = ConfigUtil.getValue("suite_redirect_uri");
return getSuiteAuthorizeURL(suiteId, preAuthCode, redirectUri, "state");
}
/**
* 应用套件授权
*
* @param suiteId
* 套件ID
* @param preAuthCode
* 预授权码
* @param redirectUri
* 授权后重定向url
* @param state
* 回调后原样返回
* @return 请求授权的URL <a
* href=""http://qydev.weixin.qq.com/wiki/index.php?title
* =%E4%BC%81%E4%B8%9A%E5%8F%B7%E7%AE%A1%E7%90%86%E5%91%98%E6%
* 8E%88%E6%9D%83%E5%BA%94%E7%94%A8>应用套件授权</a>
*/
public String getSuiteAuthorizeURL(String suiteId, String preAuthCode,
String redirectUri, String state) {
String suite_oauth_uri = getRequestUri("suite_oauth_uri");
try {
return String.format(suite_oauth_uri, suiteId, preAuthCode,
URLEncoder.encode(redirectUri, Consts.UTF_8.name()), state);
} catch (UnsupportedEncodingException e) {
;
}
return "";
}
}
@@ -2,7 +2,12 @@ package com.foxinmy.weixin4j.qy.api;
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;
/**
* 微信企业号API
@@ -15,14 +20,27 @@ import com.foxinmy.weixin4j.api.BaseApi;
* @see <a href="http://qydev.weixin.qq.com/wiki/index.php">api文档</a>
*/
public class QyApi extends BaseApi {
private final static ResourceBundle weixinBundle;
private final static ResourceBundle WEIXIN_BUNDLE;
/**
* 默认使用weixin4j.properties文件中的企业号信息
*/
public final static WeixinQyAccount DEFAULT_WEIXIN_ACCOUNT;
/**
* 默认使用File的方法读取套件ticket
*/
public final static SuiteTicketProcessor DEFAULT_TICKET_PROCESSOR;
static {
weixinBundle = ResourceBundle
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
protected ResourceBundle getWeixinBundle() {
return weixinBundle;
protected String getConfigValue(String key) {
return WEIXIN_BUNDLE.getString(key);
}
}
@@ -0,0 +1,101 @@
package com.foxinmy.weixin4j.qy.api;
import com.alibaba.fastjson.JSONObject;
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.qy.suite.WeixinSuitePreCodeCreator;
import com.foxinmy.weixin4j.qy.suite.WeixinSuiteTokenCreator;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.token.TokenStorager;
/**
* 第三方应用套件
*
* @className SuiteApi
* @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%88%E6%9D%83">第三方应用授权</a>
*/
public class SuiteApi extends QyApi {
/**
* 应用套件token
*/
private final TokenHolder suiteTokenHolder;
private final TokenHolder suiteTicketHolder;
public SuiteApi() throws WeixinException {
this(DEFAULT_WEIXIN_ACCOUNT.getSuiteId(), DEFAULT_WEIXIN_ACCOUNT
.getSuiteSecret());
}
public SuiteApi(String suiteId, String suiteSecret) throws WeixinException {
this(suiteId, suiteSecret, DEFAULT_TICKET_PROCESSOR,
DEFAULT_TOKEN_STORAGER);
}
/**
*
* @param suiteId
* 应用ID
* @param suiteSecret
* 应用secret
* @param ticketReader
* 应用ticket读取器
* @param tokenStorager
* 应用token存储器
* @throws WeixinException
*/
public SuiteApi(String suiteId, String suiteSecret,
SuiteTicketProcessor ticketReader, TokenStorager tokenStorager)
throws WeixinException {
this.suiteTokenHolder = new TokenHolder(new WeixinSuiteTokenCreator(
suiteId, suiteSecret, ticketReader), tokenStorager);
this.suiteTicketHolder = new TokenHolder(new WeixinSuitePreCodeCreator(
suiteTokenHolder, suiteId), tokenStorager);
}
/**
* 应用套件token
*
* @return
*/
public TokenHolder getTokenHolder() {
return this.suiteTokenHolder;
}
/**
* 应用套件ticket
*
* @return
*/
public TokenHolder getTicketHolder() {
return this.suiteTicketHolder;
}
/**
* 设置套件授权配置:如果需要对某次授权进行配置,则调用本接口,目前仅可以设置哪些应用可以授权,不调用则默认允许所有应用进行授权。
*
* @param appids
* 允许进行授权的应用id,如1、2、3
* @return 处理结果
* @throws WeixinException
* <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"
* >设置套件授权配置</a>
*/
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("session_info", appids);
WeixinResponse response = weixinClient
.post(String.format(suite_set_session_uri,
suiteTokenHolder.getAccessToken()), para.toJSONString());
return response.getAsJsonResult();
}
}
@@ -83,4 +83,10 @@ batch_getresult_uri={api_base_url}/batch/getresult?access_token=%s&jobid=%s
# \u63d0\u4f9b\u5546oauth\u6388\u6743
provider_oauth_uri=https://qy.weixin.qq.com/cgi-bin/loginpage?corp_id=%s&redirect_uri=%s&state=%s
# \u4f01\u4e1a\u53f7\u7ba1\u7406\u5458\u767b\u5f55\u4fe1\u606f
oauth_logininfo_uri={api_base_url}/service/get_login_info?provider_access_token=%s
oauth_logininfo_uri={api_base_url}/service/get_login_info?provider_access_token=%s
# \u5e94\u7528\u5957\u4ef6oauth\u6388\u6743
suite_oauth_uri=https://qy.weixin.qq.com/cgi-bin/loginpage?suite_id=%s&pre_auth_code=%s&redirect_uri=%s&state=%s
# \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
@@ -34,6 +34,11 @@ public class Corpinfo extends AgentOverview {
*/
@JSONField(name = "corp_agent_max")
private int corpAgentMax;
/**
* 授权方企业号二维码
*/
@JSONField(name = "corp_wxqrcode")
private String corpWxqrcode;
public String getCorpid() {
return corpid;
@@ -67,10 +72,19 @@ public class Corpinfo extends AgentOverview {
this.corpAgentMax = corpAgentMax;
}
public String getCorpWxqrcode() {
return corpWxqrcode;
}
public void setCorpWxqrcode(String corpWxqrcode) {
this.corpWxqrcode = corpWxqrcode;
}
@Override
public String toString() {
return "Corpinfo [corpid=" + corpid + ", corpType=" + corpType
+ ", corpUserMax=" + corpUserMax + ", corpAgentMax="
+ corpAgentMax + ", " + super.toString() + "]";
+ corpAgentMax + ", corpWxqrcode=" + corpWxqrcode + ", "
+ super.toString() + "]";
}
}
@@ -30,11 +30,61 @@ public class WeixinQyAccount extends WeixinAccount {
super(corpid, corpsecret);
}
/**
* 应用套件id
*/
private String suiteId;
/**
* 应用套件secret
*/
private String suiteSecret;
/**
* 应用套件token,用于生成签名,校验回调请求的合法性。后续所有托管的企业产生的回调消息都使用该值来解密。
*/
private String suiteToken;
/**
* 应用套件encodingAesKey,回调消息加解密参数,是AES密钥的Base64编码,用于解密回调消息内容对应的密文。
* 后续所有托管的企业产生的回调消息都使用该值来解密。
*/
private String suiteEncodingAesKey;
/**
* 提供商的secret
*/
private String providerSecret;
public String getSuiteId() {
return suiteId;
}
public void setSuiteId(String suiteId) {
this.suiteId = suiteId;
}
public String getSuiteSecret() {
return suiteSecret;
}
public void setSuiteSecret(String suiteSecret) {
this.suiteSecret = suiteSecret;
}
public String getSuiteToken() {
return suiteToken;
}
public void setSuiteToken(String suiteToken) {
this.suiteToken = suiteToken;
}
public String getSuiteEncodingAesKey() {
return suiteEncodingAesKey;
}
public void setSuiteEncodingAesKey(String suiteEncodingAesKey) {
this.suiteEncodingAesKey = suiteEncodingAesKey;
}
public String getProviderSecret() {
return providerSecret;
}
@@ -45,7 +95,9 @@ public class WeixinQyAccount extends WeixinAccount {
@Override
public String toString() {
return "WeixinQyAccount [" + super.toString() + ", providerSecret="
+ providerSecret + "]";
return "WeixinQyAccount [" + super.toString() + ", suiteId=" + suiteId
+ ", suiteSecret=" + suiteSecret + ", suiteToken=" + suiteToken
+ ", suiteEncodingAesKey=" + suiteEncodingAesKey
+ ", providerSecret=" + providerSecret + "]";
}
}
@@ -0,0 +1,61 @@
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());
}
}
}
@@ -0,0 +1,26 @@
package com.foxinmy.weixin4j.qy.suite;
/**
* 应用套件回调事件
*
* @className SuiteEventType
* @author jy
* @date 2015年6月21日
* @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%9B%9E%E8%B0%83%E5%8D%8F%E8%AE%AE">第三方回调协议</a>
*/
public enum SuiteEventType {
/**
* 推送ticket
*/
suite_ticket,
/**
* 变更授权
*/
change_auth,
/**
* 取消授权
*/
cancel_auth;
}
@@ -0,0 +1,67 @@
package com.foxinmy.weixin4j.qy.suite;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class SuiteTicketMessage implements Serializable {
private static final long serialVersionUID = 6457919241019021514L;
/**
* 应用套件的SuiteId
*/
@XmlElement(name = "SuiteId")
private String suiteId;
/**
* 事件类型
*/
@XmlElement(name = "InfoType")
private SuiteEventType eventType;
/**
* 时间戳
*/
@XmlElement(name = "TimeStamp")
private long timeStamp;
/**
* Ticket内容
*/
@XmlElement(name = "SuiteTicket")
private String SuiteTicket;
/**
* 授权方企业号的corpid
*/
@XmlElement(name = "AuthCorpId")
private String authCorpId;
public String getSuiteId() {
return suiteId;
}
public SuiteEventType getEventType() {
return eventType;
}
public long getTimeStamp() {
return timeStamp;
}
public String getSuiteTicket() {
return SuiteTicket;
}
public String getAuthCorpId() {
return authCorpId;
}
@Override
public String toString() {
return "SuiteTicketMessage [suiteId=" + suiteId + ", eventType="
+ eventType + ", timeStamp=" + timeStamp + ", SuiteTicket="
+ SuiteTicket + ", authCorpId=" + authCorpId + "]";
}
}
@@ -0,0 +1,31 @@
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;
}
@@ -0,0 +1,60 @@
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;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 微信企业号应用套件预授权码创建
*
* @className WeixinTokenCreator
* @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.E9.A2.84.E6.8E.88.E6.9D.83.E7.A0.81">获取应用套件预授权码</a>
* @see com.foxinmy.weixin4j.model.Token
*/
public class WeixinSuitePreCodeCreator implements TokenCreator {
private final WeixinHttpClient httpClient;
private final TokenHolder suiteTokenHolder;
private final String suiteId;
/**
*
* @param suiteTokenHolder
* 应用套件的token
* @param suiteId
* 应用套件ID
*/
public WeixinSuitePreCodeCreator(TokenHolder suiteTokenHolder,
String suiteId) {
this.suiteTokenHolder = suiteTokenHolder;
this.suiteId = suiteId;
this.httpClient = new WeixinHttpClient();
}
@Override
public String getCacheKey() {
return String.format("qy_suite_precode_%s", suiteId);
}
@Override
public Token createToken() throws WeixinException {
WeixinResponse response = httpClient.post(
String.format(URLConsts.SUITE_PRE_CODE_URL,
suiteTokenHolder.getAccessToken()),
String.format("{\"suite_id\":\"%s\"}", suiteId));
JSONObject result = response.getAsJson();
Token token = new Token(result.getString("pre_auth_code"));
token.setExpiresIn(result.getIntValue("expires_in"));
token.setTime(System.currentTimeMillis());
return token;
}
}
@@ -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;
/**
* 微信企业号应用套件凭证创建
*
* @className WeixinTokenCreator
* @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.E5.BA.94.E7.94.A8.E5.A5.97.E4.BB.B6.E4.BB.A4.E7.89.8C">获取应用套件凭证</a>
* @see com.foxinmy.weixin4j.model.Token
*/
public class WeixinSuiteTokenCreator implements TokenCreator {
private final WeixinHttpClient httpClient;
private final String suiteId;
private final String suiteSecret;
private final SuiteTicketProcessor ticketProcessor;
/**
*
* @param suiteId
* 套件ID
* @param suiteSecret
* 套件secret
* @param ticketReader
* 套件ticket读取器
*/
public WeixinSuiteTokenCreator(String suiteId, String suiteSecret,
SuiteTicketProcessor ticketProcessor) {
this.suiteId = suiteId;
this.suiteSecret = suiteSecret;
this.ticketProcessor = ticketProcessor;
this.httpClient = new WeixinHttpClient();
}
@Override
public String getCacheKey() {
return String.format("qy_suite_token_%s", suiteId);
}
@Override
public Token createToken() throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("suite_id", suiteId);
obj.put("suite_secret", suiteSecret);
obj.put("suite_ticket", ticketProcessor.read(suiteId).getSuiteTicket());
WeixinResponse response = httpClient.post(URLConsts.SUITE_TOKEN_URL,
obj.toJSONString());
obj = response.getAsJson();
Token token = new Token(obj.getString("suite_access_token"));
token.setExpiresIn(obj.getIntValue("expires_in"));
token.setTime(System.currentTimeMillis());
return token;
}
}
@@ -4,11 +4,10 @@ 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.Consts;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.qy.type.URLConsts;
import com.foxinmy.weixin4j.token.TokenCreator;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 微信企业号JSTICKET创建
@@ -28,19 +27,11 @@ public class WeixinJSTicketCreator implements TokenCreator {
private final WeixinHttpClient httpClient;
/**
* jssdk
*
* @param weixinTokenHolder
* <font color="red">公众平台的access_token</font>
*/
public WeixinJSTicketCreator(TokenHolder weixinTokenHolder) {
this(ConfigUtil.getWeixinAccount().getId(), weixinTokenHolder);
}
/**
* <font color="red">企业号的的access_token</font>
*
* @param corpid
* 企业号ID
* @param weixinTokenHolder
* <font color="red">企业号的的access_token</font>
*/
public WeixinJSTicketCreator(String corpid, TokenHolder weixinTokenHolder) {
this.corpid = corpid;
@@ -56,7 +47,7 @@ public class WeixinJSTicketCreator implements TokenCreator {
@Override
public Token createToken() throws WeixinException {
WeixinResponse response = httpClient.get(String.format(
Consts.QY_JS_TICKET_URL, weixinTokenHolder.getToken()
URLConsts.JS_TICKET_URL, weixinTokenHolder.getToken()
.getAccessToken()));
JSONObject result = response.getAsJson();
Token token = new Token(result.getString("ticket"));
@@ -1,15 +1,12 @@
package com.foxinmy.weixin4j.qy.token;
import com.alibaba.fastjson.JSON;
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.Consts;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.qy.model.WeixinQyAccount;
import com.foxinmy.weixin4j.qy.type.URLConsts;
import com.foxinmy.weixin4j.token.TokenCreator;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 微信企业号应用提供商凭证创建
@@ -28,15 +25,13 @@ public class WeixinProviderTokenCreator implements TokenCreator {
private final String corpid;
private final String providersecret;
public WeixinProviderTokenCreator() {
this(JSON.parseObject(ConfigUtil.getValue("account"),
WeixinQyAccount.class));
}
public WeixinProviderTokenCreator(WeixinQyAccount qyAccount) {
this(qyAccount.getId(), qyAccount.getProviderSecret());
}
/**
*
* @param corpid
* 企业号ID
* @param providersecret
* 企业号提供商的secret
*/
public WeixinProviderTokenCreator(String corpid, String providersecret) {
this.corpid = corpid;
this.providersecret = providersecret;
@@ -53,7 +48,7 @@ public class WeixinProviderTokenCreator implements TokenCreator {
JSONObject obj = new JSONObject();
obj.put("corpid", corpid);
obj.put("provider_secret", providersecret);
WeixinResponse response = httpClient.post(Consts.QY_PROVIDER_TOKEN_URL,
WeixinResponse response = httpClient.post(URLConsts.PROVIDER_TOKEN_URL,
obj.toJSONString());
obj = response.getAsJson();
Token token = new Token(obj.getString("provider_access_token"));
@@ -4,11 +4,9 @@ import com.alibaba.fastjson.TypeReference;
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.Consts;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.qy.type.URLConsts;
import com.foxinmy.weixin4j.token.TokenCreator;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 微信企业号TOKEN创建
@@ -27,14 +25,13 @@ public class WeixinTokenCreator implements TokenCreator {
private final String corpid;
private final String corpsecret;
public WeixinTokenCreator() {
this(ConfigUtil.getWeixinAccount());
}
public WeixinTokenCreator(WeixinAccount weixinAccount) {
this(weixinAccount.getId(), weixinAccount.getSecret());
}
/**
*
* @param corpid
* 企业号ID
* @param corpsecret
* 企业号secret
*/
public WeixinTokenCreator(String corpid, String corpsecret) {
this.corpid = corpid;
this.corpsecret = corpsecret;
@@ -48,7 +45,7 @@ public class WeixinTokenCreator implements TokenCreator {
@Override
public Token createToken() throws WeixinException {
String tokenUrl = String.format(Consts.QY_ASSESS_TOKEN_URL, corpid,
String tokenUrl = String.format(URLConsts.ASSESS_TOKEN_URL, corpid,
corpsecret);
WeixinResponse response = httpClient.get(tokenUrl);
Token token = response.getAsObject(new TypeReference<Token>() {
@@ -0,0 +1,43 @@
package com.foxinmy.weixin4j.qy.type;
/**
* URL常量类
*
* @className URLConsts
* @author jy
* @date 2014年12月3日
* @since JDK 1.7
* @see
*/
public final class URLConsts {
/**
*
*/
public static final String BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin";
/**
* 企业号获取token的url
*/
public static final String ASSESS_TOKEN_URL = BASE_URL
+ "/gettoken?corpid=%s&corpsecret=%s";
/**
* 企业号提供商获取token的url
*/
public static final String PROVIDER_TOKEN_URL = BASE_URL
+ "/service/get_provider_token";
/**
* 企业号jssdk获取token的url
*/
public static final String JS_TICKET_URL = BASE_URL
+ "/get_jsapi_ticket?access_token=%s";
/**
* 企业号第三方应用套件获取token的url
*/
public static final String SUITE_TOKEN_URL = BASE_URL
+ "/service/get_suite_token";
/**
* 企业号第三方应用套件获取预授权码的url
*/
public static final String SUITE_PRE_CODE_URL = BASE_URL
+ "/service/get_pre_auth_code?suite_access_token=%s";
}
@@ -3,12 +3,18 @@
account={"id":"wxf10bce209c91d0e2","secret":"cW0OtP7-7YJ7jHKFZaJW2skJHE9bLHadxOswBdVdI2walRBSPfTSA6QqD_QXw8JZ",\
"token":"gp2eGT5mIpngr",\
"encodingAesKey":"BRYfV4zPFUJb3v3MySNBg1ERKE3vyyMRoScu76vFySv",\
"suiteId":"\u5e94\u7528\u5957\u4ef6\u7684id","suiteSecret":"\u5e94\u7528\u5957\u4ef6\u7684secret",\
"suiteToken":"\u5e94\u7528\u5957\u4ef6\u7684token",\
"suiteEncodingAesKey":"\u5e94\u7528\u5957\u4ef6\u7684encodingAesKey",\
"providerSecret":"\u63d0\u4f9b\u5546\u7684secret"}
# \u4f7f\u7528FileTokenHolder\u65f6token\u7684\u5b58\u653e\u8def\u5f84
# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84
token_path=/tmp/weixin4j/token
# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84
media_path=/tmp/weixin4j/media
# oauth\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url
redirect_uri=
# \u4f01\u4e1a\u53f7\u767b\u9646\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url
redirect_uri=
# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u5e94\u7528\u5957\u4ef6\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url
suite_redirect_uri=