View Javadoc
1   package com.foxinmy.weixin4j.mp;
2   
3   import java.io.UnsupportedEncodingException;
4   import java.net.URLEncoder;
5   import java.util.HashMap;
6   import java.util.Map;
7   
8   import com.alibaba.fastjson.JSON;
9   import com.foxinmy.weixin4j.cache.CacheStorager;
10  import com.foxinmy.weixin4j.cache.FileCacheStorager;
11  import com.foxinmy.weixin4j.exception.WeixinException;
12  import com.foxinmy.weixin4j.model.Token;
13  import com.foxinmy.weixin4j.model.WeixinAccount;
14  import com.foxinmy.weixin4j.mp.api.ComponentApi;
15  import com.foxinmy.weixin4j.mp.model.WeixinMpAccount;
16  import com.foxinmy.weixin4j.mp.type.URLConsts;
17  import com.foxinmy.weixin4j.token.TicketManager;
18  import com.foxinmy.weixin4j.util.Consts;
19  import com.foxinmy.weixin4j.util.StringUtil;
20  import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
21  
22  /**
23   * 微信第三方应用接口实现
24   *
25   * @className WeixinComponentProxy
26   * @author jinyu(foxinmy@gmail.com)
27   * @date 2016年7月5日
28   * @since JDK 1.6
29   * @see com.foxinmy.weixin4j.mp.api.ComponentApi
30   * @see <a href=
31   *      "https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318292&token=&lang=zh_CN">
32   *      公众号第三方应用</a>
33   */
34  public class WeixinComponentProxy {
35  
36  	/**
37  	 * 每个组件授权不一样 componentId - componentApi
38  	 */
39  	private Map<String, ComponentApi> componentMap;
40  	/**
41  	 * 微信账号信息
42  	 */
43  	private final WeixinMpAccount weixinMpAccount;
44  
45  	/**
46  	 * 微信第三方组件接口实现(使用weixin4j.properties配置的account#components账号信息,
47  	 * 使用FileCacheStorager文件方式缓存TOKEN)
48  	 */
49  	public WeixinComponentProxy() {
50  		this(new FileCacheStorager<Token>());
51  	}
52  
53  	/**
54  	 * 微信第三方组件接口实现(使用weixin4j.properties配置的account#components账号信息)
55  	 *
56  	 * @param cacheStorager
57  	 *            token管理
58  	 */
59  	public WeixinComponentProxy(CacheStorager<Token> cacheStorager) {
60  		this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), WeixinMpAccount.class), cacheStorager);
61  	}
62  
63  	/**
64  	 * 微信第三方组件接口实现
65  	 *
66  	 * @param weixinMpAccount
67  	 *            账号信息
68  	 * @param cacheStorager
69  	 *            token管理
70  	 */
71  	public WeixinComponentProxy(WeixinMpAccount weixinMpAccount, CacheStorager<Token> cacheStorager) {
72  		if (weixinMpAccount == null) {
73  			throw new IllegalArgumentException("weixinMpAccount must not be empty");
74  		}
75  		if (cacheStorager == null) {
76  			throw new IllegalArgumentException("cacheStorager must not be empty");
77  		}
78  		this.weixinMpAccount = weixinMpAccount;
79  		this.componentMap = new HashMap<String, ComponentApi>(weixinMpAccount.getComponents().size());
80  		for (WeixinAccount component : weixinMpAccount.getComponents()) {
81  			this.componentMap.put(component.getId(),
82  					new ComponentApi(new TicketManager(component.getId(), component.getSecret(), cacheStorager)));
83  		}
84  		this.componentMap.put(null, componentMap.get(weixinMpAccount.getComponents().get(0).getId()));
85  	}
86  
87  	/**
88  	 * 获取微信账号信息
89  	 *
90  	 * @return
91  	 */
92  	public WeixinMpAccount getWeixinMpAccount() {
93  		return this.weixinMpAccount;
94  	}
95  
96  	/**
97  	 * 获取组接口对象(只关注第一个组件
98  	 *
99  	 * @see com.foxinmy.weixin4j.mp.api.ComponentApi
100 	 * @return API实例
101 	 */
102 	public ComponentApi component() {
103 		return this.componentMap.get(null);
104 	}
105 
106 	/**
107 	 * 获取套件接口对象(多个组件
108 	 *
109 	 * @see com.foxinmy.weixin4j.mp.api.ComponentApi
110 	 * @param componentId
111 	 *            组件ID
112 	 * @return API实例
113 	 */
114 	public ComponentApi component(String componentId) {
115 		return this.componentMap.get(componentId);
116 	}
117 
118 	/**
119 	 * 获取组件的预授权码 <font color="red">需先缓存ticket</font>
120 	 *
121 	 * @param componentId
122 	 *            组件ID
123 	 * @return 预授权码
124 	 * @see #cacheComponentTicket(String, String)
125 	 * @see com.foxinmy.weixin4j.mp.api.ComponentApi
126 	 * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getTicketManager()
127 	 * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getPreCodeManager()
128 	 * @throws WeixinException
129 	 */
130 	public String getPreComponentTicket(String componentId) throws WeixinException {
131 		ComponentApi component = component(componentId);
132 		Token token = component.getTicketManager().getTicket();
133 		if (token == null || StringUtil.isBlank(token.getAccessToken())) {
134 			throw new WeixinException("maybe oauth first?");
135 		}
136 		return component.getPreCodeManager().getAccessToken();
137 	}
138 
139 	/**
140 	 * 缓存组件ticket
141 	 *
142 	 * @param componentId
143 	 *            组件ID
144 	 * @param componentTicket
145 	 *            组件ticket内容
146 	 * @throws WeixinException
147 	 */
148 	public void cacheComponentTicket(String componentId, String componentTicket) throws WeixinException {
149 		component(componentId).getTicketManager().cachingTicket(componentTicket);
150 	}
151 
152 	/**
153 	 * 应用组件授权 <font color="red">需先缓存ticket</font>
154 	 * <li>redirectUri默认填写weixin4j.properties#component.oauth.redirect.uri
155 	 * <li>state默认填写state
156 	 *
157 	 * @param componentId
158 	 *            组件ID
159 	 * @see {@link #getComponentAuthorizationURL(String, String,String)}
160 	 * @return 请求授权的URL
161 	 * @throws WeixinException
162 	 */
163 	public String getComponentAuthorizationURL(String componentId) throws WeixinException {
164 		String redirectUri = Weixin4jConfigUtil.getValue("component.oauth.redirect.uri");
165 		return getComponentAuthorizationURL(componentId, redirectUri, "state");
166 	}
167 
168 	/**
169 	 * 应用组件授权 <font color="red">需先缓存ticket,在授权完成之后需要调用ComponentApi#
170 	 * exchangeAuthorizerToken方法 ,否则无法缓存token相关导致后续的组件接口调用失败</font>
171 	 *
172 	 * @param componentId
173 	 *            组件ID
174 	 * @param redirectUri
175 	 *            授权后重定向url
176 	 * @param state
177 	 *            回调后原样返回
178 	 * @see #cacheComponentTicket(String, String)
179 	 * @see com.foxinmy.weixin4j.mp.api.ComponentApi
180 	 * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getTicketManager()
181 	 * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getPreCodeManager()
182 	 * @see com.foxinmy.weixin4j.mp.api.ComponentApi#exchangeAuthorizerToken(String)
183 	 * @see <a href=
184 	 *      "https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1453779503&token=&lang=zh_CN">
185 	 *      应用组件授权</a>
186 	 * @return 请求授权的URL
187 	 * @throws WeixinException
188 	 */
189 	public String getComponentAuthorizationURL(String componentId, String redirectUri, String state)
190 			throws WeixinException {
191 		try {
192 			return String.format(URLConsts.COMPONENT_OAUTH_URL, componentId, getPreComponentTicket(componentId),
193 					URLEncoder.encode(redirectUri, Consts.UTF_8.name()), state);
194 		} catch (UnsupportedEncodingException e) {
195 			;
196 		}
197 		return "";
198 	}
199 
200 	/**
201 	 * 创建WeixinProxy对象
202 	 *
203 	 * @param componentId
204 	 *            组件ID
205 	 * @param authAppId
206 	 *            已授权的appid
207 	 * @see com.foxinmy.weixin4j.mp.WeixinProxy
208 	 * @return
209 	 */
210 	public WeixinProxy getWeixinProxy(String componentId, String authAppId) {
211 		return new WeixinProxy(component(componentId).getRefreshTokenManager(authAppId),
212 				component(componentId).getTokenManager());
213 	}
214 
215 	public final static String VERSION = Consts.VERSION;
216 }