🆕 #2612 【企业微信】增加获取企业活跃成员数和通讯录异步导出的接口

This commit is contained in:
zhongjun 2022-04-22 09:01:19 +08:00 committed by GitHub
parent 5d0364f6d2
commit 1030115751
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 325 additions and 0 deletions

View File

@ -0,0 +1,100 @@
package me.chanjar.weixin.cp.api;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.export.WxCpExportRequest;
import me.chanjar.weixin.cp.bean.export.WxCpExportResult;
/**
* 异步导出接口
*
* @author <a href="https://github.com/zhongjun96">zhongjun</a>
* @date 2022/4/21
**/
public interface WxCpExportService {
/**
* <pre>
*
* 导出成员
*
* 请求方式POSTHTTPS
* 请求地址<a href="https://qyapi.weixin.qq.com/cgi-bin/export/simple_user?access_token=ACCESS_TOKEN">https://qyapi.weixin.qq.com/cgi-bin/export/simple_user?access_token=ACCESS_TOKEN</a>
*
* 文档地址<a href="https://developer.work.weixin.qq.com/document/path/94849">https://developer.work.weixin.qq.com/document/path/94849</a>
* </pre>
*
* @param params 导出参数
* @return jobId 异步任务id
* @throws WxErrorException .
*/
String simpleUser(WxCpExportRequest params) throws WxErrorException;
/**
* <pre>
*
* 导出成员详情
*
* 请求方式POSTHTTPS
* 请求地址<a href="https://qyapi.weixin.qq.com/cgi-bin/export/user?access_token=ACCESS_TOKEN">https://qyapi.weixin.qq.com/cgi-bin/export/user?access_token=ACCESS_TOKEN</a>
*
* 文档地址<a href="https://developer.work.weixin.qq.com/document/path/94851">https://developer.work.weixin.qq.com/document/path/94851</a>
* </pre>
*
* @param params 导出参数
* @return jobId 异步任务id
* @throws WxErrorException .
*/
String user(WxCpExportRequest params) throws WxErrorException;
/**
* <pre>
*
* 导出部门
*
* 请求方式POSTHTTPS
* 请求地址<a href="https://qyapi.weixin.qq.com/cgi-bin/export/department?access_token=ACCESS_TOKEN">https://qyapi.weixin.qq.com/cgi-bin/export/department?access_token=ACCESS_TOKEN</a>
*
* 文档地址<a href="https://developer.work.weixin.qq.com/document/path/94852">https://developer.work.weixin.qq.com/document/path/94852</a>
* </pre>
*
* @param params 导出参数
* @return jobId 异步任务id
* @throws WxErrorException .
*/
String department(WxCpExportRequest params) throws WxErrorException;
/**
* <pre>
*
* 导出标签成员
*
* 请求方式POSTHTTPS
* 请求地址<a href="https://qyapi.weixin.qq.com/cgi-bin/export/taguser?access_token=ACCESS_TOKEN">https://qyapi.weixin.qq.com/cgi-bin/export/taguser?access_token=ACCESS_TOKEN</a>
*
* 文档地址<a href="https://developer.work.weixin.qq.com/document/path/94853">https://developer.work.weixin.qq.com/document/path/94853</a>
* </pre>
*
* @param params 导出参数
* @return jobId 异步任务id
* @throws WxErrorException .
*/
String tagUser(WxCpExportRequest params) throws WxErrorException;
/**
* <pre>
*
* 获取导出结果
*
* 请求方式GETHTTPS
* 请求地址<a href="https://qyapi.weixin.qq.com/cgi-bin/export/get_result?access_token=ACCESS_TOKEN&jobid=jobid_xxxxxxxxxxxxxxx">https://qyapi.weixin.qq.com/cgi-bin/export/get_result?access_token=ACCESS_TOKEN&jobid=jobid_xxxxxxxxxxxxxxx</a>
*
* 文档地址<a href="https://developer.work.weixin.qq.com/document/path/94854">https://developer.work.weixin.qq.com/document/path/94854</a>
* 返回的url文件下载解密可参考 <a href="https://blog.csdn.net/a201692/article/details/123530529">CSDN</a>
* </pre>
*
* @param jobId 异步任务id
* @return 导出结果
* @throws WxErrorException .
*/
WxCpExportResult getResult(String jobId) throws WxErrorException;
}

