瀏覽代碼

#1078 完善企业微信外部联系人相关接口

- 完成ExternalContact基础三个接口
- 外部联系人变更事件的消息解析
- 外部联系人的属性,增加标记公司名称和标记电话号码,还有tag分类
- 企业微信API url修改优化
master
曹祖鹏 5 年之前
committed by Binary Wang
父節點
當前提交
90b5ca56c2
共有 15 個文件被更改,包括 393 次插入28 次删除
  1. +58
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
  2. +3
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
  3. +2
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java
  4. +7
    -11
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
  5. +41
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
  6. +20
    -8
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfo.java
  7. +58
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java
  8. +49
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java
  9. +20
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java
  10. +6
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
  11. +20
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java
  12. +12
    -0
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java
  13. +45
    -0
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
  14. +2
    -7
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java
  15. +50
    -1
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java

+ 58
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java 查看文件

@@ -0,0 +1,58 @@
package me.chanjar.weixin.cp.api;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo;

import java.util.List;

/**
* <pre>
* 外部联系人管理接口,企业微信的外部联系人的接口和通讯录接口已经拆离
* Created by Joe Cao on 2019/6/14
* </pre>
*
* @author <a href="https://github.com/JoeCao">JoeCao</a>
*/
public interface WxCpExternalContactService {
/**
* 获取外部联系人详情.
* <pre>
* 企业可通过此接口,根据外部联系人的userid,拉取外部联系人详情。权限说明:
* 企业需要使用外部联系人管理secret所获取的accesstoken来调用
* 第三方应用需拥有“企业客户”权限。
* 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。
* </pre>
*
* @param userId 外部联系人的userid
*/
WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException;

/**
* 获取外部联系人列表.
* <pre>
* 企业可通过此接口获取指定成员添加的客户列表。
* 客户是指配置了客户联系功能的成员所添加的外部联系人。
* 没有配置客户联系功能的成员,所添加的外部联系人将不会作为客户返回。
* 第三方应用需拥有“企业客户”权限。
* 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。
* </pre>
*
* @param userId 外部联系人的userid
* @return List of External wx id
*/
List<String> listExternalContacts(String userId) throws WxErrorException;


/**
* 企业和第三方服务商可通过此接口获取配置了客户联系功能的成员(Customer Contact)列表。
* <pre>
* 企业需要使用外部联系人管理secret所获取的accesstoken来调用(accesstoken如何获取?);
* 第三方应用需拥有“企业客户”权限。
* 第三方应用只能获取到可见范围内的配置了客户联系功能的成员
* </pre>
*
* @return List of CpUser id
*/
List<String> listFollowUser() throws WxErrorException;

}

+ 3
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java 查看文件

@@ -284,7 +284,9 @@ public interface WxCpService {
* 获取用户相关接口的服务类对象
*/
WxCpUserService getUserService();

WxCpExternalContactService getExternalContactService();

/**
* 获取群聊服务
*


+ 2
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java 查看文件

@@ -149,4 +149,6 @@ public interface WxCpUserService {
* @param userId 外部联系人的userid
*/
WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException;


}

+ 7
- 11
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java 查看文件

@@ -19,17 +19,7 @@ import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.cp.api.WxCpAgentService;
import me.chanjar.weixin.cp.api.WxCpChatService;
import me.chanjar.weixin.cp.api.WxCpDepartmentService;
import me.chanjar.weixin.cp.api.WxCpMediaService;
import me.chanjar.weixin.cp.api.WxCpMenuService;
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
import me.chanjar.weixin.cp.api.WxCpOaService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.WxCpTagService;
import me.chanjar.weixin.cp.api.WxCpTaskCardService;
import me.chanjar.weixin.cp.api.WxCpUserService;
import me.chanjar.weixin.cp.api.*;
import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
import me.chanjar.weixin.cp.bean.WxCpMessage;
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
@@ -60,6 +50,7 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
private WxCpAgentService agentService = new WxCpAgentServiceImpl(this);
private WxCpOaService oaService = new WxCpOaServiceImpl(this);
private WxCpTaskCardService taskCardService = new WxCpTaskCardServiceImpl(this);
private WxCpExternalContactService externalContactService = new WxCpExternalContactServiceImpl(this);

