Ver Fonte

零流量低流量明细 可以上线了

lifuquan há 1 ano atrás
pai
commit
db4221060a

+ 19 - 0
doc/接口测试.md

@@ -0,0 +1,19 @@
+# 接口测试
+
+- 手动发送 零流量低流量明细
+
+```http
+POST http://127.0.0.1:11111/dingtalk-auto/task/zerotraffic/send HTTP/1.1
+Content-Type:application/json
+
+2023-06
+```
+
+- 撤回消息 零流量低流量明细
+
+```http
+POST http://127.0.0.1:11111/dingtalk-auto/task/zerotraffic/recall HTTP/1.1
+Content-Type:application/json
+
+9PiST3kl8lk2u1M2lejVheA1JJ2EI0JY8SPVEltsByc=
+```

+ 3 - 0
src/main/java/com/nokia/dingtalk_auto/config/TaskSchedulerConfig.java

@@ -5,6 +5,9 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 
+/**
+ * 启用任务调度并配置调度使用的线程池
+ */
 @Configuration
 @EnableScheduling
 public class TaskSchedulerConfig {

+ 37 - 5
src/main/java/com/nokia/dingtalk_auto/controller/ZeroTrafficTaskController.java

@@ -1,23 +1,55 @@
 package com.nokia.dingtalk_auto.controller;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import com.nokia.common.http.R;
 import com.nokia.dingtalk_auto.service.ZeroTrafficTaskService;
 
+/**
+ * 零流量低流量明细
+ */
+@RequestMapping("/dingtalk-auto/task/zerotraffic")
 @RestController
 public class ZeroTrafficTaskController {
 
     @Autowired
     private ZeroTrafficTaskService zeroTrafficTaskService;
 
-    public R recallMessage(String messageId) {
-        zeroTrafficTaskService.recallMessage(messageId);
-        return R.ok();
+    /**
+     * 撤回消息
+     * 
+     * @param messageId
+     * @return
+     */
+    @PostMapping("/recall")
+    public R recallMessage(@RequestBody String messageId) {
+        try {
+            zeroTrafficTaskService.recallMessage(messageId);
+            return R.ok().message("撤回成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+            return R.error().message(e.getMessage());
+        }
     }
 
-    public R sendMessageManually(String month) {
-        return R.ok();
+    /**
+     * 手动发送消息
+     * 
+     * @param month
+     * @return
+     */
+    @PostMapping("/send")
+    public R sendManually(@RequestBody String month) {
+        try {
+            zeroTrafficTaskService.runTaskManually(month);
+            return R.ok().message("发送成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+            return R.error().message(e.getMessage());
+        }
     }
 }

+ 160 - 52
src/main/java/com/nokia/dingtalk_auto/service/ZeroTrafficTaskService.java

@@ -1,19 +1,25 @@
 package com.nokia.dingtalk_auto.service;
 
 import java.io.File;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 import org.springframework.stereotype.Service;
 
 import com.nokia.common.dingtalk.DingtalkUtil;
 import com.nokia.common.ssh.SftpUtil;
 
 /**
- * 发送零流量低流量明细
+ * 零流量低流量明细发送
  */
 @Service
 public class ZeroTrafficTaskService {
@@ -46,43 +52,140 @@ public class ZeroTrafficTaskService {
     @Autowired
     private MessageService messageService;
 
-    public void runTask(String month) {
-        try {
+    @Autowired
+    private ThreadPoolTaskScheduler taskScheduler;
+
+    /**
+     * 定时任务,每个月2号早上8点半执行
+     */
+    @Scheduled(cron = "0 30 8 2 * *")
+    public void cronTask() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.MONTH, -1);
+        DateFormat format = new SimpleDateFormat("yyyy-MM");
+        String month = format.format(calendar.getTime());
+        // 每30分钟检查一次
+        checkRemoteDirAndWaitForFileOk(month, 1000L * 60 * 30).thenRun(() -> {
+            // 检查完成后下载
             download(month);
-        } catch (Exception e) {
-            String msg = e.getMessage();
-            if (msg.endsWith("No such file")) {
-                // 文件不存在
-                messageService.error("123456");
+        }).thenRun(() -> {
+            // 下载完成后发送
+            sendFiles(month);
+        }).exceptionally(ex -> {
+            // 处理异常--发送提醒并重新抛出异常
+            messageService.error(ex.getMessage());
+            throw new RuntimeException(ex.getMessage());
+        }).join();
+    }
+
+    /**
+     * 手动执行任务
+     * 
+     * @param month
+     */
+    public void runTaskManually(String month) {
+        CompletableFuture.runAsync(() -> {
+            download(month);
+        }, taskScheduler).thenRunAsync(() -> {
+            sendFiles(month);
+        }).exceptionally(ex -> {
+            // 处理异常--发送提醒并重新抛出异常
+            messageService.error(ex.getMessage());
+            throw new RuntimeException(ex.getMessage());
+        }).join();
+    }
+
+    /**
+     * 撤回消息
+     * 
+     * @param messageId
+     */
+    public void recallMessage(String messageId) {
+        dingtalkUtil.recallMessage(openConversationId, messageId);
+    }
+
+    /**
+     * 检查文件是否存在,如果不存在等待milliseconds毫秒后重新检查,直到文件已存在
+     * 
+     * @param month
+     * @param milliseconds 毫秒数
+     * @return
+     */
+    private CompletableFuture<Void> checkRemoteDirAndWaitForFileOk(String month, Long milliseconds) {
+        return CompletableFuture.runAsync(() -> {
+            checkRemoteDir(month);
+        }, taskScheduler).handle((result, ex) -> {
+            if (ex != null) {
+                String msg = ex.getMessage();
+                // 发现文件不存在
+                if (msg.endsWith("No such file")) {
+                    // 发送提醒
+                    messageService.error("零流量低流量明细账期 " + month + " 文件未具备,请提醒生产方进行生产。");
+                    // 等待一段时间
+                    sleep(milliseconds);
+                    // 重新检查
+                    return checkRemoteDirAndWaitForFileOk(month, milliseconds).join();
+                }
+                // 其他异常不进行重试
+                messageService.error("零流量低流量明细检查 " + month + " 账期文件时发生异常:" + msg);
+                // 重新抛出异常
+                throw new RuntimeException(ex.getMessage());
             }
-        }
+            // 没有异常时直接返回结果
+            return result;
+        });
     }
 
     /**
-     * 发送文件
+     * 发送文件,两个文件,包括一个截图和一个excel
      * 
      * @param month 2023-06 样式的表示月份的字符串
      */
-    public void sendFiles(String month) {
+    private void sendFiles(String month) {
         String localPath = localDir + month;
         File[] files = new File(localPath).listFiles();
         List<String> messageIds = new ArrayList<>();
-        // 根据发送文件的后缀发送文件,保证发送顺序
+        // 文件是否存在的标识
+        boolean[] flags = new boolean[2];
+        // 检查文件是否存在
         for (File file : files) {
             if (file.getName().toLowerCase().endsWith("1.png")) {
-                String mediaId = dingtalkUtil.upload(file.getAbsolutePath(), "image");
-                String messageId = dingtalkUtil.sendImage(openConversationId, mediaId);
-                messageIds.add(messageId);
+                flags[0] = true;
             }
         }
         for (File file : files) {
             if (file.getName().toLowerCase().endsWith(month + ".xlsx")) {
-                String mediaId = dingtalkUtil.upload(file.getAbsolutePath(), "file");
-                String messageId = dingtalkUtil.SendFile(openConversationId, mediaId, file.getName());
-                messageIds.add(messageId);
+                flags[1] = true;
+            }
+        }
+        if (flags[0] && flags[1]) {
+            // 两个文件都存在才进行发送
+            // 根据发送文件的后缀发送文件,保证发送顺序
+            for (File file : files) {
+                if (file.getName().toLowerCase().endsWith("1.png")) {
+                    String mediaId = dingtalkUtil.upload(file.getAbsolutePath(), "image");
+                    String messageId = dingtalkUtil.sendImage(openConversationId, mediaId);
+                    messageIds.add(messageId);
+                }
             }
+            for (File file : files) {
+                if (file.getName().toLowerCase().endsWith(month + ".xlsx")) {
+                    String mediaId = dingtalkUtil.upload(file.getAbsolutePath(), "file");
+                    String messageId = dingtalkUtil.SendFile(openConversationId, mediaId, file.getName());
+                    messageIds.add(messageId);
+                }
+            }
+            messageService.message(String.format("零流量低流量 %s 账期 完成发送 ==消息id: %s", month, messageIds));
+        } else {
+            // 如果缺少文件,抛出异常
+            StringBuilder stringBuilder = new StringBuilder("零流量低流量 ").append(month).append(" 账期缺少文件:");
+            if (!flags[0]) {
+                stringBuilder.append("==截图文件==");
+            } else if (!flags[1]) {
+                stringBuilder.append("==excel文件==");
+            }
+            throw new RuntimeException(stringBuilder.toString());
         }
-        messageService.message(String.format("零流量低流量 %s 账期 完成发送 ==消息id: %s", month, messageIds));
     }
 
     /**
@@ -90,22 +193,15 @@ public class ZeroTrafficTaskService {
      * 
      * @param month 2023-06 样式的表示月份的字符串
      */
-    public void download(String month) {
+    private void download(String month) {
         // 创建SftpUtil
-        SftpUtil sftpUtil = new SftpUtil()
-                .setHost(remoteHost)
-                .setPort(remotePort)
-                .setUser(remoteUser)
-                .setPassword(remotePassword);
-
+        SftpUtil sftpUtil = getSftpUtil();
         String remotePath = remoteDir + month;
         String localPath = localDir + month;
-
         File localFile = new File(localPath);
         if (!localFile.exists()) {
             localFile.mkdirs();
         }
-
         try {
             // 连接到sftp服务器
             sftpUtil.connect();
@@ -121,42 +217,54 @@ public class ZeroTrafficTaskService {
     }
 
     /**
-     * 手动下载文件
+     * 等待一段时间
      * 
-     * @param month 2023-06 样式的表示月份的字符串
+     * @param milliseconds 等待的毫秒数
+     * @return
      */
-    public void downloadManually(String month) {
-        SftpUtil sftpUtil = new SftpUtil()
-                .setHost(remoteHost)
-                .setPort(remotePort)
-                .setUser(remoteUser)
-                .setPassword(remotePassword);
-        String remotePath = remoteDir + month;
-        String localPath = localDir + month;
-
-        File localFile = new File(localPath);
-
-        if (!localFile.exists()) {
-            localFile.mkdirs();
+    private void sleep(Long milliseconds) {
+        try {
+            Thread.sleep(milliseconds);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
         }
+    }
 
+    /**
+     * 检查文件是否存在
+     * 
+     * @param month
+     * @return
+     * @throws Exception
+     */
+    private void checkRemoteDir(String month) {
+        SftpUtil sftpUtil = getSftpUtil();
+        String remotePath = remoteDir + month;
         try {
-
+            // 连接到sftp服务器
             sftpUtil.connect();
+            // ls如果路径不存在会触发RuntimeException,携带消息No such file
             List<String> files = sftpUtil.ls(remotePath);
-            for (String fileName : files) {
-                sftpUtil.get(remotePath + "/" + fileName, localPath + "/" + fileName);
+            if (files.size() == 0) {
+                // 如果路径存在,但路径下没有文件,抛出RuntimeException,携带消息No such file
+                throw new RuntimeException("No such file");
             }
-        } catch (Exception e) {
-            // 下载失败
-            e.printStackTrace();
         } finally {
-            // 从sftp服务器断开连接
             sftpUtil.disconnect();
         }
     }
 
-    public void recallMessage(String messageId) {
-        dingtalkUtil.recallMessage(openConversationId, messageId);
+    /**
+     * 获取Sftp连接工具SftpUtil
+     * 
+     * @return
+     */
+    private SftpUtil getSftpUtil() {
+        // 创建SftpUtil
+        return new SftpUtil()
+                .setHost(remoteHost)
+                .setPort(remotePort)
+                .setUser(remoteUser)
+                .setPassword(remotePassword);
     }
 }

+ 2 - 7
src/test/java/com/nokia/dingtalk_auto/DingtalkAutoApplicationTest.java

@@ -3,7 +3,6 @@ package com.nokia.dingtalk_auto;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
-
 import com.nokia.dingtalk_auto.service.ZeroTrafficTaskService;
 
 @SpringBootTest
@@ -13,12 +12,8 @@ public class DingtalkAutoApplicationTest {
     private ZeroTrafficTaskService zeroTrafficSendService;
 
     @Test
-    void test() {
-        zeroTrafficSendService.download("2023-07");
+    void test() throws Exception {
+        zeroTrafficSendService.cronTask();
     }
 
-    @Test
-    void test1() {
-        zeroTrafficSendService.recallMessage("Y3yL5KMxxasU4YGNRJ3riz2jsDZsWl43G2AK8QfOyP4=");
-    }
 }