From dd1fcaa598ea09064573e84c91c323291edfd2ac Mon Sep 17 00:00:00 2001 From: jinyu Date: Sun, 21 Jun 2015 22:20:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BB=E8=A6=81=E6=96=B0=E5=A2=9E=E4=BA=86?= =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=8F=B7=E7=9A=84=E7=AC=AC=E4=B8=89=E6=96=B9?= =?UTF-8?q?=E5=BA=94=E7=94=A8API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGE.md | 8 +- README.md | 2 - .../com/foxinmy/weixin4j/api/BaseApi.java | 13 ++- .../foxinmy/weixin4j/http/weixin/error.xml | 8 +- .../com/foxinmy/weixin4j/model/Consts.java | 37 ------ .../com/foxinmy/weixin4j/model/Token.java | 2 +- .../weixin4j/token/FileTokenStorager.java | 2 +- .../foxinmy/weixin4j/token/TokenHolder.java | 31 ++++- .../foxinmy/weixin4j/token/TokenStorager.java | 7 +- .../foxinmy/weixin4j/mp/WeixinPayProxy.java | 28 +++-- .../com/foxinmy/weixin4j/mp/WeixinProxy.java | 32 +++--- .../com/foxinmy/weixin4j/mp/api/MpApi.java | 19 +++- .../com/foxinmy/weixin4j/mp/api/OauthApi.java | 11 +- .../foxinmy/weixin4j/mp/payment/PayUtil.java | 9 +- .../weixin4j/mp/payment/v3/RefundRecord.java | 2 +- .../mp/token/WeixinJSTicketCreator.java | 17 +-- .../weixin4j/mp/token/WeixinTokenCreator.java | 21 ++-- .../foxinmy/weixin4j/mp/type/URLConsts.java | 38 +++++++ .../src/main/resources/weixin4j.properties | 2 +- .../foxinmy/weixin4j/mp/test/CouponTest.java | 2 +- .../com/foxinmy/weixin4j/mp/test/PayTest.java | 4 +- .../foxinmy/weixin4j/mp/test/TokenTest.java | 6 +- .../weixin4j/mp/test/XmlstreamTest.java | 2 - weixin4j-qy/CHANGE.md | 6 +- .../com/foxinmy/weixin4j/qy/WeixinProxy.java | 36 +++--- .../com/foxinmy/weixin4j/qy/api/OauthApi.java | 106 +++++++++--------- .../com/foxinmy/weixin4j/qy/api/QyApi.java | 26 ++++- .../com/foxinmy/weixin4j/qy/api/SuiteApi.java | 101 +++++++++++++++++ .../foxinmy/weixin4j/qy/api/weixin.properties | 8 +- .../foxinmy/weixin4j/qy/model/Corpinfo.java | 16 ++- .../weixin4j/qy/model/WeixinQyAccount.java | 56 ++++++++- .../qy/suite/FileTicketProcessor.java | 61 ++++++++++ .../weixin4j/qy/suite/SuiteEventType.java | 26 +++++ .../weixin4j/qy/suite/SuiteTicketMessage.java | 67 +++++++++++ .../qy/suite/SuiteTicketProcessor.java | 31 +++++ .../qy/suite/WeixinSuitePreCodeCreator.java | 60 ++++++++++ .../qy/suite/WeixinSuiteTokenCreator.java | 65 +++++++++++ .../qy/token/WeixinJSTicketCreator.java | 19 +--- .../qy/token/WeixinProviderTokenCreator.java | 23 ++-- .../weixin4j/qy/token/WeixinTokenCreator.java | 21 ++-- .../foxinmy/weixin4j/qy/type/URLConsts.java | 43 +++++++ .../src/main/resources/weixin4j.properties | 12 +- .../foxinmy/weixin4j/qy/test/TokenTest.java | 6 +- .../response/TransferCustomerResponse.java | 8 +- 44 files changed, 850 insertions(+), 250 deletions(-) create mode 100644 weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/URLConsts.java create mode 100644 weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java create 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/SuiteEventType.java create mode 100644 weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketMessage.java create 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/WeixinSuitePreCodeCreator.java create mode 100644 weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuiteTokenCreator.java create mode 100644 weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/type/URLConsts.java diff --git a/CHANGE.md b/CHANGE.md index 3a8d2d44..727a6c65 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -331,4 +331,10 @@ + 修缮token实现机制 - + **weixin4j-qy**: 新增企业号[登陆授权](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java)API \ No newline at end of file + + **weixin4j-qy**: 新增企业号[登陆授权](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java)API + +* 2015-06-21 + + + 新增了默认常量对象在BaseApi.java类 + + + **weixin4j-qy**:新增企业号[第三方应用API](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite)。 \ No newline at end of file diff --git a/README.md b/README.md index 1dea3dca..83f0f097 100644 --- a/README.md +++ b/README.md @@ -72,8 +72,6 @@ weixin4j ------ * 公众号第三方服务应用 -* 企业号第三方应用 - * 硬件设备 & 摇一摇周边 * 微信小店 diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java index 8b37ac49..7a4020cc 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java @@ -1,10 +1,11 @@ package com.foxinmy.weixin4j.api; -import java.util.ResourceBundle; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.foxinmy.weixin4j.http.weixin.WeixinHttpClient; +import com.foxinmy.weixin4j.token.FileTokenStorager; +import com.foxinmy.weixin4j.token.TokenStorager; /** * API基础 @@ -17,9 +18,10 @@ import com.foxinmy.weixin4j.http.weixin.WeixinHttpClient; * @see 微信企业号API文档 */ public abstract class BaseApi { + protected final WeixinHttpClient weixinClient = new WeixinHttpClient(); - protected abstract ResourceBundle getWeixinBundle(); + protected abstract String getConfigValue(String key); protected String getRequestUri(String key) { String url = getConfigValue(key); @@ -36,7 +38,8 @@ public abstract class BaseApi { return sb.toString(); } - protected String getConfigValue(String key) { - return getWeixinBundle().getString(key); - } + /** + * 默认token使用File的方式存储 + */ + public final static TokenStorager DEFAULT_TOKEN_STORAGER = new FileTokenStorager(); } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml index a881db8e..fea10021 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml @@ -486,10 +486,14 @@ 43011 需要企业授权 + + 43013 + 应用对成员不可见 + 44001 empty media data - 空白的二进制数据 + 多媒体文件为空 44002 @@ -859,7 +863,7 @@ 60125 - 部门名字长度超过限制 + 非法部门名字,长度超过限制、重名等 60126 diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Consts.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Consts.java index 83a471f3..59104361 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Consts.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Consts.java @@ -27,41 +27,4 @@ public final class Consts { public static final String SHA1 = "SHA-1"; public static final String PROTOCOL_FILE = "file"; public static final String PROTOCOL_JAR = "jar"; - - /** - * 公众平台获取token的url - */ - public static final String MP_ASSESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; - /** - * 企业号获取token的url - */ - public static final String QY_ASSESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s"; - /** - * 企业号提供商获取token的url - */ - public static final String QY_PROVIDER_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token"; - /** - * 公众平台jssdk获取token的url - */ - public static final String MP_JS_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi"; - /** - * 企业号jssdk获取token的url - */ - public static final String QY_JS_TICKET_URL = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=%s"; - /** - * 商户平台下统一订单生成的url - */ - public static final String UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder"; - /** - * 商户平台下刷卡支付的url - */ - public static final String MICROPAYURL = "https://api.mch.weixin.qq.com/pay/micropay"; - /** - * V2支付下natvie支付的url - */ - public static final String NATIVEURLV2 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s×tamp=%s&noncestr=%s"; - /** - * 商户平台(V3)下native支付的url - */ - public static final String NATIVEURLV3 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s"; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java index be9f7588..d3079914 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java @@ -32,7 +32,7 @@ public class Token implements Serializable { @JSONField(name = "expires_in") private int expiresIn; /** - * token创建的时间 只在FileTokenHolder模式下有效 + * token创建的时间 只在FileTokenStorager模式下有效 */ private long time; 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 a39f236f..d91b1126 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 @@ -51,7 +51,7 @@ public class FileTokenStorager implements TokenStorager { } @Override - public void cachingToken(Token token, String cacheKey) + public void cachingToken(String cacheKey, Token token) throws WeixinException { try { XmlStream.toXML( 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 73edb3c0..5cbe26f1 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 @@ -15,21 +15,50 @@ import com.foxinmy.weixin4j.model.Token; */ public final class TokenHolder { + /** + * token的创建 + */ private final TokenCreator tokenCreator; + /** + * token的存储 + */ private final TokenStorager tokenStorager; + /** + * + * @param tokenCreator + * token创建器 + * @param tokenStorager + * token保存器 + */ public TokenHolder(TokenCreator tokenCreator, TokenStorager tokenStorager) { this.tokenCreator = tokenCreator; this.tokenStorager = tokenStorager; } + /** + * 获取token对象 + * + * @return + * @throws WeixinException + */ public Token getToken() throws WeixinException { String cacheKey = tokenCreator.getCacheKey(); Token token = tokenStorager.lookupToken(cacheKey); if (token == null) { token = tokenCreator.createToken(); - tokenStorager.cachingToken(token, cacheKey); + tokenStorager.cachingToken(cacheKey, token); } return token; } + + /** + * 获取token字符串 + * + * @return + * @throws WeixinException + */ + public String getAccessToken() throws WeixinException { + return getToken().getAccessToken(); + } } 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 fa7e77c9..c2e0dacf 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 @@ -28,12 +28,13 @@ public interface TokenStorager { /** * 缓存新的token * - * @param token - * 新产生的token * @param cacheKey * 缓存的名称 + * + * @param token + * 新产生的token * @throws WeixinException */ - public void cachingToken(Token token, String cacheKey) + public void cachingToken(String cacheKey, Token token) throws WeixinException; } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java index 80c5f4ef..5c947853 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java @@ -3,12 +3,12 @@ package com.foxinmy.weixin4j.mp; import java.io.File; import java.util.Date; -import com.alibaba.fastjson.JSON; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.XmlResult; import com.foxinmy.weixin4j.mp.api.CashApi; import com.foxinmy.weixin4j.mp.api.CouponApi; +import com.foxinmy.weixin4j.mp.api.MpApi; import com.foxinmy.weixin4j.mp.api.Pay2Api; import com.foxinmy.weixin4j.mp.api.Pay3Api; import com.foxinmy.weixin4j.mp.api.PayApi; @@ -28,7 +28,6 @@ import com.foxinmy.weixin4j.mp.type.CurrencyType; import com.foxinmy.weixin4j.mp.type.IdQuery; import com.foxinmy.weixin4j.mp.type.IdType; import com.foxinmy.weixin4j.mp.type.RefundType; -import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenStorager; import com.foxinmy.weixin4j.util.ConfigUtil; @@ -52,32 +51,35 @@ public class WeixinPayProxy { private final CouponApi couponApi; private final CashApi cashApi; + private final TokenHolder tokenHolder; + /** * 默认使用文件保存token、使用weixin4j.properties配置的账号信息 */ public WeixinPayProxy() { - this(new FileTokenStorager()); + this(MpApi.DEFAULT_TOKEN_STORAGER); } /** * 使用weixin4j.properties配置的账号信息 */ public WeixinPayProxy(TokenStorager tokenStorager) { - this(tokenStorager, JSON.parseObject(ConfigUtil.getValue("account"), - WeixinMpAccount.class)); + this(MpApi.DEFAULT_WEIXIN_ACCOUNT, tokenStorager); } /** + * + * @param weixinAccount + * 公众号账号信息 * * @param tokenStorager * token的存储策略 - * @param weixinAccount - * 公众号账号信息 */ - public WeixinPayProxy(TokenStorager tokenStorager, - WeixinMpAccount weixinAccount) { - TokenHolder tokenHolder = new TokenHolder(new WeixinTokenCreator( - weixinAccount), tokenStorager); + public WeixinPayProxy(WeixinMpAccount weixinAccount, + TokenStorager tokenStorager) { + this.tokenHolder = new TokenHolder(new WeixinTokenCreator( + weixinAccount.getId(), weixinAccount.getSecret()), + tokenStorager); this.pay2Api = new Pay2Api(weixinAccount, tokenHolder); this.pay3Api = new Pay3Api(weixinAccount, tokenHolder); int version = weixinAccount.getVersion(); @@ -92,6 +94,10 @@ public class WeixinPayProxy { this.cashApi = new CashApi(weixinAccount); } + public TokenHolder getTokenHolder() { + return this.tokenHolder; + } + /** * 发货通知 * diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java index f6ca10ee..0a947cda 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java @@ -8,7 +8,6 @@ import java.util.List; 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.mp.api.CustomApi; import com.foxinmy.weixin4j.mp.api.DataApi; import com.foxinmy.weixin4j.mp.api.GroupApi; @@ -16,6 +15,7 @@ import com.foxinmy.weixin4j.mp.api.HelperApi; import com.foxinmy.weixin4j.mp.api.MassApi; import com.foxinmy.weixin4j.mp.api.MediaApi; import com.foxinmy.weixin4j.mp.api.MenuApi; +import com.foxinmy.weixin4j.mp.api.MpApi; import com.foxinmy.weixin4j.mp.api.NotifyApi; import com.foxinmy.weixin4j.mp.api.QrApi; import com.foxinmy.weixin4j.mp.api.TmplApi; @@ -40,7 +40,6 @@ import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator; import com.foxinmy.weixin4j.mp.type.DatacubeType; import com.foxinmy.weixin4j.mp.type.IndustryType; import com.foxinmy.weixin4j.mp.type.Lang; -import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenStorager; import com.foxinmy.weixin4j.tuple.MassTuple; @@ -48,7 +47,6 @@ import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.Tuple; import com.foxinmy.weixin4j.tuple.Video; import com.foxinmy.weixin4j.type.MediaType; -import com.foxinmy.weixin4j.util.ConfigUtil; /** * 微信公众平台接口实现 @@ -73,19 +71,23 @@ public class WeixinProxy { private final HelperApi helperApi; private final DataApi dataApi; + private final TokenHolder tokenHolder; + /** * 默认使用文件方式保存token、使用weixin4j.properties配置的账号信息 */ public WeixinProxy() { - this(new FileTokenStorager()); + this(MpApi.DEFAULT_TOKEN_STORAGER); } /** * 默认使用weixin4j.properties配置的账号信息 + * * @param tokenStorager */ public WeixinProxy(TokenStorager tokenStorager) { - this(tokenStorager, ConfigUtil.getWeixinAccount()); + this(MpApi.DEFAULT_WEIXIN_ACCOUNT.getId(), MpApi.DEFAULT_WEIXIN_ACCOUNT + .getSecret(), tokenStorager); } /** @@ -94,19 +96,13 @@ public class WeixinProxy { * @param appsecret */ public WeixinProxy(String appid, String appsecret) { - this(new FileTokenStorager(), new WeixinAccount(appid, appsecret)); + this(appid, appsecret, MpApi.DEFAULT_TOKEN_STORAGER); } - /** - * - * @param tokenStorager - * token存储策略 - * @param weixinAccount - * 公众号账号信息 - */ - public WeixinProxy(TokenStorager tokenStorager, WeixinAccount weixinAccount) { - TokenHolder tokenHolder = new TokenHolder(new WeixinTokenCreator( - weixinAccount), tokenStorager); + public WeixinProxy(String appid, String appsecret, + TokenStorager tokenStorager) { + this.tokenHolder = new TokenHolder(new WeixinTokenCreator(appid, + appsecret), tokenStorager); this.mediaApi = new MediaApi(tokenHolder); this.notifyApi = new NotifyApi(tokenHolder); this.customApi = new CustomApi(tokenHolder); @@ -120,6 +116,10 @@ public class WeixinProxy { this.dataApi = new DataApi(tokenHolder); } + public TokenHolder getTokenHolder() { + return this.tokenHolder; + } + /** * 上传媒体文件 * diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java index efa836b3..98cfd9d9 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java @@ -2,7 +2,10 @@ package com.foxinmy.weixin4j.mp.api; import java.util.ResourceBundle; +import com.alibaba.fastjson.JSON; import com.foxinmy.weixin4j.api.BaseApi; +import com.foxinmy.weixin4j.mp.model.WeixinMpAccount; +import com.foxinmy.weixin4j.util.ConfigUtil; /** * 微信公众平台API @@ -15,14 +18,22 @@ import com.foxinmy.weixin4j.api.BaseApi; * @see api文档 */ public class MpApi extends BaseApi { - private final static ResourceBundle weixinBundle; + + private final static ResourceBundle WEIXIN_BUNDLE; + /** + * 默认使用weixin4j.properties文件中的公众号信息 + */ + public final static WeixinMpAccount DEFAULT_WEIXIN_ACCOUNT; + static { - weixinBundle = ResourceBundle + WEIXIN_BUNDLE = ResourceBundle .getBundle("com/foxinmy/weixin4j/mp/api/weixin"); + DEFAULT_WEIXIN_ACCOUNT = JSON.parseObject( + ConfigUtil.getValue("account"), WeixinMpAccount.class); } @Override - protected ResourceBundle getWeixinBundle() { - return weixinBundle; + protected String getConfigValue(String key) { + return WEIXIN_BUNDLE.getString(key); } } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java index baf26212..4846cd06 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java @@ -7,7 +7,6 @@ import com.alibaba.fastjson.TypeReference; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Consts; -import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.mp.model.OauthToken; import com.foxinmy.weixin4j.mp.model.User; import com.foxinmy.weixin4j.util.ConfigUtil; @@ -24,13 +23,14 @@ import com.foxinmy.weixin4j.util.StringUtil; * href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN">微信登陆 */ public class OauthApi extends MpApi { + /** * @see {@link com.foxinmy.weixin4j.mp.api.OauthApi#getAuthorizeURL(String, String,String)} * * @return 请求授权的URL */ public String getAuthorizeURL() { - String appId = ConfigUtil.getWeixinAccount().getId(); + String appId = DEFAULT_WEIXIN_ACCOUNT.getId(); String redirectUri = ConfigUtil.getValue("redirect_uri"); return getAuthorizeURL(appId, redirectUri, "state", "snsapi_login"); } @@ -65,8 +65,8 @@ public class OauthApi extends MpApi { * @return */ public OauthToken getOauthToken(String code) throws WeixinException { - WeixinAccount account = ConfigUtil.getWeixinAccount(); - return getOauthToken(code, account.getId(), account.getSecret()); + return getOauthToken(code, DEFAULT_WEIXIN_ACCOUNT.getId(), + DEFAULT_WEIXIN_ACCOUNT.getSecret()); } /** @@ -98,8 +98,7 @@ public class OauthApi extends MpApi { * @return */ public OauthToken refreshToken(String refreshToken) throws WeixinException { - WeixinAccount account = ConfigUtil.getWeixinAccount(); - return refreshToken(account.getId(), refreshToken); + return refreshToken(DEFAULT_WEIXIN_ACCOUNT.getId(), refreshToken); } /** diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/PayUtil.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/PayUtil.java index e7731205..1c211b4c 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/PayUtil.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/PayUtil.java @@ -19,6 +19,7 @@ import com.foxinmy.weixin4j.mp.payment.v3.PayRequestV3; import com.foxinmy.weixin4j.mp.payment.v3.PrePay; import com.foxinmy.weixin4j.mp.type.SignType; import com.foxinmy.weixin4j.mp.type.TradeType; +import com.foxinmy.weixin4j.mp.type.URLConsts; import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.DateUtil; import com.foxinmy.weixin4j.util.DigestUtil; @@ -228,7 +229,7 @@ public class PayUtil { } String payJsRequestXml = XmlStream.toXML(payPackage); try { - WeixinResponse response = httpClient.post(Consts.UNIFIEDORDER, + WeixinResponse response = httpClient.post(URLConsts.UNIFIEDORDER, payJsRequestXml); PrePay prePay = response.getAsObject(new TypeReference() { }); @@ -303,7 +304,7 @@ public class PayUtil { map.put("productid", productId); map.put("appkey", weixinAccount.getPaySignKey()); String sign = paysignSha(map); - return String.format(Consts.NATIVEURLV2, sign, weixinAccount.getId(), + return String.format(URLConsts.NATIVEURLV2, sign, weixinAccount.getId(), productId, timestamp, noncestr); } @@ -328,7 +329,7 @@ public class PayUtil { map.put("nonce_str", noncestr); map.put("product_id", productId); String sign = paysignMd5(map, weixinAccount.getPaySignKey()); - return String.format(Consts.NATIVEURLV3, sign, weixinAccount.getId(), + return String.format(URLConsts.NATIVEURLV3, sign, weixinAccount.getId(), weixinAccount.getMchId(), productId, timestamp, noncestr); } @@ -408,7 +409,7 @@ public class PayUtil { String sign = paysignMd5(payPackage, weixinAccount.getPaySignKey()); payPackage.setSign(sign); String para = XmlStream.toXML(payPackage); - WeixinResponse response = httpClient.post(Consts.MICROPAYURL, para); + WeixinResponse response = httpClient.post(URLConsts.MICROPAYURL, para); return response .getAsObject(new TypeReference() { }); diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/RefundRecord.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/RefundRecord.java index f9f629ab..0386e77d 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/RefundRecord.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/RefundRecord.java @@ -88,7 +88,7 @@ public class RefundRecord extends ApiResult { * * @see com.foxinmy.weixin4j.mp.payment.v3.RefundDetail */ - @ListsuffixResult({ "out_refund_no(_\\d)$", "^refund_.*(_\\d)$" }) + @ListsuffixResult({ "^out_refund_no(_\\d)$", "^refund_.*(_\\d)$" }) private List refundList; protected RefundRecord() { diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/token/WeixinJSTicketCreator.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/token/WeixinJSTicketCreator.java index fa43fe44..ad649f20 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/token/WeixinJSTicketCreator.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/token/WeixinJSTicketCreator.java @@ -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.mp.type.URLConsts; import com.foxinmy.weixin4j.token.TokenCreator; import com.foxinmy.weixin4j.token.TokenHolder; -import com.foxinmy.weixin4j.util.ConfigUtil; /** * 微信公众平台JSTICKET创建者 @@ -27,21 +26,11 @@ public class WeixinJSTicketCreator implements TokenCreator { private final TokenHolder weixinTokenHolder; private final WeixinHttpClient httpClient; - /** - * jssdk - * - * @param weixinTokenHolder - * 公众平台的access_token - */ - public WeixinJSTicketCreator(TokenHolder weixinTokenHolder) { - this(ConfigUtil.getWeixinAccount().getId(), weixinTokenHolder); - } - /** * jssdk * * @param appid - * appid + * 公众号的appid * @param weixinTokenHolder * 公众平台的access_token */ @@ -59,7 +48,7 @@ public class WeixinJSTicketCreator implements TokenCreator { @Override public Token createToken() throws WeixinException { WeixinResponse response = httpClient.get(String.format( - Consts.MP_JS_TICKET_URL, weixinTokenHolder.getToken() + URLConsts.JS_TICKET_URL, weixinTokenHolder.getToken() .getAccessToken())); JSONObject result = response.getAsJson(); Token token = new Token(result.getString("ticket")); diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/token/WeixinTokenCreator.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/token/WeixinTokenCreator.java index 2e45935c..25427b4b 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/token/WeixinTokenCreator.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/token/WeixinTokenCreator.java @@ -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.mp.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 appid; private final String secret; - public WeixinTokenCreator() { - this(ConfigUtil.getWeixinAccount()); - } - - public WeixinTokenCreator(WeixinAccount weixinAccount) { - this(weixinAccount.getId(), weixinAccount.getSecret()); - } - + /** + * + * @param appid + * 公众号ID + * @param secret + * 公众号secret + */ public WeixinTokenCreator(String appid, String secret) { this.appid = appid; this.secret = secret; @@ -48,7 +45,7 @@ public class WeixinTokenCreator implements TokenCreator { @Override public Token createToken() throws WeixinException { - String tokenUrl = String.format(Consts.MP_ASSESS_TOKEN_URL, appid, + String tokenUrl = String.format(URLConsts.ASSESS_TOKEN_URL, appid, secret); WeixinResponse response = httpClient.get(tokenUrl); Token token = response.getAsObject(new TypeReference() { diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/URLConsts.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/URLConsts.java new file mode 100644 index 00000000..767e3d57 --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/URLConsts.java @@ -0,0 +1,38 @@ +package com.foxinmy.weixin4j.mp.type; + + +/** + * URL常量类 + * + * @className URLConsts + * @author jy + * @date 2014年12月3日 + * @since JDK 1.7 + * @see + */ +public final class URLConsts { + /** + * 公众平台获取token的url + */ + public static final String ASSESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + /** + * 公众平台jssdk获取token的url + */ + public static final String JS_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi"; + /** + * 商户平台下统一订单生成的url + */ + public static final String UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder"; + /** + * 商户平台下刷卡支付的url + */ + public static final String MICROPAYURL = "https://api.mch.weixin.qq.com/pay/micropay"; + /** + * V2支付下natvie支付的url + */ + public static final String NATIVEURLV2 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s×tamp=%s&noncestr=%s"; + /** + * 商户平台(V3)下native支付的url + */ + public static final String NATIVEURLV3 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s"; +} diff --git a/weixin4j-mp/src/main/resources/weixin4j.properties b/weixin4j-mp/src/main/resources/weixin4j.properties index a34117d8..f05c1af4 100644 --- a/weixin4j-mp/src/main/resources/weixin4j.properties +++ b/weixin4j-mp/src/main/resources/weixin4j.properties @@ -9,7 +9,7 @@ account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\ "partnerKey":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ "paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} -# \u4f7f\u7528FileTokenHolder\u65f6token\u7684\u5b58\u653e\u8def\u5f84 +# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84 token_path=/tmp/weixin4j/token # \u4e8c\u7ef4\u7801\u4fdd\u5b58\u8def\u5f84 qr_path=/tmp/weixin4j/qrcode diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/CouponTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/CouponTest.java index 540f2305..4e2caa6d 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/CouponTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/CouponTest.java @@ -32,7 +32,7 @@ public class CouponTest { ACCOUNT = new WeixinMpAccount("appid", "appsecret", "paysign", "mchid"); - WEIXINPAY = new WeixinPayProxy(new FileTokenStorager(), ACCOUNT); + WEIXINPAY = new WeixinPayProxy(ACCOUNT, new FileTokenStorager()); } protected final File caFile = new File("证书文件路径(*.p12)"); diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java index f9d5d7d7..ebc1f227 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java @@ -30,10 +30,10 @@ public class PayTest { static { ACCOUNT2 = new WeixinMpAccount("请填入v2版本的appid", "请填入v2版本的appSecret", "请填入v3版本的paysignkey", "请填入v2版本的partnerId", "请填入v2版本的partnerKey"); - PAY2 = new WeixinPayProxy(new FileTokenStorager(), ACCOUNT2); + PAY2 = new WeixinPayProxy(ACCOUNT2, new FileTokenStorager()); ACCOUNT3 = new WeixinMpAccount("请填入v3版本的appid", "请填入v3版本的appSecret", "请填入v3版本的paysignkey", "请填入v3版本的mchid"); - PAY3 = new WeixinPayProxy(new FileTokenStorager(), ACCOUNT3); + PAY3 = new WeixinPayProxy(ACCOUNT3, new FileTokenStorager()); } @Test diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java index 6cbfcb32..6a117234 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java @@ -5,9 +5,11 @@ import org.junit.Before; import org.junit.Test; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator; import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.token.TokenHolder; +import com.foxinmy.weixin4j.util.ConfigUtil; /** * token测试 @@ -23,7 +25,9 @@ public class TokenTest { @Before public void setUp() { - tokenHolder = new TokenHolder(new WeixinTokenCreator(), + WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount(); + tokenHolder = new TokenHolder(new WeixinTokenCreator( + weixinAccount.getId(), weixinAccount.getSecret()), new FileTokenStorager()); } diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/XmlstreamTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/XmlstreamTest.java index 466fef8f..0e1bca42 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/XmlstreamTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/XmlstreamTest.java @@ -106,7 +106,6 @@ public class XmlstreamTest { // System.err.println(xml2refundRecordV2()); xml2refundRecordV3(); // object2xmlWithoutRootElement(); - /*RefundRecord refundRecord = xml2refundRecordV2(); System.err.println(refundRecord); String sign = refundRecord.getSign(); @@ -115,6 +114,5 @@ public class XmlstreamTest { System.err.println("sign=" + sign + ",validSign=" + validSign); System.err.println(ListsuffixResultSerializer .serializeToXML(refundRecord));*/ - } } diff --git a/weixin4j-qy/CHANGE.md b/weixin4j-qy/CHANGE.md index c9265ee8..7a412571 100644 --- a/weixin4j-qy/CHANGE.md +++ b/weixin4j-qy/CHANGE.md @@ -52,4 +52,8 @@ * 2015-06-12 - + 新增企业号[登陆授权](src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java)API \ No newline at end of file + + 新增企业号[登陆授权](src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java)API + +* 2015-06-21 + + + **weixin4j-qy**:新增企业号[第三方应用API](src/main/java/com/foxinmy/weixin4j/qy/suite)。 \ No newline at end of file diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java index 2d3c523e..5f46f651 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java @@ -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 api文档 */ 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有查看权限,否则本次调用失败) *

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 26352ed9..a25d1286 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 @@ -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 企业号登录授权说明 + * @see 第三方应用授权说明 */ 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 企业号登陆授权 */ 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 应用套件授权 + */ + 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 ""; + } } 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 84338455..a3a8295c 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 @@ -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 api文档 */ 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); } } 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 new file mode 100644 index 00000000..6654fd3f --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java @@ -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 第三方应用授权 + */ +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 + * 设置套件授权配置 + */ + 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(); + } +} 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 3810e486..1973f049 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 @@ -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 \ No newline at end of file +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 \ 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 0b260e4d..9306b319 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 @@ -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() + "]"; } } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/WeixinQyAccount.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/WeixinQyAccount.java index 41bb020e..3422ec21 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/WeixinQyAccount.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/WeixinQyAccount.java @@ -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 + "]"; } } 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 new file mode 100644 index 00000000..b4bcf9e9 --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/FileTicketProcessor.java @@ -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()); + } + } +} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteEventType.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteEventType.java new file mode 100644 index 00000000..a582fa91 --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteEventType.java @@ -0,0 +1,26 @@ +package com.foxinmy.weixin4j.qy.suite; + +/** + * 应用套件回调事件 + * + * @className SuiteEventType + * @author jy + * @date 2015年6月21日 + * @since JDK 1.7 + * @see 第三方回调协议 + */ +public enum SuiteEventType { + /** + * 推送ticket + */ + suite_ticket, + /** + * 变更授权 + */ + change_auth, + /** + * 取消授权 + */ + cancel_auth; +} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketMessage.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketMessage.java new file mode 100644 index 00000000..767bb5e9 --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketMessage.java @@ -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 + "]"; + } +} 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 new file mode 100644 index 00000000..538f7413 --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketProcessor.java @@ -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; +} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuitePreCodeCreator.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuitePreCodeCreator.java new file mode 100644 index 00000000..936f7beb --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuitePreCodeCreator.java @@ -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 获取应用套件预授权码 + * @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; + } +} 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 new file mode 100644 index 00000000..2356df0f --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuiteTokenCreator.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; + +/** + * 微信企业号应用套件凭证创建 + * + * @className WeixinTokenCreator + * @author jy + * @date 2015年6月17日 + * @since JDK 1.7 + * @see 获取应用套件凭证 + * @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; + } +} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinJSTicketCreator.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinJSTicketCreator.java index bec02e53..b672dd95 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinJSTicketCreator.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinJSTicketCreator.java @@ -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 - * 公众平台的access_token - */ - public WeixinJSTicketCreator(TokenHolder weixinTokenHolder) { - this(ConfigUtil.getWeixinAccount().getId(), weixinTokenHolder); - } - - /** - * 企业号的的access_token * + * @param corpid + * 企业号ID * @param weixinTokenHolder + * 企业号的的access_token */ 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")); diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinProviderTokenCreator.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinProviderTokenCreator.java index d7778da3..e54c4848 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinProviderTokenCreator.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinProviderTokenCreator.java @@ -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")); diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTokenCreator.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTokenCreator.java index fb7eaac9..0b2a0b2a 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTokenCreator.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTokenCreator.java @@ -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() { 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 new file mode 100644 index 00000000..60c3d277 --- /dev/null +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/type/URLConsts.java @@ -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"; +} diff --git a/weixin4j-qy/src/main/resources/weixin4j.properties b/weixin4j-qy/src/main/resources/weixin4j.properties index b8f0b2a7..ee64af0f 100644 --- a/weixin4j-qy/src/main/resources/weixin4j.properties +++ b/weixin4j-qy/src/main/resources/weixin4j.properties @@ -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= \ No newline at end of file +# \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= \ No newline at end of file diff --git a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java index 9b86f857..3f2f573a 100644 --- a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java +++ b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java @@ -5,9 +5,11 @@ import org.junit.Before; import org.junit.Test; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.qy.token.WeixinTokenCreator; import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.token.TokenHolder; +import com.foxinmy.weixin4j.util.ConfigUtil; /** * token测试 @@ -23,7 +25,9 @@ public class TokenTest { @Before public void setUp() { - tokenHolder = new TokenHolder(new WeixinTokenCreator(), + WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount(); + tokenHolder = new TokenHolder(new WeixinTokenCreator( + weixinAccount.getId(), weixinAccount.getSecret()), new FileTokenStorager()); } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/TransferCustomerResponse.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/TransferCustomerResponse.java index 8bb6d743..7318dec3 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/TransferCustomerResponse.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/TransferCustomerResponse.java @@ -17,12 +17,12 @@ public class TransferCustomerResponse implements WeixinResponse { */ private String kfAccount; - public String getKfAccount() { - return kfAccount; + public TransferCustomerResponse(String kfAccount) { + this.kfAccount = kfAccount; } - public void setKfAccount(String kfAccount) { - this.kfAccount = kfAccount; + public String getKfAccount() { + return kfAccount; } @Override