/**
* 全局的是否正在刷新access token的锁
@@ -396,6 +387,11 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
return userService;
}

@Override
public WxCpExternalContactService getExternalContactService() {
return externalContactService;
}

@Override
public WxCpChatService getChatService() {
return chatService;


+ 41
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java 查看文件

@@ -0,0 +1,41 @@
package me.chanjar.weixin.cp.api.impl;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpExternalContactService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo;
import me.chanjar.weixin.cp.bean.WxCpUserExternalContactList;
import me.chanjar.weixin.cp.bean.WxCpUserWithExternalPermission;

import java.util.List;

import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*;

public class WxCpExternalContactServiceImpl implements WxCpExternalContactService {
private WxCpService mainService;

public WxCpExternalContactServiceImpl(WxCpService mainService) {
this.mainService = mainService;
}

@Override
public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException {
String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId), null);

return WxCpUserExternalContactInfo.fromJson(responseContent);
}

@Override
public List<String> listExternalContacts(String userId) throws WxErrorException {
String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(LIST_EXTERNAL_CONTACT + userId), null);
WxCpUserExternalContactList list = WxCpUserExternalContactList.fromJson(responseContent);
return list.getExternalUserId();
}

@Override
public List<String> listFollowUser() throws WxErrorException {
String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(GET_FOLLOW_USER_LIST), null);
WxCpUserWithExternalPermission list = WxCpUserWithExternalPermission.fromJson(responseContent);
return list.getFollowUser();
}
}

+ 20
- 8
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfo.java 查看文件

@@ -1,16 +1,11 @@
package me.chanjar.weixin.cp.bean;

import java.util.List;

import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.*;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

import java.util.List;

/**
* <pre>
* 外部联系人详情
@@ -118,9 +113,26 @@ public class WxCpUserExternalContactInfo {
private String description;
@SerializedName("createtime")
private Long createTime;
private String state;
@SerializedName("remark_company")
private String remarkCompany;
@SerializedName("remark_mobiles")
private String[] remarkMobiles;
private Tag[] tags;

}

public static WxCpUserExternalContactInfo fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactInfo.class);
}

@Setter
@Getter
public static class Tag {
@SerializedName("group_name")
private String groupName;
@SerializedName("tag_name")
private String tagName;
private int type;
}
}

+ 58
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java 查看文件

@@ -0,0 +1,58 @@
package me.chanjar.weixin.cp.bean;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

import java.util.List;

/**
* <pre>
* 外部联系人列表
* Created by Joe Cao on 2019/6/16.
* 参考文档:https://work.weixin.qq.com/api/doc#90001/90143/91570
* </pre>
*
* @author <a href="https://github.com/JoeCao">Joe Cao</a>
*/
public class WxCpUserExternalContactList {
@SerializedName("errcode")
@Expose
private Long errcode;
@SerializedName("errmsg")
@Expose
private String errmsg;

@SerializedName("external_userid")
@Expose
private List<String> externalUserId = null;

public Long getErrcode() {
return errcode;
}

public void setErrcode(Long errcode) {
this.errcode = errcode;
}

public String getErrmsg() {
return errmsg;
}

public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}


public List<String> getExternalUserId() {
return externalUserId;
}

public void setExternalUserId(List<String> externalUserId) {
this.externalUserId = externalUserId;
}

public static WxCpUserExternalContactList fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactList.class);
}
}

+ 49
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java 查看文件

@@ -0,0 +1,49 @@
package me.chanjar.weixin.cp.bean;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

import java.util.List;

public class WxCpUserWithExternalPermission {
@SerializedName("errcode")
@Expose
private Long errcode;
@SerializedName("errmsg")
@Expose
private String errmsg;

@SerializedName("follow_user")
@Expose
private List<String> followUser = null;

public Long getErrcode() {
return errcode;
}

public void setErrcode(Long errcode) {
this.errcode = errcode;
}

public String getErrmsg() {
return errmsg;
}

public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}

public List<String> getFollowUser() {
return followUser;
}

public void setFollowUser(List<String> followUser) {
this.followUser = followUser;
}


public static WxCpUserWithExternalPermission fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpUserWithExternalPermission.class);
}
}

+ 20
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java 查看文件

