package com.usoftchina.qywx.sdk; import com.usoftchina.qywx.sdk.config.Agent; import com.usoftchina.qywx.sdk.config.QywxProperties; import com.usoftchina.qywx.sdk.dto.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; import org.springframework.ui.ModelMap; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; /** * 通讯录管理 * * @author yingp */ public class AddrBookSdk extends BaseSdk { /** * 通讯录管理私钥 *

使用应用secret只能进行“查询”、“邀请”等非写操作,而且只能操作应用可见范围内的通讯录

*/ public final static String ADDRESS_BOOK_AGENT_CODE = "AddressBook"; private final Logger logger = LoggerFactory.getLogger(AddrBookSdk.class); public AddrBookSdk(QywxProperties properties) { super(properties); } /** * 是否启用 * * @return */ public boolean enabled() { Agent agent = getAgentMap().get(ADDRESS_BOOK_AGENT_CODE); return null != agent && null != agent.getSecret(); } /** * sdk是否只有读权限 * * @return */ public boolean isReadonly() { return enabled() && getAgentMap().get(ADDRESS_BOOK_AGENT_CODE).isReadonly(); } /** * 创建成员 * * @param req */ public void createUser(CreateUserReq req) { tryAndIgnoreSystemError(() -> restTemplate.postForEntity(baseUrl + "/cgi-bin/user/create?access_token={access_token}", req.build(), BaseResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))) ); } /** * 读取成员 * * @param userId 成员UserID。对应管理端的帐号,企业内必须唯一。不区分大小写,长度为1~64个字节 */ public GetUserResp getUser(String userId) { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/get?access_token={access_token}&userid={userid}", GetUserResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)).addAttribute("userid", userId)); assertOK(resp); return resp.getBody(); } /** * 更新成员 * * @param req */ public void updateUser(UpdateUserReq req) { tryAndIgnoreSystemError(() -> restTemplate.postForEntity(baseUrl + "/cgi-bin/user/update?access_token={access_token}", req.build(), BaseResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))) ); } /** * 删除成员 * * @param userId 成员UserID。对应管理端的帐号 */ public void deleteUser(String userId) { tryAndIgnoreSystemError(() -> restTemplate.getForEntity(baseUrl + "/cgi-bin/user/delete?access_token={access_token}&userid={userid}", BaseResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)).addAttribute("userid", userId)) ); } /** * 批量删除成员 * * @param userIdList 成员UserID列表。对应管理端的帐号。最多支持200个。若存在无效UserID,直接返回错误 */ public void deleteUser(List userIdList) { tryAndIgnoreSystemError(() -> restTemplate.postForEntity(baseUrl + "/cgi-bin/user/batchdelete?access_token={access_token}", new ModelMap("useridlist", userIdList), BaseResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))) ); } /** * 获取部门成员 * * @param departmentId 部门ID * @param fetchChild 是否递归获取子部门下面的成员:1-递归获取,0-只获取本部门 * 企业微信升级,方法不可用 */ @Deprecated public List getSimpleUserList(Integer departmentId, boolean fetchChild) { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/simplelist?access_token={access_token}&department_id={department_id}&fetch_child={fetch_child}", GetSimpleUserListResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)) .addAttribute("department_id", departmentId) .addAttribute("fetch_child", fetchChild ? 1 : 0)); assertOK(resp); return resp.getBody().getUserlist(); } /** * 获取部门成员详情 * * @param departmentId 部门ID * @param fetchChild 是否递归获取子部门下面的成员:1-递归获取,0-只获取本部门 * 企业微信升级,方法不可用 * @return */ @Deprecated public List getUserList(Integer departmentId, boolean fetchChild) { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/list?access_token={access_token}&department_id={department_id}&fetch_child={fetch_child}", GetUserListResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)) .addAttribute("department_id", departmentId) .addAttribute("fetch_child", fetchChild ? 1 : 0)); assertOK(resp); return resp.getBody().getUserlist(); } /** * 获取部门成员详情 * @param cursor 用于分页查询的游标,字符串类型,由上一次调用返回,首次调用不填 * limit 分页,预期请求的数据量,取值范围 1 ~ 10000 默认10000 * @return */ public List getUserIdList(List userList,String cursor) { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/list_id?access_token={access_token}&cursor={cursor}&limit={limit}", GetSimpleUserIDListResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)) .addAttribute("cursor", cursor) .addAttribute("limit", 10000)); assertOK(resp); if(StringUtils.hasText(resp.getBody().getNext_cursor())){ System.out.println("Next_cursor:"+resp.getBody().getNext_cursor()); return getUserIdList(resp.getBody().getDept_user(),resp.getBody().getNext_cursor()); }else { userList.addAll(resp.getBody().getDept_user()); return userList; } } /** * userid转openid *

该接口使用场景为企业支付,在使用企业红包和向员工付款时,需要自行将企业微信的userid转成openid。

* * @param userId * @return */ public String getOpenId(String userId) { ResponseEntity resp = restTemplate.postForEntity(baseUrl + "/cgi-bin/user/convert_to_openid?access_token={access_token}", new ModelMap("userid", userId), GetOpenIdResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))); assertOK(resp); return resp.getBody().getOpenid(); } /** * 二次验证 *

* 企业在开启二次验证时,必须在管理端填写企业二次验证页面的url。 * 当成员登录企业微信或关注微工作台(原企业号)加入企业时,会自动跳转到企业的验证页面。在跳转到企业的验证页面时,会带上如下参数:code=CODE。 * 企业收到code后,使用“通讯录同步助手”调用接口“根据code获取成员信息”获取成员的userid。然后在验证成员信息成功后,调用如下接口即可让成员成功加入企业 *

* * @param userId */ public void authSuccess(String userId) { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/authsucc?access_token={access_token}&userid={userid}", BaseResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)) .addAttribute("userid", userId)); assertOK(resp); } /** * 邀请成员 *

企业可通过接口批量邀请成员使用企业微信,邀请后将通过短信或邮件下发通知

* * @param req */ public InviteResp invite(InviteReq req) { ResponseEntity resp = restTemplate.postForEntity(baseUrl + "/cgi-bin/batch/invite?access_token={access_token}", req.build(), InviteResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))); assertOK(resp); return resp.getBody(); } /** * 获取加入企业二维码 * * @param type 尺寸 * @return 二维码链接,有效期7天 */ public String getJoinQrCode(QrCodeType type) { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/corp/get_join_qrcode?access_token={access_token}&size_type={size_type}", GetJoinQrCodeResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)) .addAttribute("size_type", type.code)); assertOK(resp); return resp.getBody().getJoin_qrcode(); } /** * qrcode尺寸类型 */ public enum QrCodeType { T_171_171(1), T_399_399(2), T_741_741(3), T_2052_2052(4); private final int code; QrCodeType(int code) { this.code = code; } public int getCode() { return code; } } /** * 创建部门 * * @param req * @return 部门ID */ public Integer createDepartment(CreateDepartmentReq req) { ResponseEntity resp = tryAndIgnoreSystemError(() -> restTemplate.postForEntity(baseUrl + "/cgi-bin/department/create?access_token={access_token}", req.build(), CreateDepartmentResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))) ); return null == resp ? null : resp.getBody().getId(); } /** * 更新部门 * * @param req */ public void updateDepartment(UpdateDepartmentReq req) { tryAndIgnoreSystemError(() -> restTemplate.postForEntity(baseUrl + "/cgi-bin/department/update?access_token={access_token}", req.build(), BaseResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))) ); } /** * 删除部门 * * @param departmentId */ public void deleteDepartment(int departmentId) { tryAndIgnoreSystemError(() -> restTemplate.getForEntity(baseUrl + "/cgi-bin/department/delete?access_token={access_token}&id={id}", BaseResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)) .addAttribute("id", departmentId)) ); } /** * 获取部门 * 企业微信升级,方法不可用 * @param departmentId * @return */ @Deprecated public GetDepartmentListResp.Department getDepartment(int departmentId) { List departmentList = getDepartmentList(departmentId); if (!CollectionUtils.isEmpty(departmentList)) { for (GetDepartmentListResp.Department department : departmentList) { if (department.getId().equals(departmentId)) { return department; } } } return null; } /** * 获取部门,包括下级 * 企业微信升级,方法不可用 * @param departmentId * @return */ @Deprecated public List getDepartmentList(int departmentId) { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/department/list?access_token={access_token}&id={id}", GetDepartmentListResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)) .addAttribute("id", departmentId)); assertOK(resp); if (!CollectionUtils.isEmpty(resp.getBody().getDepartment())) { return resp.getBody().getDepartment(); } return null; } /** * 获取部门列表 * 企业微信升级,方法不可用 * @return */ @Deprecated public List getDepartmentList() { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/department/list?access_token={access_token}", GetDepartmentListResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))); assertOK(resp); return resp.getBody().getDepartment(); } /** * 获取部门列表 * * @return */ public List getSimpleDepartmentList() { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/department/simplelist?access_token={access_token}&id={id}", GetDepartmentSimpleListResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)) .addAttribute("id", 0)); assertOK(resp); return resp.getBody().getDepartment_id(); } /** * 获取部门列表 * * @return */ public List getSimpleDepartmentList(Integer departmentId) { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/department/simplelist?access_token={access_token}&id={id}", GetDepartmentSimpleListResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)) .addAttribute("id", departmentId)); assertOK(resp); return resp.getBody().getDepartment_id(); } /** * 获取访问用户身份 * * @param agentCode 应用编号 * @param code 授权码 */ public GetUserInfoResp getUserInfo(String agentCode, String code) { ResponseEntity resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/getuserinfo?access_token={access_token}&code={code}", GetUserInfoResp.class, new ModelMap("access_token", getAccessToken(agentCode)) .addAttribute("code", code)); assertOK(resp); return resp.getBody(); } /** * 获取用户UserID * * @param mobile 手机号 * */ public GetUserInfoResp getUserInfoByMobile(String mobile) { ResponseEntity resp = restTemplate.postForEntity(baseUrl + "/cgi-bin/user/getuserid?access_token={access_token}&debug=1", new ModelMap("mobile", mobile), GetUserInfoResp.class, new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))); return resp.getBody(); } /** * 获取用户openid * access_token 代开发企业应用的access_token * */ public GetUserOpenIDListResp convert_openUserId(List userList) { logger.info("convert_openUserId:{}",String.join("," , userList)); ResponseEntity resp = restTemplate.postForEntity( baseUrl + "/cgi-bin/batch/userid_to_openuserid?access_token={access_token}", new ModelMap("userid_list", userList), GetUserOpenIDListResp.class, new ModelMap("access_token", getAccessToken(null))); logger.info("convert_openUserId--:{}",resp.getBody()); assertOK(resp); return resp.getBody(); } /** * 以下接口仅能获取企业内部openuserid * */ /* public List convert_openUserId(List userList) { List openUsers = new ArrayList<>(); for(String userId : userList) { try { GetUserOpenIDListResp.OpenUser openUser = new GetUserOpenIDListResp.OpenUser(); openUser.setUserid(userId); openUser.setOpen_userid(getOpenId(userId)); openUsers.add(openUser); } catch (Exception e) { logger.error("转换用户ID失败: {}", userId, e); // 失败时仍保留用户ID,但openid为null GetUserOpenIDListResp.OpenUser openUser = new GetUserOpenIDListResp.OpenUser(); openUser.setUserid(userId); openUsers.add(openUser); } } return openUsers; }*/ }