View Javadoc
1   package com.foxinmy.weixin4j.qy.api;
2   
3   import java.io.InputStream;
4   import java.util.ArrayList;
5   import java.util.List;
6   
7   import com.alibaba.fastjson.JSON;
8   import com.alibaba.fastjson.JSONArray;
9   import com.alibaba.fastjson.JSONObject;
10  import com.foxinmy.weixin4j.exception.WeixinException;
11  import com.foxinmy.weixin4j.http.weixin.ApiResult;
12  import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
13  import com.foxinmy.weixin4j.model.Token;
14  import com.foxinmy.weixin4j.qy.model.OUserInfo;
15  import com.foxinmy.weixin4j.qy.model.Party;
16  import com.foxinmy.weixin4j.qy.model.User;
17  import com.foxinmy.weixin4j.qy.type.InviteType;
18  import com.foxinmy.weixin4j.qy.type.UserStatus;
19  import com.foxinmy.weixin4j.token.TokenManager;
20  import com.foxinmy.weixin4j.util.NameValue;
21  import com.foxinmy.weixin4j.util.StringUtil;
22  
23  /**
24   * 成员API
25   * 
26   * @className UserApi
27   * @author jinyu(foxinmy@gmail.com)
28   * @date 2014年11月19日
29   * @since JDK 1.6
30   * @see com.foxinmy.weixin4j.qy.model.User
31   * @see <a href= "http://work.weixin.qq.com/api/doc#10018">管理成员说明</a>
32   */
33  public class UserApi extends QyApi {
34  	private final MediaApi mediaApi;
35  	private final PartyApi partyApi;
36  	private final TokenManager tokenManager;
37  
38  	public UserApi(TokenManager tokenManager) {
39  		this.tokenManager = tokenManager;
40  		this.mediaApi = new MediaApi(tokenManager);
41  		this.partyApi = new PartyApi(tokenManager);
42  	}
43  
44  	/**
45  	 * 创建成员
46  	 * 
47  	 * @param user
48  	 *            成员对象
49  	 * @see com.foxinmy.weixin4j.qy.model.User
50  	 * @see <a href= "http://work.weixin.qq.com/api/doc#10018"> 创建成员说明</a>
51  	 * @return 处理结果
52  	 * @throws WeixinException
53  	 */
54  	public ApiResult createUser(User user) throws WeixinException {
55  		String user_create_uri = getRequestUri("user_create_uri");
56  		return excute(user_create_uri, user, null);
57  	}
58  
59  	/**
60  	 * 创建成员
61  	 * 
62  	 * @param user
63  	 *            成员对象
64  	 * @param avatar
65  	 *            头像文件 可为空
66  	 * @see com.foxinmy.weixin4j.qy.model.User
67  	 * @see <a href= "http://work.weixin.qq.com/api/doc#10018"> 创建成员说明</a>
68  	 * @return 处理结果
69  	 * @throws WeixinException
70  	 */
71  	public ApiResult createUser(User user, InputStream avatar)
72  			throws WeixinException {
73  		String user_create_uri = getRequestUri("user_create_uri");
74  		return excute(user_create_uri, user, avatar);
75  	}
76  
77  	/**
78  	 * 更新用户(如果非必须的字段未指定 则不更新该字段之前的设置值)
79  	 * 
80  	 * @param user
81  	 *            成员对象
82  	 * @see com.foxinmy.weixin4j.qy.model.User
83  	 * @see <a href= "http://work.weixin.qq.com/api/doc#10020"> 更新成员说明</a>
84  	 * @return 处理结果
85  	 * @throws WeixinException
86  	 */
87  	public ApiResult updateUser(User user) throws WeixinException {
88  		String user_update_uri = getRequestUri("user_update_uri");
89  		return excute(user_update_uri, user, null);
90  	}
91  
92  	/**
93  	 * 更新用户(如果非必须的字段未指定 则不更新该字段之前的设置值)
94  	 * 
95  	 * @param user
96  	 *            成员对象
97  	 * @param avatar
98  	 *            头像文件
99  	 * @see com.foxinmy.weixin4j.qy.model.User
100 	 * @see <a href= "http://work.weixin.qq.com/api/doc#10020"> 更新成员说明</a>
101 	 * @return 处理结果
102 	 * @throws WeixinException
103 	 */
104 	public ApiResult updateUser(User user, InputStream avatar)
105 			throws WeixinException {
106 		String user_update_uri = getRequestUri("user_update_uri");
107 		return excute(user_update_uri, user, avatar);
108 	}
109 
110 	private ApiResult excute(String uri, User user, InputStream avatar)
111 			throws WeixinException {
112 		JSONObject obj = (JSONObject) JSON.toJSON(user);
113 		Object val = obj.remove("extattr");
114 		if (val != null) {
115 			JSONObject attrs = new JSONObject();
116 			attrs.put("attrs", val);
117 			obj.put("extattr", attrs);
118 		}
119 		val = obj.remove("status");
120 		if (val != null) {
121 			obj.put("enable", val);
122 		}
123 		if (avatar != null) {
124 			obj.put("avatar_mediaid", mediaApi.uploadMedia(0, avatar, null));
125 		} else {
126 			obj.put("avatar_mediaid", obj.remove("avatar"));
127 		}
128 		Token token = tokenManager.getCache();
129 		WeixinResponse response = weixinExecutor.post(
130 				String.format(uri, token.getAccessToken()), obj.toJSONString());
131 		return response.getAsResult();
132 	}
133 
134 	/**
135 	 * 获取成员
136 	 * 
137 	 * @param userid
138 	 *            成员唯一ID
139 	 * @see com.foxinmy.weixin4j.qy.model.User
140 	 * @see <a href= "http://work.weixin.qq.com/api/doc#10019">获取成员说明</a>
141 	 * @return 成员对象
142 	 * @throws WeixinException
143 	 */
144 	public User getUser(String userid) throws WeixinException {
145 		String user_get_uri = getRequestUri("user_get_uri");
146 		Token token = tokenManager.getCache();
147 		WeixinResponse response = weixinExecutor.get(String.format(
148 				user_get_uri, token.getAccessToken(), userid));
149 		JSONObject obj = response.getAsJson();
150 		Object attrs = obj.remove("extattr");
151 		User user = JSON.toJavaObject(obj, User.class);
152 		if (attrs != null) {
153 			user.setExtattr(JSON.parseArray(
154 					((JSONObject) attrs).getString("attrs"), NameValue.class));
155 		}
156 		return user;
157 	}
158 
159 	/**
160 	 * 根据code获取用户信息
161 	 * 
162 	 * @param code
163 	 *            通过员工授权获取到的code,每次员工授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期
164 	 * @see com.foxinmy.weixin4j.qy.model.User
165 	 * @return 成员对象
166 	 * @see {@link #getUser(String)}
167 	 * @see {@link #getUserIdByCode(String)}
168 	 * @see <a href= "http://work.weixin.qq.com/api/doc#10028/根据code获取成员信息">
169 	 *      oauth授权获取用户信息</a>
170 	 * @throws WeixinException
171 	 */
172 	public User getUserByCode(String code) throws WeixinException {
173 		JSONObject result = getUserIdByCode(code);
174 		if (result.containsKey("user_ticket")) {
175 			String user_ticket_detail_uri = getRequestUri("user_ticket_detail_uri");
176 			Token token = tokenManager.getCache();
177 			WeixinResponse response = weixinExecutor.post(
178 					String.format(user_ticket_detail_uri,
179 							token.getAccessToken()),
180 					String.format("{\"user_ticket\":\"%s\"}",
181 							result.getString("user_ticket")));
182 			JSONObject obj = response.getAsJson();
183 			Object attrs = obj.remove("extattr");
184 			User user = JSON.toJavaObject(obj, User.class);
185 			if (attrs != null) {
186 				user.setExtattr(JSON.parseArray(
187 						((JSONObject) attrs).getString("attrs"),
188 						NameValue.class));
189 			}
190 			return user;
191 		} else {
192 			String userId = result.getString("UserId");
193 			if (StringUtil.isBlank(userId)) {
194 				userId = openid2userid(result.getString("OpenId"));
195 			}
196 			return getUser(userId);
197 		}
198 	}
199 
200 	/**
201 	 * 根据code获取成员ID信息
202 	 * 
203 	 * @param code
204 	 *            通过员工授权获取到的code,每次员工授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期
205 	 * @return 换取结果
206 	 * @see <a href= "https://work.weixin.qq.com/api/doc#10028">
207 	 *      oauth授权获取用户信息</a>
208 	 * @throws WeixinException
209 	 */
210 	public JSONObject getUserIdByCode(String code) throws WeixinException {
211 		String user_getid_uri = getRequestUri("user_getid_uri");
212 		Token token = tokenManager.getCache();
213 		WeixinResponse response = weixinExecutor.get(String.format(
214 				user_getid_uri, token.getAccessToken(), code));
215 		return response.getAsJson();
216 	}
217 
218 	/**
219 	 * 获取企业号管理员登录信息
220 	 * 
221 	 * @param authCode
222 	 *            oauth2.0授权企业号管理员登录产生的code
223 	 * @return 登陆信息
224 	 * @see <a href=
225 	 *      "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">
226 	 *      授权获取企业号管理员登录信息</a>
227 	 * @see com.foxinmy.weixin4j.qy.model.OUserInfo
228 	 * @throws WeixinException
229 	 */
230 	public OUserInfo getOUserInfoByCode(String authCode) throws WeixinException {
231 		Token token = tokenManager.getCache();
232 		String oauth_logininfo_uri = getRequestUri("oauth_logininfo_uri");
233 		WeixinResponse response = weixinExecutor.post(
234 				String.format(oauth_logininfo_uri, token.getAccessToken()),
235 				String.format("{\"auth_code\":\"%s\"}", authCode));
236 		return JSON.parseObject(response.getAsString(), OUserInfo.class);
237 	}
238 
239 	/**
240 	 * 获取部门成员
241 	 * 
242 	 * @param partyId
243 	 *            部门ID
244 	 * @param fetchChild
245 	 *            是否递归获取子部门下面的成员
246 	 * @param userStatus
247 	 *            成员状态 status可叠加 未填写则默认为未关注(4)
248 	 * @param findDetail
249 	 *            是否获取详细信息
250 	 * @see com.foxinmy.weixin4j.qy.model.User
251 	 * @see <a href= "https://work.weixin.qq.com/api/doc#10061"> 获取部门成员说明</a>
252 	 * @return 成员列表
253 	 * @throws WeixinException
254 	 */
255 	public List<User> listUser(int partyId, boolean fetchChild,
256 			UserStatus userStatus, boolean findDetail) throws WeixinException {
257 		String user_list_uri = findDetail ? getRequestUri("user_list_uri")
258 				: getRequestUri("user_slist_uri");
259 		Token token = tokenManager.getCache();
260 		if (userStatus == null) {
261 			userStatus = UserStatus.UNFOLLOW;
262 		}
263 		WeixinResponse response = weixinExecutor.get(String.format(
264 				user_list_uri, token.getAccessToken(), partyId, fetchChild ? 1
265 						: 0, userStatus.getVal()));
266 		List<User> list = null;
267 		if (findDetail) {
268 			JSONArray arrays = response.getAsJson().getJSONArray("userlist");
269 			list = new ArrayList<User>(arrays.size());
270 			for (int i = 0; i < arrays.size(); i++) {
271 				JSONObject obj = arrays.getJSONObject(i);
272 				Object attrs = obj.remove("extattr");
273 				User user = JSON.toJavaObject(obj, User.class);
274 				if (attrs != null) {
275 					user.setExtattr(JSON.parseArray(
276 							((JSONObject) attrs).getString("attrs"),
277 							NameValue.class));
278 				}
279 				list.add(user);
280 			}
281 		} else {
282 			list = JSON.parseArray(response.getAsJson().getString("userlist"),
283 					User.class);
284 		}
285 		return list;
286 	}
287 
288 	/**
289 	 * 获取部门下所有状态成员(不进行递归)
290 	 * 
291 	 * @param partyId
292 	 *            部门ID
293 	 * @see {@link #listUser(int, boolean, UserStatus,boolean)}
294 	 * @return 成员列表
295 	 * @throws WeixinException
296 	 */
297 	public List<User> listUser(int partyId) throws WeixinException {
298 		return listUser(partyId, false, UserStatus.BOTH, false);
299 	}
300 
301 	/**
302 	 * 获取权限范围内的所有成员列表
303 	 * 
304 	 * @param userStatus
305 	 *            成员状态 未填写则默认为全部状态下的成员
306 	 * @return 成员列表
307 	 * @see {@link #listUser(int, boolean, UserStatus,boolean)}
308 	 * @see {@link PartyApi#listParty(int)}
309 	 * @throws WeixinException
310 	 */
311 	public List<User> listAllUser(UserStatus userStatus) throws WeixinException {
312 		List<User> users = null;
313 		List<Party> parties = partyApi.listParty(0);
314 		if (!parties.isEmpty()) {
315 			if (userStatus == null) {
316 				userStatus = UserStatus.BOTH;
317 			}
318 			users = new ArrayList<User>();
319 			for (Party party : parties) {
320 				users.addAll(listUser(party.getId(), true, userStatus, true));
321 			}
322 		}
323 		return users;
324 	}
325 
326 	/**
327 	 * 删除成员
328 	 * 
329 	 * @param userid
330 	 *            成员ID
331 	 * @see <a href= "https://work.weixin.qq.com/api/doc#10030"> 删除成员说明</a>
332 	 * @return 处理结果
333 	 * @throws WeixinException
334 	 */
335 	public ApiResult deleteUser(String userid) throws WeixinException {
336 		String user_delete_uri = getRequestUri("user_delete_uri");
337 		Token token = tokenManager.getCache();
338 		WeixinResponse response = weixinExecutor.get(String.format(
339 				user_delete_uri, token.getAccessToken(), userid));
340 		return response.getAsResult();
341 	}
342 
343 	/**
344 	 * 批量删除成员
345 	 * 
346 	 * @param userIds
347 	 *            成员列表
348 	 * @see <a href= "https://work.weixin.qq.com/api/doc#10060" >批量删除成员说明</a>
349 	 * @return 处理结果
350 	 * @throws WeixinException
351 	 */
352 	public ApiResult batchDeleteUser(List<String> userIds)
353 			throws WeixinException {
354 		JSONObject obj = new JSONObject();
355 		obj.put("useridlist", userIds);
356 		String user_delete_uri = getRequestUri("user_batchdelete_uri");
357 		Token token = tokenManager.getCache();
358 		WeixinResponse response = weixinExecutor.post(
359 				String.format(user_delete_uri, token.getAccessToken()),
360 				obj.toJSONString());
361 		return response.getAsResult();
362 	}
363 
364 	/**
365 	 * 开启二次验证成功时调用(管理员须拥有userid对应员工的管理权限)
366 	 * 
367 	 * @param userid
368 	 *            成员ID
369 	 * @return 调用结果
370 	 * @see <a href= "https://work.weixin.qq.com/api/doc#11378"> 二次验证说明</a>
371 	 * @throws WeixinException
372 	 */
373 	public ApiResult authsucc(String userId) throws WeixinException {
374 		String user_authsucc_uri = getRequestUri("user_authsucc_uri");
375 		Token token = tokenManager.getCache();
376 		WeixinResponse response = weixinExecutor.get(String.format(
377 				user_authsucc_uri, token.getAccessToken(), userId));
378 		return response.getAsResult();
379 	}
380 
381 	/**
382 	 * 邀请成员关注(管理员须拥有该成员的查看权限)
383 	 * 
384 	 * @param userId
385 	 *            成员ID
386 	 * @param tips
387 	 *            推送到微信上的提示语(只有认证号可以使用)。当使用微信推送时,该字段默认为“请关注XXX企业号”,邮件邀请时,该字段无效。
388 	 * @return 邀请类型
389 	 * @see <a href=
390 	 *      "http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E9.82.80.E8.AF.B7.E6.88.90.E5.91.98.E5.85.B3.E6.B3.A8">
391 	 *      邀请成员关注说明</a>
392 	 * @throws WeixinException
393 	 */
394 	public InviteType inviteUser(String userId, String tips)
395 			throws WeixinException {
396 		JSONObject obj = new JSONObject();
397 		obj.put("userid", userId);
398 		obj.put("invite_tips", tips);
399 		String invite_user_uri = getRequestUri("invite_user_uri");
400 		Token token = tokenManager.getCache();
401 		WeixinResponse response = weixinExecutor.post(
402 				String.format(invite_user_uri, token.getAccessToken()),
403 				obj.toJSONString());
404 		int type = response.getAsJson().getIntValue("type");
405 		if (type == 1) {
406 			return InviteType.WEIXIN;
407 		} else if (type == 2) {
408 			return InviteType.EMAIL;
409 		} else {
410 			return null;
411 		}
412 	}
413 
414 	/**
415 	 * userid转换成openid:该接口使用场景为微信支付、微信红包和企业转账,企业号用户在使用微信支付的功能时,
416 	 * 需要自行将企业号的userid转成openid。 在使用微信红包功能时,需要将应用id和userid转成appid和openid才能使用。
417 	 * 
418 	 * @param userid
419 	 *            企业号内的成员id 必填
420 	 * @param agentid
421 	 *            需要发送红包的应用ID,若只是使用微信支付和企业转账,则无需该参数 传入0或负数则忽略
422 	 * @return 结果数组 第一个元素为对应的openid 第二个元素则为应用的appid(如果有)
423 	 * @throws WeixinException
424 	 * @see <a href= "https://work.weixin.qq.com/api/doc#11279">
425 	 *      userid与openid互换</a>
426 	 */
427 	public String[] userid2openid(String userid, int agentid)
428 			throws WeixinException {
429 		JSONObject obj = new JSONObject();
430 		obj.put("userid", userid);
431 		if (agentid > 0) {
432 			obj.put("agentid", agentid);
433 		}
434 		String userid2openid_uri = getRequestUri("userid2openid_uri");
435 		WeixinResponse response = weixinExecutor
436 				.post(String.format(userid2openid_uri,
437 						tokenManager.getAccessToken()), obj.toJSONString());
438 		obj = response.getAsJson();
439 		return new String[] { obj.getString("openid"), obj.getString("appid") };
440 	}
441 
442 	/**
443 	 * openid转换成userid:该接口主要应用于使用微信支付、微信红包和企业转账之后的结果查询,
444 	 * 开发者需要知道某个结果事件的openid对应企业号内成员的信息时,可以通过调用该接口进行转换查询。
445 	 * 
446 	 * @param openid
447 	 *            在使用微信支付、微信红包和企业转账之后,返回结果的openid
448 	 * @return 该openid在企业号中对应的成员userid
449 	 * @throws WeixinException
450 	 * @see <a href= "https://work.weixin.qq.com/api/doc#11279">
451 	 *      userid与openid互换</a>
452 	 */
453 	public String openid2userid(String openid) throws WeixinException {
454 		String openid2userid_uri = getRequestUri("openid2userid_uri");
455 		WeixinResponse response = weixinExecutor
456 				.post(String.format(openid2userid_uri,
457 						tokenManager.getAccessToken()),
458 						String.format("{\"openid\": \"%s\"}", openid));
459 		return response.getAsJson().getString("userid");
460 	}
461 }