@@ -175,6 +175,26 @@ public class WxCpXmlMessage implements Serializable {
@XStreamConverter(value = XStreamCDataConverter.class)
private String userId;

/**
* 变更信息的外部联系人的userid,注意不是企业成员的帐号.
*/
@XStreamAlias("ExternalUserID")
@XStreamConverter(value = XStreamCDataConverter.class)
private String externalUserID;

/**
* 添加此用户的「联系我」方式配置的state参数,可用于识别添加此用户的渠道
*/
@XStreamAlias("State")
@XStreamConverter(value = XStreamCDataConverter.class)
private String state;

/**
* 欢迎语code,可用于发送欢迎语
*/
@XStreamAlias("WelcomeCode")
@XStreamConverter(value = XStreamCDataConverter.class)
private String welcomeCode;
/**
* 新的UserID,变更时推送(userid由系统生成时可更改一次).
*/


+ 6
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java 查看文件

@@ -103,4 +103,10 @@ public final class WxCpApiPathConsts {
public static final String USER_CONVERT_TO_USERID = "/cgi-bin/user/convert_to_userid";
public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid=";
}

public static class ExternalContact {
public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid=";
public static final String LIST_EXTERNAL_CONTACT = "/cgi-bin/externalcontact/list?userid=";
public static final String GET_FOLLOW_USER_LIST = "/cgi-bin/externalcontact/get_follow_user_list";
}
}

+ 20
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java 查看文件

@@ -89,6 +89,26 @@ public class WxCpConsts {
*/
public static final String TASKCARD_CLICK = "taskcard_click";

/**
* 企业成员添加外部联系人事件推送
*/
public static final String CHANGE_EXTERNAL_CONTACT = "change_external_contact";


}

/**
* 企业外部联系人变更事件的CHANGE_TYPE
*/
public static class ExternalContactChangeType {
/**
* 新增外部联系人
*/
public static final String ADD_EXTERNAL_CONTACT = "add_external_contact";
/**
* 删除外部联系人
*/
public static final String DEL_EXTERNAL_CONTACT = "del_external_contact";
}

