Kaynağa Gözat

优化钉钉会议接口 查询速度

cr 1 ay önce
ebeveyn
işleme
16f49c714f

+ 191 - 82
blade-service/blade-dingding/src/main/java/org/springblade/dingding/service/impl/MeetingServiceImpl.java

@@ -8,11 +8,13 @@ import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
 import com.alibaba.nacos.shaded.com.google.gson.JsonParser;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang.StringUtils;
+import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
 import org.springblade.core.log.exception.ServiceException;
@@ -21,6 +23,7 @@ import org.springblade.dingding.vo.MeetingSchedule;
 import org.springblade.dingding.vo.MeetingVo;
 import org.springblade.dingding.vo.ScheduleItem;
 import org.springframework.http.*;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.web.client.HttpClientErrorException;
 import org.springframework.web.client.HttpServerErrorException;
@@ -37,6 +40,9 @@ import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.TextStyle;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @Service
@@ -47,97 +53,203 @@ public class MeetingServiceImpl implements MeetingService {
     private static final String APP_SECRET = "TctTp-Qmyh9r20bdeHcLWZ8qfxSEP8R29qo53GZH2elWV-yDZMqgqFKEjp5PtlXZ";
     private static final String USER_ID = "01141506681633389467";
 
+    // 缓存用户信息,避免重复调用
+    private final Map<String, Object> userInfoCache = new ConcurrentHashMap<>();
+    private final Map<String, String> departmentCache = new ConcurrentHashMap<>();
+
+    // 创建带超时配置的HttpClient
+    private CloseableHttpClient createHttpClientWithTimeout() {
+        RequestConfig config = RequestConfig.custom()
+                .setConnectTimeout(10000) // 10秒连接超时
+                .setSocketTimeout(15000)   // 15秒socket超时
+                .build();
+
+        return HttpClientBuilder.create()
+                .setDefaultRequestConfig(config)
+                .build();
+    }
+
 
 
     @Override
     public  List<MeetingVo> getMeetingInfo() {
-        List<MeetingVo> vos=new ArrayList<>();
-        String accessToken = getAccessToken();
-        String unionId = (String) getUserInfo(accessToken,"unionid",USER_ID);
-        String meetingsJson = getMeetings(accessToken, unionId);
+        long startTime = System.currentTimeMillis();
         try {
-            // 解析JSON字符串
-            com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(meetingsJson);
-            // 获取result数组
+            String accessToken = getAccessToken();
+            String unionId = (String) getUserInfo(accessToken, "unionid", USER_ID);
+            String meetingsJson = getMeetings(accessToken, unionId);
+
+            List<MeetingVo> vos = parseMeetingRooms(meetingsJson);
+            if (vos.isEmpty()) {
+                return vos;
+            }
+
+            // 准备时间范围参数
+            String[] timeRange = getTodayTimeRange();
+
+            // 并行处理每个会议室
+            List<CompletableFuture<Void>> futures = vos.stream()
+                    .map(vo -> processMeetingRoomAsync(vo, accessToken, unionId, timeRange[0], timeRange[1]))
+                    .collect(Collectors.toList());
+
+            // 等待所有完成,设置超时
+            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
+                    .get(25, TimeUnit.SECONDS); // 25秒总超时
+
+            return vos;
+        } catch (Exception e) {
+            throw new ServiceException("获取会议室信息失败: " + e.getMessage());
+        } finally {
+            long duration = System.currentTimeMillis() - startTime;
+            System.out.println("getMeetingInfo执行耗时: " + duration + "ms");
+        }
+    }
+
+    private String[] getTodayTimeRange() {
+        LocalDateTime startOfDay = LocalDateTime.now().with(LocalTime.MIDNIGHT);
+        ZonedDateTime startOfDayZoned = startOfDay.atZone(ZoneId.systemDefault());
+        String startTime = startOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
+                .format(DateTimeFormatter.ISO_INSTANT);
+
+        LocalDateTime endOfDay = LocalDateTime.now().with(LocalTime.MAX);
+        ZonedDateTime endOfDayZoned = endOfDay.atZone(ZoneId.systemDefault());
+        String endTime = endOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
+                .format(DateTimeFormatter.ISO_INSTANT);
+
+        return new String[]{startTime, endTime};
+    }
+    private List<MeetingVo> parseMeetingRooms(String meetingsJson) {
+        List<MeetingVo> vos = new ArrayList<>();
+        try {
+            JSONObject jsonObject = JSON.parseObject(meetingsJson);
             JSONArray resultArray = jsonObject.getJSONArray("result");
-            // 遍历数组,提取roomId和roomName
+
             for (int i = 0; i < resultArray.size(); i++) {
-                MeetingVo vo=new MeetingVo();
                 JSONObject roomObject = resultArray.getJSONObject(i);
-                String roomId = roomObject.getString("roomId");
-                String roomName = roomObject.getString("roomName");
-                vo.setRoomId(roomId);
-                vo.setFixedData(roomName);
+                MeetingVo vo = new MeetingVo();
+                vo.setRoomId(roomObject.getString("roomId"));
+                vo.setFixedData(roomObject.getString("roomName"));
+                vo.setStatus(1); // 默认状态
                 vos.add(vo);
             }
-            LocalDateTime startOfDay = LocalDateTime.now().with(LocalTime.MIDNIGHT);
-            ZonedDateTime startOfDayZoned = startOfDay.atZone(ZoneId.systemDefault());
-            String startTime=startOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
-                    .format(DateTimeFormatter.ISO_INSTANT);
-            LocalDateTime endOfDay = LocalDateTime.now().with(LocalTime.MAX);
-            ZonedDateTime endOfDayZoned = endOfDay.atZone(ZoneId.systemDefault());
-            String endTime= endOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
-                    .format(DateTimeFormatter.ISO_INSTANT);
-            for (MeetingVo vo : vos) {
-                String[] roomIds = new String[]{vo.getRoomId()};
-                String meetingHistory = getMeetingHistory(accessToken, unionId,roomIds,startTime,endTime);
-                List<ScheduleItem> scheduleItems = parseScheduleItemsWithStream(meetingHistory);
-                List<MeetingSchedule>list=new ArrayList<>();
-                if(!scheduleItems.isEmpty()){
-                    //循环查出预定的会议是否正在进行
-                    for (ScheduleItem item : scheduleItems) {
-                        String stringStartDateTime = extractTimeFromDateTime(item.getStartDateTime());
-                        String stringEndDateTime = extractTimeFromDateTime(item.getEndDateTime());
-                        //正在进行的会议
-                        if(isCurrentTimeInRange(item.getStartDateTime(),item.getEndDateTime())){
-                            try {
-                                vo.setStatus(2);
-                                String meetingList = getMeetingList(item.getOrganizerId(), accessToken);
-                                JSONObject meetingListjsonObject = JSON.parseObject(meetingList);
-                                JSONArray onGoingConfIdList = meetingListjsonObject.getJSONArray("onGoingConfIdList");
-                                String tatil = getMeetingDetail(accessToken, onGoingConfIdList.getString(0));
-                                String userID = getUserID(accessToken, item.getOrganizerId());
-                                Object o = getUserInfo(accessToken, "dept_id_list", userID);
-                                List<String> deptIdList = JSON.parseArray(o.toString(), String.class);
-                                String departmentInfo = getDepartmentInfo(accessToken, deptIdList.get(0));
-                                vo.setMeetingTheme(tatil);
-                                vo.setMeetingDept(departmentInfo);
-                                String name = (String)getUserInfo(accessToken, "name", userID);
-                                vo.setMeetingBooker(name);
-                                vo.setMeetingTime(formatDateTimeRangeWithFormatter(item.getStartDateTime(),item.getEndDateTime()));
-                                String allUser = getAllUser(onGoingConfIdList.getString(0), accessToken);
-                                vo.setParticipants(allUser);
-                                break;
-                            }catch (Exception e){
-                                break;
-                            }
-                        }
-                        //今日预约的会议
-                        MeetingSchedule schedule = new MeetingSchedule();
-                        String userID = getUserID(accessToken, item.getOrganizerId());
-                        Object o = getUserInfo(accessToken, "dept_id_list", userID);
-                        List<String> deptIdList = JSON.parseArray(o.toString(), String.class);
-                        String departmentInfo = getDepartmentInfo(accessToken, deptIdList.get(0));
-                        schedule.setReservationTime(stringStartDateTime+"~"+stringEndDateTime);
-                        schedule.setReservationDept(departmentInfo);
-                        vo.setStatus(1);
-                        list.add(schedule);
-                    }
-                }else {
-                    vo.setStatus(1);
+        } catch (Exception e) {
+            System.err.println("解析会议室列表失败: " + e.getMessage());
+        }
+        return vos;
+    }
+    @Async
+    protected CompletableFuture<Void> processMeetingRoomAsync(MeetingVo vo, String accessToken,
+                                                              String unionId, String startTime, String endTime) {
+        return CompletableFuture.runAsync(() -> {
+            try {
+                processMeetingRoom(vo, accessToken, unionId, startTime, endTime);
+            } catch (Exception e) {
+                System.err.println("处理会议室 " + vo.getFixedData() + " 失败: " + e.getMessage());
+                // 设置默认值,避免影响其他会议室
+                vo.setStatus(1);
+                vo.setMeetings(new ArrayList<>());
+                vo.setMeetingSession(0);
+            }
+        });
+    }
+    private void processMeetingRoom(MeetingVo vo, String accessToken, String unionId,
+                                    String startTime, String endTime) {
+        String[] roomIds = new String[]{vo.getRoomId()};
+        String meetingHistory = getMeetingHistory(accessToken, unionId, roomIds, startTime, endTime);
+        List<ScheduleItem> scheduleItems = parseScheduleItemsWithStream(meetingHistory);
+
+        List<MeetingSchedule> meetings = new ArrayList<>();
+        boolean hasOngoingMeeting = false;
+
+        for (ScheduleItem item : scheduleItems) {
+            if (hasOngoingMeeting) {
+                break; // 如果已经有进行中的会议,跳过后续处理
+            }
+
+            if (isCurrentTimeInRange(item.getStartDateTime(), item.getEndDateTime())) {
+                // 处理进行中的会议
+                processOngoingMeeting(vo, item, accessToken);
+                hasOngoingMeeting = true;
+            } else {
+                // 处理预约的会议
+                MeetingSchedule schedule = processScheduledMeeting(item, accessToken);
+                if (schedule != null) {
+                    meetings.add(schedule);
                 }
-                vo.setMeetingSession(list.size());
-                vo.setMeetings(list);
             }
+        }
+
+        vo.setMeetings(meetings);
+        vo.setMeetingSession(meetings.size());
+        if (!hasOngoingMeeting) {
+            vo.setStatus(1);
+        }
+    }
+
+    private void processOngoingMeeting(MeetingVo vo, ScheduleItem item, String accessToken) {
+        try {
+            vo.setStatus(2);
+
+            String meetingList = getMeetingList(item.getOrganizerId(), accessToken);
+            JSONObject meetingListJson = JSON.parseObject(meetingList);
+            JSONArray onGoingConfIdList = meetingListJson.getJSONArray("onGoingConfIdList");
+
+            if (onGoingConfIdList != null && !onGoingConfIdList.isEmpty()) {
+                String conferenceId = onGoingConfIdList.getString(0);
+                String meetingTitle = getMeetingDetail(accessToken, conferenceId);
+                vo.setMeetingTheme(meetingTitle);
+
+                String allUsers = getAllUser(conferenceId, accessToken);
+                vo.setParticipants(allUsers);
+            }
+
+            String userId = getUserID(accessToken, item.getOrganizerId());
+            String userName = (String) getUserInfo(accessToken, "name", userId);
+            vo.setMeetingBooker(userName);
+
+            Object deptInfo = getUserInfo(accessToken, "dept_id_list", userId);
+            if (deptInfo != null) {
+                List<String> deptIdList = JSON.parseArray(deptInfo.toString(), String.class);
+                if (!deptIdList.isEmpty()) {
+                    String departmentName = getDepartmentInfo(accessToken, deptIdList.get(0));
+                    vo.setMeetingDept(departmentName);
+                }
+            }
+
+            vo.setMeetingTime(formatDateTimeRangeWithFormatter(item.getStartDateTime(), item.getEndDateTime()));
+
         } catch (Exception e) {
-            e.printStackTrace();
+            System.err.println("处理进行中会议失败: " + e.getMessage());
+            vo.setStatus(1); // 出错时回退到预约状态
         }
-        return vos;
     }
+    private MeetingSchedule processScheduledMeeting(ScheduleItem item, String accessToken) {
+        try {
+            String startTime = extractTimeFromDateTime(item.getStartDateTime());
+            String endTime = extractTimeFromDateTime(item.getEndDateTime());
+
+            String userId = getUserID(accessToken, item.getOrganizerId());
+            Object deptInfo = getUserInfo(accessToken, "dept_id_list", userId);
 
-   public String getAllUser(String CONFERENCE_ID,String ACCESS_TOKEN){
-       CloseableHttpClient httpClient = HttpClients.createDefault();
-       try {
+            if (deptInfo != null) {
+                List<String> deptIdList = JSON.parseArray(deptInfo.toString(), String.class);
+                if (!deptIdList.isEmpty()) {
+                    String departmentName = getDepartmentInfo(accessToken, deptIdList.get(0));
+
+                    MeetingSchedule schedule = new MeetingSchedule();
+                    schedule.setReservationTime(startTime + "~" + endTime);
+                    schedule.setReservationDept(departmentName);
+                    return schedule;
+                }
+            }
+        } catch (Exception e) {
+            System.err.println("处理预约会议失败: " + e.getMessage());
+        }
+        return null;
+    }
+
+    public String getAllUser(String CONFERENCE_ID,String ACCESS_TOKEN){
+       try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
            // 构建请求 URL
            StringBuilder urlBuilder = new StringBuilder("https://api.dingtalk.com/v1.0/conference/videoConferences/")
                    .append(CONFERENCE_ID)
@@ -221,8 +333,7 @@ public class MeetingServiceImpl implements MeetingService {
     }
 
     public String getMeetingList(String UNION_ID, String ACCESS_TOKEN){
-        CloseableHttpClient httpClient = HttpClients.createDefault();
-        try {
+        try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
             // 构建请求 URL
             String url = "https://api.dingtalk.com/v1.0/conference/users/lists?unionId=" + UNION_ID;
             HttpGet httpGet = new HttpGet(url);
@@ -248,8 +359,7 @@ public class MeetingServiceImpl implements MeetingService {
     }
 
     public String getMeetingDetail(String ACCESS_TOKEN,String CONFERENCE_ID){
-        CloseableHttpClient httpClient = HttpClients.createDefault();
-        try {
+        try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
             // 构建请求 URL,包含会议 ID
             String url = "https://api.dingtalk.com/v1.0/conference/videoConferences/" + CONFERENCE_ID;
             HttpGet httpGet = new HttpGet(url);
@@ -278,8 +388,7 @@ public class MeetingServiceImpl implements MeetingService {
     }
 
     public  String getUserID(String ACCESS_TOKEN,String UNION_ID) throws Exception {
-        CloseableHttpClient httpClient = HttpClients.createDefault();
-        try {
+        try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
             // 构建请求 URL,包含 access_token 和 unionid 参数
             String url = "https://oapi.dingtalk.com/user/getUseridByUnionid?access_token=" + ACCESS_TOKEN + "&unionid=" + UNION_ID;
             HttpGet httpGet = new HttpGet(url);
@@ -332,7 +441,7 @@ public class MeetingServiceImpl implements MeetingService {
      * 查询部门信息
      */
     public String getDepartmentInfo(String accessToken, String deptId) throws Exception {
-        CloseableHttpClient httpClient = HttpClients.createDefault();
+        CloseableHttpClient httpClient = createHttpClientWithTimeout();
         String url = "https://oapi.dingtalk.com/topapi/v2/department/get?access_token=" + accessToken;
 
         HttpPost httpPost = new HttpPost(url);

+ 6 - 1
blade-service/blade-dingding/src/main/resources/application-dev.yml

@@ -1,7 +1,12 @@
 #服务器端口
 server:
   port: 9120
-
+  task:
+    execution:
+      pool:
+        core-size: 10
+        max-size: 20
+        queue-capacity: 100
 #数据源配置
 spring:
   datasource:

+ 6 - 1
blade-service/blade-dingding/src/main/resources/application-prod.yml

@@ -1,7 +1,12 @@
 #服务器端口
 server:
   port: 9120
-
+  task:
+    execution:
+      pool:
+        core-size: 10
+        max-size: 20
+        queue-capacity: 100
 #数据源配置
 spring:
   datasource:

+ 6 - 1
blade-service/blade-dingding/src/main/resources/application-test.yml

@@ -1,7 +1,12 @@
 #服务器端口
 server:
   port: 9120
-
+  task:
+    execution:
+      pool:
+        core-size: 10
+        max-size: 20
+        queue-capacity: 100
 #数据源配置
 spring:
   datasource:

+ 2 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

@@ -4812,11 +4812,11 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                     childContract.setAncestors(ancestors);
                     //wbsTreeContractMapper.updateAncestorsPid(ancestorsPId,ancestors,childContract.getPKeyId());
                 }
-                this.saveBatch(childContracts);
+                this.updateBatchById(childContracts);
             }
             //this.wbsTreeContractMapper.updateWbsTreeAncestors(contract);
         }
-        this.saveBatch(list);
+        this.updateBatchById(list);
         String ids = dto.getLeftPkeyIds().stream().map(id -> id + "").collect(Collectors.joining(","));
         this.wbsTreeContractStatisticsClient.updateAncestors(ids);
         return R.success("操作成功");