diff --git a/CHANGE.md b/CHANGE.md index 3122b421..67a19726 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -607,4 +607,9 @@ + weixin4j-server:移入weixin4j下模块化 + weixin4j-server:删除无用的工具类并重新整理 + + +* 2015-12-30 + + + weixin4j-qy:新增服务商接口(ProviderApi) \ No newline at end of file diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/README.md b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/README.md new file mode 100644 index 00000000..35188e3e --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/README.md @@ -0,0 +1,5 @@ +* CashApi `现金红包API` + +* CouponApi `优惠券API` + +* Pay3Api `微信支付API` \ No newline at end of file diff --git a/weixin4j-mp/README.md b/weixin4j-mp/README.md index 07d52906..7aac2451 100644 --- a/weixin4j-mp/README.md +++ b/weixin4j-mp/README.md @@ -7,39 +7,31 @@ weixin4j-mp 功能列表 ------- -* MediaApi `媒体素材API` + * CustomApi `多客服API` -* NotifyApi `客服消息API` + * DataApi `数据统计API` -* CustomApi `多客服API` + * GroupApi `分组管理API` -* MassApi `群发消息API` + * HelperApi `辅助API` -* UserApi `用户管理API` + * MassApi `群发消息API` -* GroupApi `分组管理API` + * MediaApi `上传/下载媒体文件API` -* MenuApi `底部菜单API` + * MenuApi `底部菜单API` -* QrApi `二维码API` + * NotifyApi `客服消息API` -* TmplApi `模板消息API` + * OauthApi `oauth授权API` -* HelperApi `辅助API` + * Pay2Api `V2支付API` -* Pay2Api `V2支付API` - -* Pay3Api `V3(商户平台)支付API` + * QrApi `二维码API` -* CouponApi `代金券API` + * TmplApi `模板消息API` -* DataApi `数据统计API` - -* OauthApi `oauth授权API` - -* CashApi `现金API` - -* PayUtil [微信支付工具类](https://github.com/foxinmy/weixin4j/tree/master/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/PayUtil.java) + * UserApi `用户管理API` 如何使用 -------- diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/README.md b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/README.md index 1ca6f235..88ea2e68 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/README.md +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/README.md @@ -1,31 +1,25 @@ -* MediaApi `上传/下载媒体文件API` - -* NotifyApi `客服消息API` - * CustomApi `多客服API` -* MassApi `群发消息API` - -* UserApi `用户管理API` +* DataApi `数据统计API` * GroupApi `分组管理API` +* HelperApi `辅助API` + +* MassApi `群发消息API` + +* MediaApi `上传/下载媒体文件API` + * MenuApi `底部菜单API` +* NotifyApi `客服消息API` + +* OauthApi `oauth授权API` + +* Pay2Api `V2支付API` + * QrApi `二维码API` * TmplApi `模板消息API` -* HelperApi `辅助API` - -* Pay2Api `V2支付API` - -* Pay3Api `V3支付API` - -* CouponApi `代金券API` - -* DataApi `数据统计API` - -* OauthApi `oauth授权API` - -* CashApi `现金API` \ No newline at end of file +* UserApi `用户管理API` \ No newline at end of file diff --git a/weixin4j-qy/README.md b/weixin4j-qy/README.md index b84347a9..927c5e64 100644 --- a/weixin4j-qy/README.md +++ b/weixin4j-qy/README.md @@ -7,33 +7,32 @@ weixin4j-qy 功能列表 ------- - * PartyApi `部门管理API` - - * UserApi `成员管理API` - - * TagApi `标签管理API` - + * AgentApi `应用设置API` + + * BatchApi `批量任务API` + + * ChatApi `会话服务API` + + * Helper `辅助API` + * MediaApi `媒体素材API` * MenuApi `菜单管理API` * NotifyApi `消息发送API` - - * AgentApi `应用设置API` - - * BatchApi `批量任务API` - + * OauthApi `oauth授权登陆API` - - * SuiteApi `第三方应用API` - - * Pay3Api `商户平台支付API` + + * PartyApi `部门管理API` + +* ProviderApi `服务商API` + +* SuiteApi `第三方应用API` + +* TagApi `标签管理API` - * CouponApi `代金券API` - - * CashApi `现金API` +* UserApi `成员管理API` - * ChatApi `会话服务API` 如何使用 -------- diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java index 034ed372..204f1568 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java @@ -5,10 +5,17 @@ import java.util.Map; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.model.WeixinAccount; +import com.foxinmy.weixin4j.qy.api.ProviderApi; import com.foxinmy.weixin4j.qy.api.QyApi; import com.foxinmy.weixin4j.qy.api.SuiteApi; +import com.foxinmy.weixin4j.qy.model.OUserInfo; +import com.foxinmy.weixin4j.qy.model.WeixinQyAccount; import com.foxinmy.weixin4j.qy.suite.SuiteTicketHolder; +import com.foxinmy.weixin4j.qy.token.WeixinProviderTokenCreator; +import com.foxinmy.weixin4j.qy.type.LoginTargetType; +import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenStorager; +import com.foxinmy.weixin4j.util.StringUtil; /** * 微信第三方应用接口实现 @@ -23,7 +30,8 @@ import com.foxinmy.weixin4j.token.TokenStorager; */ public class WeixinSuiteProxy { - private final Map suiteMap; + private Map suiteMap; + private ProviderApi providerApi; public WeixinSuiteProxy() { this(QyApi.DEFAULT_TOKEN_STORAGER); @@ -38,8 +46,8 @@ public class WeixinSuiteProxy { * @throws WeixinException */ public WeixinSuiteProxy(String suiteId, String suiteSecret) { - this(QyApi.DEFAULT_TOKEN_STORAGER, new WeixinAccount(suiteId, - suiteSecret)); + this(QyApi.DEFAULT_TOKEN_STORAGER, null, null, new WeixinAccount( + suiteId, suiteSecret)); } /** @@ -48,7 +56,7 @@ public class WeixinSuiteProxy { * token存储 */ public WeixinSuiteProxy(TokenStorager tokenStorager) { - this(tokenStorager, QyApi.DEFAULT_WEIXIN_ACCOUNT.suitesToArray()); + this(tokenStorager, QyApi.DEFAULT_WEIXIN_ACCOUNT); } /** @@ -56,17 +64,42 @@ public class WeixinSuiteProxy { * @param tokenStorager * token存储 * @param suites - * 套件信息 + * 套件信息 必填项 */ public WeixinSuiteProxy(TokenStorager tokenStorager, - WeixinAccount... suites) { - this.suiteMap = new HashMap(); - for (WeixinAccount suite : suites) { - this.suiteMap.put(suite.getId(), new SuiteApi( - new SuiteTicketHolder(suite.getId(), suite.getSecret(), - tokenStorager))); + WeixinQyAccount weixinAccount) { + this(tokenStorager, weixinAccount.getId(), weixinAccount + .getProviderSecret(), weixinAccount.suitesToArray()); + } + + /** + * + * @param tokenStorager + * token存储 + * @param corpId + * 服务商的企业号ID 使用服务商API时必填项 + * @param providerSecret + * 服务商secret 使用服务商API时必填项 + * @param suites + * 套件信息 使用套件API时必填项 + */ + public WeixinSuiteProxy(TokenStorager tokenStorager, String corpId, + String providerSecret, WeixinAccount... suites) { + if (suites != null) { + this.suiteMap = new HashMap(); + for (WeixinAccount suite : suites) { + this.suiteMap.put(suite.getId(), new SuiteApi( + new SuiteTicketHolder(suite.getId(), suite.getSecret(), + tokenStorager))); + this.suiteMap.put(null, suiteMap.get(suites[0].getId())); + } + } + if (StringUtil.isNotBlank(corpId) + && StringUtil.isNotBlank(providerSecret)) { + this.providerApi = new ProviderApi(new TokenHolder( + new WeixinProviderTokenCreator(corpId, providerSecret), + tokenStorager)); } - this.suiteMap.put(null, suiteMap.get(suites[0].getId())); } /** @@ -91,5 +124,41 @@ public class WeixinSuiteProxy { return this.suiteMap.get(suiteId); } + /** + * 第三方套件获取企业号管理员登录信息 + * + * @param authCode + * oauth2.0授权企业号管理员登录产生的code + * @return 登陆信息 + * @see com.foxinmy.weixin4j.qy.api.ProviderApi + * @see 授权获取企业号管理员登录信息 + * @see com.foxinmy.weixin4j.qy.model.OUserInfo + * @throws WeixinException + */ + public OUserInfo getOUserInfoByCode(String authCode) throws WeixinException { + return providerApi.getOUserInfoByCode(authCode); + } + + /** + * 获取登录企业号官网的url + * + * @param corpId + * oauth授权的corpid + * @param targetType + * 登录跳转到企业号后台的目标页面 + * @param agentId + * 授权方应用id 小余1时则不传递 + * @return 登陆URL + * @see com.foxinmy.weixin4j.qy.api.ProviderApi + * @see 获取登录企业号官网的url + * @throws WeixinException + */ + public String getLoingUrl(String corpId, LoginTargetType targetType, + int agentId) throws WeixinException { + return providerApi.getLoingUrl(corpId, targetType, agentId); + } + public final static String VERSION = "1.6.5"; } 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 8758090f..902c035c 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 @@ -3,12 +3,7 @@ package com.foxinmy.weixin4j.qy.api; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -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.OUserInfo; import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; /** @@ -90,6 +85,8 @@ public class OauthApi extends QyApi { * @param state * 用于保持请求和回调的状态,授权请求后原样带回给第三方 * @return 请求授权的URL + * @see ProviderApi + * @see {@link com.foxinmy.weixin4j.qy.WeixinSuiteProxy#getOUserInfoByCode(String)} * @see 企业号第三方提供商授权 */ @@ -105,33 +102,6 @@ public class OauthApi extends QyApi { return ""; } - /** - * 第三方套件获取企业号管理员登录信息 - * - * @param providerToken - * 提供商的token - * @param authCode - * oauth2.0授权企业号管理员登录产生的code - * @return 登陆信息 - * @see 授权获取企业号管理员登录信息 - * @see com.foxinmy.weixin4j.qy.model.OUserInfo - * @throws WeixinException - */ - public OUserInfo getOUserInfoByCode(String providerToken, String authCode) - throws WeixinException { - String oauth_logininfo_uri = getRequestUri("oauth_logininfo_uri"); - WeixinResponse response = weixinExecutor.post( - String.format(oauth_logininfo_uri, providerToken), - String.format("{\"auth_code\":\"%s\"}", authCode)); - JSONObject obj = response.getAsJson(); - OUserInfo oUser = JSON.toJavaObject(obj, OUserInfo.class); - oUser.getRedirectLoginInfo().setAccessToken( - obj.getJSONObject("redirect_login_info").getString( - "login_ticket")); - return oUser; - } - /** * 应用套件授权 * diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/ProviderApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/ProviderApi.java new file mode 100644 index 00000000..d80bb3a6 --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/ProviderApi.java @@ -0,0 +1,96 @@ +package com.foxinmy.weixin4j.qy.api; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.qy.model.OUserInfo; +import com.foxinmy.weixin4j.qy.type.LoginTargetType; +import com.foxinmy.weixin4j.token.TokenHolder; +import com.foxinmy.weixin4j.util.StringUtil; + +/** + * 服务商相关API + * + * @className ProviderApi + * @author jy + * @date 2015年12月30日 + * @since JDK 1.6 + * @see 企业号登录授权说明 + */ +public class ProviderApi extends QyApi { + private final TokenHolder providerTokenHolder; + + public ProviderApi(TokenHolder providerTokenHolder) { + this.providerTokenHolder = providerTokenHolder; + } + + /** + * 第三方套件获取企业号管理员登录信息 + * + * @param authCode + * oauth2.0授权企业号管理员登录产生的code + * @return 登陆信息 + * @see 授权获取企业号管理员登录信息 + * @see com.foxinmy.weixin4j.qy.model.OUserInfo + * @throws WeixinException + */ + public OUserInfo getOUserInfoByCode(String authCode) throws WeixinException { + String oauth_logininfo_uri = getRequestUri("oauth_logininfo_uri"); + WeixinResponse response = weixinExecutor.post( + String.format(oauth_logininfo_uri, + providerTokenHolder.getAccessToken()), + String.format("{\"auth_code\":\"%s\"}", authCode)); + JSONObject obj = response.getAsJson(); + OUserInfo oUser = JSON.toJavaObject(obj, OUserInfo.class); + oUser.getRedirectLoginInfo().setAccessToken( + obj.getJSONObject("redirect_login_info").getString( + "login_ticket")); + providerTokenHolder.getTokenStorager().caching( + getLoginTicketCacheKey(oUser.getCorpInfo().getCorpId()), + oUser.getRedirectLoginInfo()); + return oUser; + } + + private String getLoginTicketCacheKey(String coprId) { + return String.format("wx_qy_provider_login_ticket_%s", coprId); + } + + /** + * 获取登录企业号官网的url + * + * @param corpId + * oauth授权的corpid + * @param targetType + * 登录跳转到企业号后台的目标页面 + * @param agentId + * 授权方应用id 小余1时则不传递 + * @return 登陆URL + * @see 获取登录企业号官网的url + * @throws WeixinException + */ + public String getLoingUrl(String corpId, LoginTargetType targetType, + int agentId) throws WeixinException { + Token token = providerTokenHolder.getTokenStorager().lookup( + getLoginTicketCacheKey(corpId)); + if (token == null || StringUtil.isBlank(token.getAccessToken())) { + throw new WeixinException("maybe oauth first?"); + } + String oauth_loginurl_uri = getRequestUri("oauth_loginurl_uri"); + JSONObject obj = new JSONObject(); + obj.put("login_ticket", token.getAccessToken()); + obj.put("target", targetType.name()); + if (agentId > 0) { + obj.put("agentid", agentId); + } + WeixinResponse response = weixinExecutor.post( + String.format(oauth_loginurl_uri, + providerTokenHolder.getAccessToken()), + obj.toJSONString()); + return response.getAsJson().getString("login_url"); + } +} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/README.md b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/README.md new file mode 100644 index 00000000..033d75b2 --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/README.md @@ -0,0 +1,26 @@ +* AgentApi `应用设置API` + +* BatchApi `批量任务API` + +* ChatApi `会话服务API` + +* Helper `辅助API` + +* MediaApi `媒体素材API` + +* MenuApi `菜单管理API` + +* NotifyApi `消息发送API` + +* OauthApi `oauth授权登陆API` + +* PartyApi `部门管理API` + +* ProviderApi `服务商API` + +* SuiteApi `第三方应用API` + +* TagApi `标签管理API` + +* UserApi `成员管理API` + \ No newline at end of file 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 ada62c28..312f18fa 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 @@ -88,6 +88,8 @@ user_oauth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redi 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 +# \u767b\u5f55\u4f01\u4e1a\u53f7\u5b98\u7f51\u7684url +oauth_loginurl_uri={api_base_url}/service/get_login_url?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 diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/type/LoginTargetType.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/type/LoginTargetType.java new file mode 100644 index 00000000..253befe5 --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/type/LoginTargetType.java @@ -0,0 +1,14 @@ +package com.foxinmy.weixin4j.qy.type; + +/** + * 登录跳转到企业号后台的目标页面 + * + * @className LoginTargetType + * @author jy + * @date 2015年12月30日 + * @since JDK 1.6 + * @see + */ +public enum LoginTargetType { + agent_setting, send_msg, contact, third_admin +}