View File

@ -511,4 +511,18 @@ public interface WxCpService extends WxService {
* @param kfService the kf service
*/
void setKfService(WxCpKfService kfService);
/**
* 获取异步导出服务
*
* @return 异步导出服务
*/
WxCpExportService getExportService();
/**
* 设置异步导出服务
*
* @param exportService 异步导出服务
*/
void setExportService(WxCpExportService exportService);
}

View File

@ -5,6 +5,7 @@ import me.chanjar.weixin.cp.bean.WxCpInviteResult;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -199,4 +200,21 @@ public interface WxCpUserService {
* @throws WxErrorException .
*/
String getJoinQrCode(int sizeType) throws WxErrorException;
/**
* <pre>
*
* 获取企业活跃成员数
*
* 请求方式POSTHTTPS
* 请求地址<a href="https://qyapi.weixin.qq.com/cgi-bin/user/get_active_stat?access_token=ACCESS_TOKEN">https://qyapi.weixin.qq.com/cgi-bin/user/get_active_stat?access_token=ACCESS_TOKEN</a>
*
* 文档地址<a href="https://developer.work.weixin.qq.com/document/path/92714">https://developer.work.weixin.qq.com/document/path/92714</a>
* </pre>
*
* @param date 具体某天的活跃人数最长支持获取30天前数据
* @return join_qrcode 活跃成员数
* @throws WxErrorException .
*/
Integer getActiveStat(Date date) throws WxErrorException;
}

View File

@ -61,6 +61,8 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
private WxCpAgentWorkBenchService workBenchService = new WxCpAgentWorkBenchServiceImpl(this);
private WxCpKfService kfService = new WxCpKfServiceImpl(this);
private WxCpExportService exportService = new WxCpExportServiceImpl(this);
/**
* 全局的是否正在刷新access token的锁.
*/
@ -588,4 +590,15 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
public void setKfService(WxCpKfService kfService) {
this.kfService = kfService;
}
@Override
public WxCpExportService getExportService() {
return exportService;
}
@Override
public void setExportService(WxCpExportService exportService) {
this.exportService = exportService;
}
}

View File

@ -0,0 +1,59 @@
package me.chanjar.weixin.cp.api.impl;
import com.google.gson.JsonObject;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.json.GsonParser;
import me.chanjar.weixin.cp.api.WxCpExportService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.export.WxCpExportRequest;
import me.chanjar.weixin.cp.bean.export.WxCpExportResult;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Export.*;
/**
* 异步导出接口
*
* @author <a href="https://github.com/zhongjun96">zhongjun</a>
* @date 2022/4/21
**/
@RequiredArgsConstructor
public class WxCpExportServiceImpl implements WxCpExportService {
private final WxCpService mainService;
@Override
public String simpleUser(WxCpExportRequest params) throws WxErrorException {
return export(SIMPLE_USER, params);
}
@Override
public String user(WxCpExportRequest params) throws WxErrorException {
return export(USER, params);
}
@Override
public String department(WxCpExportRequest params) throws WxErrorException {
return export(DEPARTMENT, params);
}
@Override
public String tagUser(WxCpExportRequest params) throws WxErrorException {
return export(TAG_USER, params);
}
@Override
public WxCpExportResult getResult(String jobId) throws WxErrorException {
String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(GET_RESULT), jobId);
String responseContent = this.mainService.get(url, null);
return WxCpGsonBuilder.create().fromJson(responseContent, WxCpExportResult.class);
}
private String export(String path, WxCpExportRequest params) throws WxErrorException {
String url = this.mainService.getWxCpConfigStorage().getApiUrl(path);
String responseContent = this.mainService.post(url, params.toJson());
JsonObject tmpJson = GsonParser.parse(responseContent);
return tmpJson.get("jobid").getAsString();
}
}

View File

