主要新增了企业号的第三方应用API
This commit is contained in:
parent
692a2b8129
commit
dd1fcaa598
@ -331,4 +331,10 @@
|
||||
|
||||
+ 修缮token实现机制
|
||||
|
||||
+ **weixin4j-qy**: 新增企业号[登陆授权](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java)API
|
||||
+ **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)。
|
||||
@ -72,8 +72,6 @@ weixin4j
|
||||
------
|
||||
* 公众号第三方服务应用
|
||||
|
||||
* 企业号第三方应用
|
||||
|
||||
* 硬件设备 & 摇一摇周边
|
||||
|
||||
* 微信小店
|
||||
|
||||
@ -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 <a href="http://qydev.weixin.qq.com/wiki/index.php">微信企业号API文档</a>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
@ -486,10 +486,14 @@
|
||||
<code>43011</code>
|
||||
<text>需要企业授权</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>43013</code>
|
||||
<text>应用对成员不可见</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>44001</code>
|
||||
<desc>empty media data</desc>
|
||||
<text>空白的二进制数据</text>
|
||||
<text>多媒体文件为空</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>44002</code>
|
||||
@ -859,7 +863,7 @@
|
||||
</error>
|
||||
<error>
|
||||
<code>60125</code>
|
||||
<text>部门名字长度超过限制</text>
|
||||
<text>非法部门名字,长度超过限制、重名等</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>60126</code>
|
||||
|
||||
@ -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";
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ public class Token implements Serializable {
|
||||
@JSONField(name = "expires_in")
|
||||
private int expiresIn;
|
||||
/**
|
||||
* token创建的时间 只在FileTokenHolder模式下有效
|
||||
* token创建的时间 只在FileTokenStorager模式下有效
|
||||
*/
|
||||
private long time;
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发货通知
|
||||
*
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传媒体文件
|
||||
*
|
||||
|
||||
@ -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 <a href="http://mp.weixin.qq.com/wiki/index.php">api文档</a>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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">微信登陆</a>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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<PrePay>() {
|
||||
});
|
||||
@ -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<com.foxinmy.weixin4j.mp.payment.v3.Order>() {
|
||||
});
|
||||
|
||||
@ -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<RefundDetail> refundList;
|
||||
|
||||
protected RefundRecord() {
|
||||
|
||||
@ -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
|
||||
* <font color="red">公众平台的access_token</font>
|
||||
*/
|
||||
public WeixinJSTicketCreator(TokenHolder weixinTokenHolder) {
|
||||
this(ConfigUtil.getWeixinAccount().getId(), weixinTokenHolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* jssdk
|
||||
*
|
||||
* @param appid
|
||||
* appid
|
||||
* 公众号的appid
|
||||
* @param weixinTokenHolder
|
||||
* <font color="red">公众平台的access_token</font>
|
||||
*/
|
||||
@ -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"));
|
||||
|
||||
@ -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<Token>() {
|
||||
|
||||
@ -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";
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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)");
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
@ -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));*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,4 +52,8 @@
|
||||
|
||||
* 2015-06-12
|
||||
|
||||
+ 新增企业号[登陆授权](src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java)API
|
||||
+ 新增企业号[登陆授权](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)。
|
||||
@ -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=
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user