diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExportService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExportService.java
new file mode 100644
index 000000000..a28c7fc7d
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExportService.java
@@ -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 zhongjun
+ * @date 2022/4/21
+ **/
+public interface WxCpExportService {
+
+ /**
+ *
+ *
+ * 导出成员
+ *
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/export/simple_user?access_token=ACCESS_TOKEN
+ *
+ * 文档地址:https://developer.work.weixin.qq.com/document/path/94849
+ *
+ *
+ * @param params 导出参数
+ * @return jobId 异步任务id
+ * @throws WxErrorException .
+ */
+ String simpleUser(WxCpExportRequest params) throws WxErrorException;
+
+ /**
+ *
+ *
+ * 导出成员详情
+ *
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/export/user?access_token=ACCESS_TOKEN
+ *
+ * 文档地址:https://developer.work.weixin.qq.com/document/path/94851
+ *
+ *
+ * @param params 导出参数
+ * @return jobId 异步任务id
+ * @throws WxErrorException .
+ */
+ String user(WxCpExportRequest params) throws WxErrorException;
+
+ /**
+ *
+ *
+ * 导出部门
+ *
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/export/department?access_token=ACCESS_TOKEN
+ *
+ * 文档地址:https://developer.work.weixin.qq.com/document/path/94852
+ *
+ *
+ * @param params 导出参数
+ * @return jobId 异步任务id
+ * @throws WxErrorException .
+ */
+ String department(WxCpExportRequest params) throws WxErrorException;
+
+ /**
+ *
+ *
+ * 导出标签成员
+ *
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/export/taguser?access_token=ACCESS_TOKEN
+ *
+ * 文档地址:https://developer.work.weixin.qq.com/document/path/94853
+ *
+ *
+ * @param params 导出参数
+ * @return jobId 异步任务id
+ * @throws WxErrorException .
+ */
+ String tagUser(WxCpExportRequest params) throws WxErrorException;
+
+ /**
+ *
+ *
+ * 获取导出结果
+ *
+ * 请求方式:GET(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/export/get_result?access_token=ACCESS_TOKEN&jobid=jobid_xxxxxxxxxxxxxxx
+ *
+ * 文档地址:https://developer.work.weixin.qq.com/document/path/94854
+ * 返回的url文件下载解密可参考 CSDN
+ *
+ *
+ * @param jobId 异步任务id
+ * @return 导出结果
+ * @throws WxErrorException .
+ */
+ WxCpExportResult getResult(String jobId) throws WxErrorException;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
index 76f337f8e..851e9c192 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
@@ -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);
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java
index ede813a0a..e5a51eea1 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java
@@ -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;
+
+ /**
+ *
+ *
+ * 获取企业活跃成员数。
+ *
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/user/get_active_stat?access_token=ACCESS_TOKEN
+ *
+ * 文档地址:https://developer.work.weixin.qq.com/document/path/92714
+ *
+ *
+ * @param date 具体某天的活跃人数,最长支持获取30天前数据
+ * @return join_qrcode 活跃成员数
+ * @throws WxErrorException .
+ */
+ Integer getActiveStat(Date date) throws WxErrorException;
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
index 263fa87a7..ece8bd9ad 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
@@ -61,6 +61,8 @@ public abstract class BaseWxCpServiceImpl 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 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;
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExportServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExportServiceImpl.java
new file mode 100644
index 000000000..1e9034388
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExportServiceImpl.java
@@ -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 zhongjun
+ * @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();
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java
index d0648b21e..b789fc1b6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java
@@ -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();
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportRequest.java
new file mode 100644
index 000000000..ef21c19e2
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportRequest.java
@@ -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的加密密钥,长度固定为43,base64decode之后即得到AESKey。加密方式采用AES-256-CBC方式,数据采用PKCS#7填充至32字节的倍数;IV初始向量大小为16字节,取AESKey前16字节,详见:http://tools.ietf.org/html/rfc2315
+ */
+ @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);
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportResult.java
new file mode 100644
index 000000000..b291049ae
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportResult.java
@@ -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 dataList;
+
+
+ @Data
+ public static class ExportData {
+
+ /**
+ * 数据下载链接,支持指定Range头部分段下载。有效期2个小时
+ */
+ private String url;
+
+ /**
+ * 密文数据大小
+ */
+ private Integer size;
+
+ /**
+ * 密文数据md5
+ */
+ private String md5;
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
index 8c45a676e..c3b4e03ec 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
@@ -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";
+ }
}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java
index 9c4448830..0fb494ff3 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java
@@ -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);
+ }
}