View Javadoc
1   package com.foxinmy.weixin4j.qy;
2   
3   import java.io.UnsupportedEncodingException;
4   import java.net.URLEncoder;
5   import java.util.HashMap;
6   import java.util.List;
7   import java.util.Map;
8   
9   import com.alibaba.fastjson.JSON;
10  import com.foxinmy.weixin4j.cache.CacheStorager;
11  import com.foxinmy.weixin4j.cache.FileCacheStorager;
12  import com.foxinmy.weixin4j.exception.WeixinException;
13  import com.foxinmy.weixin4j.model.Token;
14  import com.foxinmy.weixin4j.model.WeixinAccount;
15  import com.foxinmy.weixin4j.qy.api.ProviderApi;
16  import com.foxinmy.weixin4j.qy.api.SuiteApi;
17  import com.foxinmy.weixin4j.qy.model.OUserInfo;
18  import com.foxinmy.weixin4j.qy.model.WeixinQyAccount;
19  import com.foxinmy.weixin4j.qy.token.WeixinProviderTokenCreator;
20  import com.foxinmy.weixin4j.qy.type.LoginTargetType;
21  import com.foxinmy.weixin4j.qy.type.URLConsts;
22  import com.foxinmy.weixin4j.token.TicketManager;
23  import com.foxinmy.weixin4j.token.TokenManager;
24  import com.foxinmy.weixin4j.util.Consts;
25  import com.foxinmy.weixin4j.util.StringUtil;
26  import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
27  
28  /**
29   * 微信第三方应用接口实现
30   *
31   * @className WeixinSuiteProxy
32   * @author jinyu(foxinmy@gmail.com)
33   * @date 2015年6月22日
34   * @since JDK 1.6
35   * @see com.foxinmy.weixin4j.qy.api.SuiteApi
36   * @see <a href= "http://work.weixin.qq.com/api/doc#10968"> 企业号第三方应用</a>
37   */
38  public class WeixinSuiteProxy {
39  
40  	/**
41  	 * 每个套件授权不一样 suiteId - suiteApi
42  	 */
43  	private Map<String, SuiteApi> suiteMap;
44  	/**
45  	 * 供应商API:如登陆URL
46  	 */
47  	private ProviderApi providerApi;
48  	/**
49  	 * 企业号账号信息
50  	 */
51  	private final WeixinQyAccount weixinQyAccount;
52  
53  	/**
54  	 * 微信第三方套件接口实现(使用weixin4j.properties配置的account账号信息,
55  	 * 使用FileCacheStorager文件方式缓存TOKEN)
56  	 */
57  	public WeixinSuiteProxy() {
58  		this(new FileCacheStorager<Token>());
59  	}
60  
61  	/**
62  	 * 微信第三方套件接口实现(使用weixin4j.properties配置的account账号信息)
63  	 *
64  	 * @param cacheStorager
65  	 *            token管理
66  	 */
67  	public WeixinSuiteProxy(CacheStorager<Token> cacheStorager) {
68  		this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"),
69  				WeixinQyAccount.class), cacheStorager);
70  	}
71  
72  	/**
73  	 * 微信第三方套件接口实现
74  	 *
75  	 * @param weixinQyAccount
76  	 *            账号信息
77  	 * @param cacheStorager
78  	 *            token管理
79  	 */
80  	public WeixinSuiteProxy(WeixinQyAccount weixinQyAccount,
81  			CacheStorager<Token> cacheStorager) {
82  		if (weixinQyAccount == null) {
83  			throw new IllegalArgumentException(
84  					"weixinQyAccount must not be empty");
85  		}
86  		if (cacheStorager == null) {
87  			throw new IllegalArgumentException(
88  					"cacheStorager must not be empty");
89  		}
90  		this.weixinQyAccount = weixinQyAccount;
91  		List<WeixinAccount> suites = weixinQyAccount.getSuites();
92  		if (suites != null && !suites.isEmpty()) {
93  			this.suiteMap = new HashMap<String, SuiteApi>(suites.size());
94  			for (WeixinAccount suite : suites) {
95  				this.suiteMap.put(suite.getId(), new SuiteApi(
96  						new TicketManager(suite.getId(), suite.getSecret(),
97  								cacheStorager)));
98  			}
99  			this.suiteMap.put(null, suiteMap.get(suites.get(0).getId()));
100 		}
101 		if (StringUtil.isNotBlank(weixinQyAccount.getId())
102 				&& StringUtil.isNotBlank(weixinQyAccount.getProviderSecret())) {
103 			this.providerApi = new ProviderApi(
104 					new TokenManager(new WeixinProviderTokenCreator(
105 							weixinQyAccount.getId(), weixinQyAccount
106 									.getProviderSecret()), cacheStorager),
107 					cacheStorager);
108 		}
109 	}
110 
111 	/**
112 	 * 企业号信息
113 	 *
114 	 * @return
115 	 */
116 	public WeixinQyAccount getWeixinQyAccount() {
117 		return weixinQyAccount;
118 	}
119 
120 	/**
121 	 * 获取套件接口对象(只关注第一个套件
122 	 *
123 	 * @see com.foxinmy.weixin4j.qy.api.SuiteApi
124 	 * @return API实例
125 	 */
126 	public SuiteApi suite() {
127 		return this.suiteMap.get(null);
128 	}
129 
130 	/**
131 	 * 获取套件接口对象(多个套件
132 	 *
133 	 * @see com.foxinmy.weixin4j.qy.api.SuiteApi
134 	 * @param suiteId
135 	 *            套件ID
136 	 * @return API实例
137 	 */
138 	public SuiteApi suite(String suiteId) {
139 		return this.suiteMap.get(suiteId);
140 	}
141 
142 	/**
143 	 * 获取套件的预授权码 <font color="red">需先缓存ticket</font>
144 	 *
145 	 * @param suiteId
146 	 *            套件ID
147 	 * @return 预授权码
148 	 * @see #cacheSuiteTicket(String, String)
149 	 * @see com.foxinmy.weixin4j.qy.api.SuiteApi
150 	 * @see com.foxinmy.weixin4j.qy.api.SuiteApi#getTicketManager()
151 	 * @see com.foxinmy.weixin4j.qy.api.SuiteApi#getPreCodeManager()
152 	 * @throws WeixinException
153 	 */
154 	public String getPreSuiteTicket(String suiteId) throws WeixinException {
155 		SuiteApi suite = suite(suiteId);
156 		Token token = suite.getTicketManager().getTicket();
157 		if (token == null || StringUtil.isBlank(token.getAccessToken())) {
158 			throw new WeixinException("maybe oauth first?");
159 		}
160 		return suite.getPreCodeManager().getAccessToken();
161 	}
162 
163 	/**
164 	 * 缓存套件ticket
165 	 *
166 	 * @param suiteId
167 	 *            套件ID
168 	 * @param suiteTicket
169 	 *            套件ticket内容
170 	 * @see <a href= "http://work.weixin.qq.com/api/doc#10982/推送suite_ticket">
171 	 *      推送suite_ticket协议</a>
172 	 * @throws WeixinException
173 	 */
174 	public void cacheSuiteTicket(String suiteId, String suiteTicket)
175 			throws WeixinException {
176 		suite(suiteId).getTicketManager().cachingTicket(suiteTicket);
177 	}
178 
179 	/**
180 	 * 应用套件授权 <font color="red">需先缓存ticket</font> <li>
181 	 * redirectUri默认填写weixin4j.properties#suite.oauth.redirect.uri <li>
182 	 * state默认填写state
183 	 *
184 	 * @param suiteId
185 	 *            套件ID
186 	 * @see {@link #getSuiteAuthorizationURL(String, String,String)}
187 	 * @return 请求授权的URL
188 	 * @throws WeixinException
189 	 */
190 	public String getSuiteAuthorizationURL(String suiteId)
191 			throws WeixinException {
192 		String redirectUri = Weixin4jConfigUtil
193 				.getValue("suite.oauth.redirect.uri");
194 		return getSuiteAuthorizationURL(suiteId, redirectUri, "state");
195 	}
196 
197 	/**
198 	 * 应用套件授权 <font
199 	 * color="red">需先缓存ticket,在授权完成之后需要调用SuiteApi#exchangeAuthInfo方法
200 	 * ,否则无法缓存token相关导致后续的组件接口调用失败</font>
201 	 *
202 	 * @param suiteId
203 	 *            套件ID
204 	 * @param redirectUri
205 	 *            授权后重定向url
206 	 * @param state
207 	 *            回调后原样返回
208 	 * @see #cacheSuiteTicket(String, String)
209 	 * @see com.foxinmy.weixin4j.qy.api.SuiteApi
210 	 * @see com.foxinmy.weixin4j.qy.api.SuiteApi#getTicketManager()
211 	 * @see com.foxinmy.weixin4j.qy.api.SuiteApi#getPreCodeManager()
212 	 * @see com.foxinmy.weixin4j.qy.api.SuiteApi#exchangeAuthInfo(String)
213 	 * @see <a href="http://work.weixin.qq.com/api/doc#10974">企业号第三方应用套件授权</a>
214 	 * @return 请求授权的URL
215 	 * @throws WeixinException
216 	 */
217 	public String getSuiteAuthorizationURL(String suiteId, String redirectUri,
218 			String state) throws WeixinException {
219 		try {
220 			return String.format(URLConsts.SUITE_OAUTH_URL, suiteId,
221 					getPreSuiteTicket(suiteId),
222 					URLEncoder.encode(redirectUri, Consts.UTF_8.name()), state);
223 		} catch (UnsupportedEncodingException e) {
224 			;
225 		}
226 		return "";
227 	}
228 
229 	/**
230 	 * 第三方套件获取企业号管理员登录信息
231 	 *
232 	 * @param authCode
233 	 *            oauth2.0授权企业号管理员登录产生的code:通过成员授权获取到的code,每次成员授权带上的code将不一样,
234 	 *            code只能使用一次,5分钟未被使用自动过期
235 	 * @return 登陆信息
236 	 * @see com.foxinmy.weixin4j.qy.api.ProviderApi
237 	 * @see <a href=
238 	 *      "http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E4%BC%81%E4%B8%9A%E7%AE%A1%E7%90%86%E5%91%98%E7%99%BB%E5%BD%95%E4%BF%A1%E6%81%AF">
239 	 *      授权获取企业号管理员登录信息</a>
240 	 * @see com.foxinmy.weixin4j.qy.model.OUserInfo
241 	 * @throws WeixinException
242 	 */
243 	public OUserInfo getOUserInfoByCode(String authCode) throws WeixinException {
244 		return providerApi.getOUserInfoByCode(authCode);
245 	}
246 
247 	/**
248 	 * 获取登录企业号官网的url
249 	 *
250 	 * @param corpId
251 	 *            <font color="red">oauth授权的corpid</font>
252 	 * @param targetType
253 	 *            登录跳转到企业号后台的目标页面
254 	 * @param agentId
255 	 *            授权方应用id 小余1时则不传递
256 	 * @return 登陆URL
257 	 * @see com.foxinmy.weixin4j.qy.api.ProviderApi
258 	 * @see <a href=
259 	 *      "http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%99%BB%E5%BD%95%E4%BC%81%E4%B8%9A%E5%8F%B7%E5%AE%98%E7%BD%91%E7%9A%84url">
260 	 *      获取登录企业号官网的url</a>
261 	 * @throws WeixinException
262 	 */
263 	public String getLoginUrl(String corpId, LoginTargetType targetType,
264 			int agentId) throws WeixinException {
265 		return providerApi.getLoginUrl(corpId, targetType, agentId);
266 	}
267 
268 	/**
269 	 * 创建WeixinProxy对象
270 	 *
271 	 * @param suiteId
272 	 *            套件ID
273 	 * @param authCorpId
274 	 *            已授权的corpid
275 	 * @see com.foxinmy.weixin4j.qy.WeixinProxy
276 	 * @return
277 	 */
278 	public WeixinProxy getWeixinProxy(String suiteId, String authCorpId) {
279 		return new WeixinProxy(suite(suiteId).getPerTicketManager(authCorpId),
280 				suite(suiteId).getTokenManager());
281 	}
282 
283 	public final static String VERSION = Consts.VERSION;
284 }