From ef60ffc4c5b25c0a59566e6b049068577a813ba1 Mon Sep 17 00:00:00 2001 From: zhongjun96 Date: Thu, 21 Apr 2022 16:50:35 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1):?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=8E=B7=E5=8F=96=E4=BC=81=E4=B8=9A=E6=B4=BB?= =?UTF-8?q?=E8=B7=83=E6=88=90=E5=91=98=E6=95=B0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/cp/api/WxCpUserService.java | 18 ++++++++++++++++++ .../cp/api/impl/WxCpUserServiceImpl.java | 15 +++++++++++++++ .../weixin/cp/constant/WxCpApiPathConsts.java | 1 + .../cp/api/impl/WxCpUserServiceImplTest.java | 8 ++++++++ 4 files changed, 42 insertions(+) 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 ede813a0a5..e5a51eea1f 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.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/WxCpUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java index d0648b21ec..b789fc1b63 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.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 @@ */ @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 String getJoinQrCode(int sizeType) throws WxErrorException { 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/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java index 8c45a676e4..173a933feb 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 @@ interface User { 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 { 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 9c4448830e..0fb494ff34 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 void testGetUserId() throws WxErrorException { @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); + } } From ad5a49748bd56aade39bd06f11a2cd1b921ad9e0 Mon Sep 17 00:00:00 2001 From: zhongjun96 Date: Thu, 21 Apr 2022 18:59:03 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat(=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1):?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=80=9A=E8=AE=AF=E5=BD=95=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/api/WxCpExportService.java | 100 ++++++++++++++++++ .../me/chanjar/weixin/cp/api/WxCpService.java | 14 +++ .../cp/api/impl/BaseWxCpServiceImpl.java | 13 +++ .../cp/api/impl/WxCpExportServiceImpl.java | 59 +++++++++++ .../cp/bean/export/WxCpExportRequest.java | 41 +++++++ .../cp/bean/export/WxCpExportResult.java | 37 +++++++ .../weixin/cp/constant/WxCpApiPathConsts.java | 8 ++ 7 files changed, 272 insertions(+) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExportService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExportServiceImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportRequest.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportResult.java 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 0000000000..a28c7fc7d9 --- /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 76f337f8e2..851e9c192f 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/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java index 263fa87a76..ece8bd9add 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 WxCpKfService getKfService() { 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 0000000000..1e90343881 --- /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/bean/export/WxCpExportRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportRequest.java new file mode 100644 index 0000000000..ef21c19e28 --- /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 0000000000..5e2b176075 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/export/WxCpExportResult.java @@ -0,0 +1,37 @@ +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; + + + private Integer status; + + @SerializedName("data_list") + private List dataList; + + + @Data + public static class ExportData { + + private String url; + + private Integer size; + + 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 173a933feb..c3b4e03ecb 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 @@ -311,4 +311,12 @@ interface Kf { 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"; + } } From b20905a082b78749b5beff1e782e5d1aac3b497a Mon Sep 17 00:00:00 2001 From: zhongjun96 Date: Thu, 21 Apr 2022 19:05:36 +0800 Subject: [PATCH 3/3] =?UTF-8?q?:art:=20=E6=B7=BB=E5=8A=A0=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/bean/export/WxCpExportResult.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) 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 index 5e2b176075..b291049ae0 100644 --- 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 @@ -18,7 +18,9 @@ public class WxCpExportResult extends WxCpBaseResp { private static final long serialVersionUID = -8673839248829238966L; - + /** + * 任务状态:0-未处理,1-处理中,2-完成,3-异常失败 + */ private Integer status; @SerializedName("data_list") @@ -28,10 +30,19 @@ public class WxCpExportResult extends WxCpBaseResp { @Data public static class ExportData { + /** + * 数据下载链接,支持指定Range头部分段下载。有效期2个小时 + */ private String url; + /** + * 密文数据大小 + */ private Integer size; + /** + * 密文数据md5 + */ private String md5; } }