@ -14,7 +14,10 @@ import me.chanjar.weixin.cp.bean.WxCpInviteResult;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import org.apache.commons.lang3.time.FastDateFormat;
import java.text.Format;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -29,6 +32,8 @@ import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.User.*;
*/
@RequiredArgsConstructor
public class WxCpUserServiceImpl implements WxCpUserService {
private final Format dateFormat = FastDateFormat.getInstance("yyyy-MM-dd");
private final WxCpService mainService;
@Override
@ -208,4 +213,14 @@ public class WxCpUserServiceImpl implements WxCpUserService {
JsonObject tmpJson = GsonParser.parse(responseContent);
return tmpJson.get("join_qrcode").getAsString();
}
@Override
public Integer getActiveStat(Date date) throws WxErrorException {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("date", this.dateFormat.format(date));
String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_ACTIVE_STAT);
String responseContent = this.mainService.post(url, jsonObject.toString());
JsonObject tmpJson = GsonParser.parse(responseContent);
return tmpJson.get("active_cnt").getAsInt();
}
}

View File

@ -0,0 +1,41 @@
package me.chanjar.weixin.cp.bean.export;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import java.io.Serializable;
/**
* 异步导出参数
*
* @author zhongjun
* @date 2022/4/21
**/
@Data
public class WxCpExportRequest implements Serializable {
private static final long serialVersionUID = -8127528999898984359L;
/**
* base64encode的加密密钥长度固定为43base64decode之后即得到AESKey加密方式采用AES-256-CBC方式数据采用PKCS#7填充至32字节的倍数IV初始向量大小为16字节取AESKey前16字节详见<a href="http://tools.ietf.org/html/rfc2315">http://tools.ietf.org/html/rfc2315</a>
*/
@SerializedName("encoding_aeskey")
private String encodingAesKey;
/**
* 每块数据的部门数支持范围[104,106]默认值为10^6
*/
@SerializedName("block_size")
private Integer blockSize;
/**
* 需要导出的标签
* 导出标签成员时使用
*/
@SerializedName("tagid")
private Integer tagId;
public String toJson() {
return WxCpGsonBuilder.create().toJson(this);
}
}

View File

@ -0,0 +1,48 @@
package me.chanjar.weixin.cp.bean.export;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
import java.util.List;
/**
* 异步导出响应
*
* @author zhongjun
* @date 2022/4/21
**/
@Data
@EqualsAndHashCode(callSuper = true)
public class WxCpExportResult extends WxCpBaseResp {
private static final long serialVersionUID = -8673839248829238966L;
/**
* 任务状态:0-未处理1-处理中2-完成3-异常失败
*/
private Integer status;
@SerializedName("data_list")
private List<ExportData> dataList;
@Data
public static class ExportData {
/**
* 数据下载链接,支持指定Range头部分段下载有效期2个小时
*/
private String url;
/**
* 密文数据大小
*/
private Integer size;
/**
* 密文数据md5
*/
private String md5;
}
}

View File

@ -215,6 +215,7 @@ public interface WxCpApiPathConsts {
String GET_USER_ID = "/cgi-bin/user/getuserid";
String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid=";
String GET_JOIN_QR_CODE = "/cgi-bin/corp/get_join_qrcode?size_type=";
String GET_ACTIVE_STAT = "/cgi-bin/user/get_active_stat";
}
interface ExternalContact {
@ -310,4 +311,12 @@ public interface WxCpApiPathConsts {
String CUSTOMER_BATCH_GET = "/cgi-bin/kf/customer/batchget";
}
interface Export {
String SIMPLE_USER = "/cgi-bin/export/simple_user";
String USER = "/cgi-bin/export/user";
String DEPARTMENT = "/cgi-bin/export/department";
String TAG_USER = "/cgi-bin/export/taguser";
String GET_RESULT = "/cgi-bin/export/get_result?jobid=%s";
}
}

View File

@ -1,5 +1,6 @@
package me.chanjar.weixin.cp.api.impl;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -121,4 +122,11 @@ public class WxCpUserServiceImplTest {
@Test
public void testGetExternalContact() {
}
@Test
public void testGetActiveStat() throws WxErrorException {
Integer activeStat = this.wxCpService.getUserService().getActiveStat(new Date());
System.out.printf("active stat: %d", activeStat);
assertNotNull(activeStat);
}
}