From cec65038e8b9b80dca71b017ef18d0f027b47891 Mon Sep 17 00:00:00 2001
From: tjx <t2856754968@163.com>
Date: 星期三, 26 十一月 2025 13:46:03 +0800
Subject: [PATCH] 新增企业微信的接口
---
src/main/java/com/gs/xky/service/WorkWXService.java | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 251 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/gs/xky/service/WorkWXService.java b/src/main/java/com/gs/xky/service/WorkWXService.java
index 430d00f..300521d 100644
--- a/src/main/java/com/gs/xky/service/WorkWXService.java
+++ b/src/main/java/com/gs/xky/service/WorkWXService.java
@@ -1,19 +1,25 @@
package com.gs.xky.service;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gs.xky.config.DataAcquisitionConfiguration;
+import com.gs.xky.entity.QwStaff;
+import com.gs.xky.mapper.QwStaffMapper;
import lombok.Data;
import lombok.RequiredArgsConstructor;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
+import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@@ -27,6 +33,8 @@
.build();
private final ObjectMapper objectMapper = new ObjectMapper();
+
+ private final QwStaffMapper qwStaffMapper;
public String getAccessToken() throws IOException {
String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s",
@@ -54,8 +62,193 @@
}
log.info("鎴愬姛鑾峰彇浼佷笟寰俊access_token锛屾湁鏁堟湡: {}绉�", tokenResponse.getExpiresIn());
+ log.info("access_token : {}", tokenResponse.getAccessToken());
return tokenResponse.getAccessToken();
}
+ }
+
+ public String getContactAccessToken() throws IOException {
+ String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s",
+ DataAcquisitionConfiguration.CORPID,
+ DataAcquisitionConfiguration.TXL_CORPSECRET);
+
+ Request request = new Request.Builder()
+ .url(url)
+ .get()
+ .build();
+
+ try (Response response = client.newCall(request).execute()) {
+ if (!response.isSuccessful()) {
+ log.error("鑾峰彇浼佷笟寰俊閫氳褰昦ccess_token澶辫触锛孒TTP鐘舵�佺爜: {}", response.code());
+ throw new IOException("鑾峰彇閫氳褰昦ccess_token澶辫触: " + response.message());
+ }
+
+ String responseBody = response.body().string();
+ WorkWXTokenResponse tokenResponse = objectMapper.readValue(responseBody, WorkWXTokenResponse.class);
+
+ if (tokenResponse.getErrcode() != 0) {
+ log.error("鑾峰彇浼佷笟寰俊閫氳褰昦ccess_token澶辫触锛岄敊璇爜: {}, 閿欒淇℃伅: {}",
+ tokenResponse.getErrcode(), tokenResponse.getErrmsg());
+ throw new IOException("鑾峰彇閫氳褰昦ccess_token澶辫触: " + tokenResponse.getErrmsg());
+ }
+
+ log.info("鎴愬姛鑾峰彇浼佷笟寰俊閫氳褰昦ccess_token锛屾湁鏁堟湡: {}绉�", tokenResponse.getExpiresIn());
+ return tokenResponse.getAccessToken();
+ }
+ }
+
+
+ public List<WorkWXUser> getUserList() throws IOException {
+ String accessToken = getContactAccessToken();
+ String url = String.format(
+ "https://qyapi.weixin.qq.com/cgi-bin/user/list_id?access_token=%s",
+ accessToken);
+
+ List<WorkWXUser> allUsers = new ArrayList<>();
+ String cursor = null;
+
+ do {
+ Map<String, Object> requestBody = new HashMap<>();
+ requestBody.put("limit", 10000);
+ if (cursor != null) {
+ requestBody.put("cursor", cursor);
+ }
+
+ MediaType mediaType = MediaType.parse("application/json; charset=UTF-8");
+ String jsonBody = objectMapper.writeValueAsString(requestBody);
+ RequestBody body = RequestBody.create(mediaType, jsonBody);
+
+ Request request = new Request.Builder()
+ .url(url)
+ .post(body)
+ .addHeader("Content-Type", "application/json; charset=UTF-8")
+ .build();
+
+ try (Response response = client.newCall(request).execute()) {
+ if (!response.isSuccessful()) {
+ log.error("鑾峰彇浼佷笟寰俊鐢ㄦ埛鍒楄〃澶辫触锛孒TTP鐘舵�佺爜: {}", response.code());
+ throw new IOException("鑾峰彇鐢ㄦ埛鍒楄〃澶辫触: " + response.message());
+ }
+
+ String responseBody = response.body().string();
+ log.info("鑾峰彇鐢ㄦ埛鍒楄〃鍝嶅簲: {}", responseBody);
+
+ WorkWXUserListIdResponse userListResponse = objectMapper.readValue(responseBody, WorkWXUserListIdResponse.class);
+
+ if (userListResponse.getErrcode() != 0) {
+ log.error("鑾峰彇浼佷笟寰俊鐢ㄦ埛鍒楄〃澶辫触锛岄敊璇爜: {}, 閿欒淇℃伅: {}",
+ userListResponse.getErrcode(), userListResponse.getErrmsg());
+ throw new IOException("鑾峰彇鐢ㄦ埛鍒楄〃澶辫触: " + userListResponse.getErrmsg());
+ }
+
+ if (userListResponse.getDeptUser() != null && !userListResponse.getDeptUser().isEmpty()) {
+ allUsers.addAll(userListResponse.getDeptUser());
+ }
+
+ cursor = userListResponse.getNextCursor();
+
+ } catch (IOException e) {
+ log.error("瑙f瀽鐢ㄦ埛鍒楄〃鍝嶅簲澶辫触", e);
+ throw e;
+ }
+
+ } while (cursor != null && !cursor.isEmpty());
+
+ log.info("鎴愬姛鑾峰彇浼佷笟寰俊鐢ㄦ埛鍒楄〃锛岀敤鎴锋暟閲�: {}", allUsers.size());
+ return allUsers;
+ }
+
+ public List<CheckinData> getCheckinDataByQwStaff(long startTime, long endTime) throws IOException {
+ List<QwStaff> qwStaffList = qwStaffMapper.selectList(new LambdaQueryWrapper<QwStaff>());
+
+ if (qwStaffList == null || qwStaffList.isEmpty()) {
+ log.warn("QW_STAFF琛ㄤ腑娌℃湁鏁版嵁");
+ return new ArrayList<>();
+ }
+
+ List<String> useridList = qwStaffList.stream()
+ .map(QwStaff::getAccount)
+ .filter(account -> account != null && !account.isEmpty())
+ .collect(Collectors.toList());
+
+ if (useridList.isEmpty()) {
+ log.warn("QW_STAFF琛ㄤ腑娌℃湁鏈夋晥鐨刟ccount鏁版嵁");
+ return new ArrayList<>();
+ }
+
+ log.info("浠嶲W_STAFF琛ㄨ幏鍙栧埌 {} 涓敤鎴穉ccount", useridList.size());
+ return getCheckinData(startTime, endTime, useridList);
+ }
+
+ public List<CheckinData> getCheckinData(long startTime, long endTime, List<String> useridList) throws IOException {
+ String accessToken = getAccessToken();
+ String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata?access_token=%s", accessToken);
+
+ List<CheckinData> allCheckinData = new ArrayList<>();
+
+ int batchSize = 100;
+ int totalUsers = useridList.size();
+ int batchCount = (totalUsers + batchSize - 1) / batchSize;
+
+ log.info("寮�濮嬭幏鍙栨墦鍗℃暟鎹紝鎬荤敤鎴锋暟: {}, 鍒嗘壒鏁�: {}, 鏃堕棿鑼冨洿: {} - {}", totalUsers, batchCount, startTime, endTime);
+
+ for (int i = 0; i < batchCount; i++) {
+ int fromIndex = i * batchSize;
+ int toIndex = Math.min((i + 1) * batchSize, totalUsers);
+
+ List<String> batchUserList = useridList.subList(fromIndex, toIndex);
+ log.info("姝e湪鑾峰彇绗� {}/{} 鎵规墦鍗℃暟鎹紝鐢ㄦ埛鏁�: {}", i + 1, batchCount, batchUserList.size());
+
+ Map<String, Object> requestBody = new HashMap<>();
+ requestBody.put("opencheckindatatype", 3);
+ requestBody.put("starttime", startTime);
+ requestBody.put("endtime", endTime);
+ requestBody.put("useridlist", batchUserList);
+
+ MediaType mediaType = MediaType.parse("application/json; charset=UTF-8");
+ String jsonBody = objectMapper.writeValueAsString(requestBody);
+ RequestBody body = RequestBody.create(mediaType, jsonBody);
+
+ Request request = new Request.Builder()
+ .url(url)
+ .post(body)
+ .addHeader("Content-Type", "application/json; charset=UTF-8")
+ .build();
+
+ try (Response response = client.newCall(request).execute()) {
+ if (!response.isSuccessful()) {
+ log.error("鑾峰彇鎵撳崱鏁版嵁澶辫触锛孒TTP鐘舵�佺爜: {}", response.code());
+ throw new IOException("鑾峰彇鎵撳崱鏁版嵁澶辫触: " + response.message());
+ }
+
+ String responseBody = response.body().string();
+
+ WorkWXCheckinResponse checkinResponse = objectMapper.readValue(responseBody, WorkWXCheckinResponse.class);
+
+ if (checkinResponse.getErrcode() != 0) {
+ log.error("鑾峰彇鎵撳崱鏁版嵁澶辫触锛岄敊璇爜: {}, 閿欒淇℃伅: {}",
+ checkinResponse.getErrcode(), checkinResponse.getErrmsg());
+ throw new IOException("鑾峰彇鎵撳崱鏁版嵁澶辫触: " + checkinResponse.getErrmsg());
+ }
+
+ if (checkinResponse.getCheckindata() != null) {
+ allCheckinData.addAll(checkinResponse.getCheckindata());
+ log.info("绗� {}/{} 鎵硅幏鍙栧埌鎵撳崱璁板綍鏁�: {}", i + 1, batchCount, checkinResponse.getCheckindata().size());
+ }
+ }
+
+ if (i < batchCount - 1) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ log.warn("鎵规闂寸瓑寰呰涓柇");
+ }
+ }
+ }
+
+ log.info("鎵撳崱鏁版嵁鑾峰彇瀹屾垚锛屾�昏褰曟暟: {}", allCheckinData.size());
+ return allCheckinData;
}
@Data
@@ -67,4 +260,59 @@
@JsonProperty("expires_in")
private Integer expiresIn;
}
+
+ @Data
+ private static class WorkWXUserIdResponse {
+ private Integer errcode;
+ private String errmsg;
+ private String userid;
+ }
+
+ @Data
+ private static class WorkWXUserListIdResponse {
+ private Integer errcode;
+ private String errmsg;
+ @JsonProperty("next_cursor")
+ private String nextCursor;
+ @JsonProperty("dept_user")
+ private List<WorkWXUser> deptUser;
+ }
+
+ @Data
+ public static class WorkWXUser {
+ private String userid;
+ private List<Integer> department;
+ private String name;
+ @JsonProperty("open_userid")
+ private String openUserid;
+ }
+
+ @Data
+ private static class WorkWXCheckinResponse {
+ private Integer errcode;
+ private String errmsg;
+ private List<CheckinData> checkindata;
+ }
+
+ @Data
+ public static class CheckinData {
+ private String userid;
+ private String groupname;
+ @JsonProperty("checkin_type")
+ private String checkinType;
+ @JsonProperty("exception_type")
+ private String exceptionType;
+ @JsonProperty("checkin_time")
+ private Long checkinTime;
+ @JsonProperty("location_title")
+ private String locationTitle;
+ @JsonProperty("location_detail")
+ private String locationDetail;
+ private String wifiname;
+ private String notes;
+ private String wifimac;
+ private String mediaids;
+ private Double lat;
+ private Double lng;
+ }
}
--
Gitblit v1.9.3