/**


+ 12
- 0
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java 查看文件

@@ -52,6 +52,8 @@ public class ApiTestModule implements Module {

protected String tagId;

protected String externalUserId;

public String getUserId() {
return this.userId;
}
@@ -76,12 +78,22 @@ public class ApiTestModule implements Module {
this.tagId = tagId;
}

public String getExternalUserId() {
return externalUserId;
}

public void setExternalUserId(String externalUserId) {
this.externalUserId = externalUserId;
}

@Override
public String toString() {
return super.toString() + " > WxXmlCpConfigStorage{" +
"userId='" + this.userId + '\'' +
", departmentId='" + this.departmentId + '\'' +
", tagId='" + this.tagId + '\'' +
", externalUserId='" + this.externalUserId + '\'' +

'}';
}
}


+ 45
- 0
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java 查看文件

@@ -0,0 +1,45 @@
package me.chanjar.weixin.cp.api.impl;

import com.google.inject.Inject;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

import java.util.List;

import static org.testng.Assert.assertNotNull;

@Guice(modules = ApiTestModule.class)
public class WxCpExternalContactServiceImplTest {
@Inject
private WxCpService wxCpService;
@Inject
protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage;
private String userId = "someone" + System.currentTimeMillis();

@Test
public void testGetExternalContact() throws WxErrorException {
String externalUserId = this.configStorage.getExternalUserId();
WxCpUserExternalContactInfo result = this.wxCpService.getExternalContactService().getExternalContact(externalUserId);
System.out.println(result);
assertNotNull(result);
}

@Test
public void testListExternalContacts() throws WxErrorException {
String userId = this.configStorage.getUserId();
List<String> ret = this.wxCpService.getExternalContactService().listExternalContacts(userId);
System.out.println(ret);
assertNotNull(ret);
}

@Test
public void testListExternalWithPermission() throws WxErrorException {
List<String> ret = this.wxCpService.getExternalContactService().listFollowUser();
System.out.println(ret);
assertNotNull(ret);
}
}

+ 2
- 7
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java 查看文件

@@ -93,7 +93,7 @@ public class WxCpUserServiceImplTest {
@Test
public void testInvite() throws Exception {
WxCpInviteResult result = this.wxCpService.getUserService().invite(
Lists.newArrayList(userId), null,null);
Lists.newArrayList(userId), null, null);
System.out.println(result);
}

@@ -111,10 +111,5 @@ public class WxCpUserServiceImplTest {
assertNotNull(result);
}

@Test
public void testGetExternalContact() throws WxErrorException {
WxCpUserExternalContactInfo result = this.wxCpService.getUserService().getExternalContact(userId);
System.out.println(result);
assertNotNull(result);
}

}

+ 50
- 1
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java 查看文件

@@ -1,6 +1,7 @@
package me.chanjar.weixin.cp.bean;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.cp.constant.WxCpConsts;
import org.testng.annotations.Test;

import static me.chanjar.weixin.cp.constant.WxCpConsts.EventType.TASKCARD_CLICK;
@@ -106,7 +107,7 @@ public class WxCpXmlMessageTest {
"<Count>2</Count>" +
"</SendPicsInfo>" +
"</xml>";
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml.replace("</PicList><PicList>",""));
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml.replace("</PicList><PicList>", ""));
assertEquals(wxMessage.getToUserName(), "wx45a0972125658be9");
assertEquals(wxMessage.getFromUserName(), "xiaohe");
assertEquals(wxMessage.getCreateTime(), new Long(1502012364L));
@@ -173,4 +174,52 @@ public class WxCpXmlMessageTest {
assertEquals(wxMessage.getEventKey(), "key111");
assertEquals(wxMessage.getTaskId(), "taskid111");
}

public void testAddExternalUserEvent() {
String xml = "<xml>" +
"<ToUserName><![CDATA[toUser]]></ToUserName>" +
"<FromUserName><![CDATA[sys]]></FromUserName>" +
"<CreateTime>1403610513</CreateTime>" +
"<MsgType><![CDATA[event]]></MsgType>" +
"<Event><![CDATA[change_external_contact]]></Event>" +
"<ChangeType><![CDATA[add_external_contact]]></ChangeType>" +
"<UserID><![CDATA[zhangsan]]></UserID>" +
"<ExternalUserID><![CDATA[woAJ2GCAAAXtWyujaWJHDDGi0mACH71w]]></ExternalUserID>" +
"<State><![CDATA[teststate]]></State>" +
"<WelcomeCode><![CDATA[WELCOMECODE]]></WelcomeCode>" +
"</xml >";
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml);
assertEquals(wxMessage.getToUserName(), "toUser");
assertEquals(wxMessage.getFromUserName(), "sys");
assertEquals(wxMessage.getCreateTime(), Long.valueOf(1403610513L));
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT);
assertEquals(wxMessage.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CONTACT);
assertEquals(wxMessage.getChangeType(), WxCpConsts.ExternalContactChangeType.ADD_EXTERNAL_CONTACT);
assertEquals(wxMessage.getExternalUserID(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w");
assertEquals(wxMessage.getState(), "teststate");
assertEquals(wxMessage.getWelcomeCode(), "WELCOMECODE");

}

public void testDelExternalUserEvent() {
String xml = "<xml>" +
"<ToUserName><![CDATA[toUser]]></ToUserName>" +
"<FromUserName><![CDATA[sys]]></FromUserName>" +
"<CreateTime>1403610513</CreateTime>" +
"<MsgType><![CDATA[event]]></MsgType>" +
"<Event><![CDATA[change_external_contact]]></Event>" +
"<ChangeType><![CDATA[del_external_contact]]></ChangeType>" +
"<UserID><![CDATA[zhangsan]]></UserID>" +
"<ExternalUserID><![CDATA[woAJ2GCAAAXtWyujaWJHDDGi0mACH71w]]></ExternalUserID>" +
"</xml>";
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml);
assertEquals(wxMessage.getToUserName(), "toUser");
assertEquals(wxMessage.getFromUserName(), "sys");
assertEquals(wxMessage.getCreateTime(), Long.valueOf(1403610513L));
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT);
assertEquals(wxMessage.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CONTACT);
assertEquals(wxMessage.getChangeType(), WxCpConsts.ExternalContactChangeType.DEL_EXTERNAL_CONTACT);
assertEquals(wxMessage.getUserId(), "zhangsan");
assertEquals(wxMessage.getExternalUserID(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w");
}
}

Loading…
取消
儲存