24282 2 anos atrás
pai
commit
78342ca698

+ 21 - 0
src/main/java/com/fjhx/config/exception/EmailEngineException.java

@@ -0,0 +1,21 @@
+package com.fjhx.config.exception;
+
+import cn.hutool.http.HttpStatus;
+import lombok.Getter;
+
+@Getter
+public class EmailEngineException extends RuntimeException {
+
+    private final Integer errorCode;
+
+    private final String errorMsg;
+
+    // 传入业务异常说明
+    public EmailEngineException(String errorMsg) {
+        super(errorMsg);
+
+        this.errorCode = HttpStatus.HTTP_BAD_REQUEST;
+        this.errorMsg = errorMsg;
+    }
+
+}

+ 5 - 0
src/main/java/com/fjhx/constants/RedisConstant.java

@@ -9,4 +9,9 @@ public interface RedisConstant {
      */
     String PROGRESS_KEY = PREFIX + "progressKey:";
 
+    /**
+     * 下载失败附件key
+     */
+    String DOWNLOAD_FAIL_FILE_KEY = PREFIX + "downloadFailFileKey:";
+
 }

+ 61 - 46
src/main/java/com/fjhx/service/impl/AccountServiceImpl.java

@@ -10,10 +10,14 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fjhx.config.TaskPoolConfig;
+import com.fjhx.config.exception.EmailEngineException;
 import com.fjhx.config.redis.RedisCache;
 import com.fjhx.constants.RedisConstant;
 import com.fjhx.constants.SendConstant;
-import com.fjhx.entity.*;
+import com.fjhx.entity.EmailInfo;
+import com.fjhx.entity.EmailMessage;
+import com.fjhx.entity.EmailMessageAttachment;
+import com.fjhx.entity.EmailMessageSend;
 import com.fjhx.enums.SendEventEnum;
 import com.fjhx.service.*;
 import com.fjhx.utils.EmailEngineUtil;
@@ -37,9 +41,6 @@ public class AccountServiceImpl implements IAccountService {
     private IEmailInfoService emailInfoService;
 
     @Autowired
-    private IEmailMailboxService emailMailboxService;
-
-    @Autowired
     private IEmailMessageService emailMessageService;
 
     @Autowired
@@ -56,10 +57,12 @@ public class AccountServiceImpl implements IAccountService {
     @Override
     public EmailInfo binding(BindingVo bindingVo) {
 
+        EmailInfo emailInfo;
+
         try {
             String email = bindingVo.getEmail();
 
-            EmailInfo emailInfo = emailInfoService.getOne(Wrappers.<EmailInfo>lambdaQuery().eq(EmailInfo::getEmail, email));
+            emailInfo = emailInfoService.getOne(Wrappers.<EmailInfo>lambdaQuery().eq(EmailInfo::getEmail, email));
             // 如果存在,直接返回邮箱信息
             if (emailInfo != null) {
                 return emailInfo;
@@ -70,14 +73,15 @@ public class AccountServiceImpl implements IAccountService {
             EmailEngineUtil.createAccount(bindingVo);
             // redis添加同步进度
             this.progressInitialization(bindingVo);
-            // 异步遍历文件夹下的所有邮件
-            this.asyncReadEmail(emailInfo.getId(), bindingVo);
-            return emailInfo;
+
         } catch (Exception e) {
             EmailEngineUtil.deleteAccount(bindingVo.getEmail());
             throw e;
         }
 
+        // 异步遍历文件夹下的所有邮件
+        this.asyncReadEmail(emailInfo.getId(), bindingVo, 19);
+        return emailInfo;
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -123,17 +127,12 @@ public class AccountServiceImpl implements IAccountService {
         String email = bindingVo.getEmail();
         int pages = bindingVo.getPages();
 
+        MessageVo messageVo = EmailEngineUtil.getMessageList(email, bindingVo.getPath(), 1);
+
         ProgressVo progressVo = new ProgressVo();
         progressVo.setEmail(email);
         progressVo.setCompleteMessageCount(0);
         progressVo.setPercentage(0);
-        progressVo.setInit(false);
-        RedisCache.set(RedisConstant.PROGRESS_KEY + email, progressVo);
-
-        ThreadUtil.sleep(1000L);
-
-        MessageVo messageVo = EmailEngineUtil.getMessageList(email, bindingVo.getPath(), 1);
-        progressVo.setInit(true);
         progressVo.setTotalMessageCount(messageVo.getTotal() > pages * 10 ? pages * 10 : messageVo.getTotal());
         RedisCache.set(RedisConstant.PROGRESS_KEY + email, progressVo);
     }
@@ -141,40 +140,57 @@ public class AccountServiceImpl implements IAccountService {
     /**
      * 异步读取文件
      */
-    private void asyncReadEmail(Long emailInfoId, BindingVo bindingVo) {
+    private void asyncReadEmail(Long emailInfoId, BindingVo bindingVo, Integer pageFlag) {
         String email = bindingVo.getEmail();
         int pages = bindingVo.getPages();
         String mailbox = bindingVo.getPath();
 
         executor.execute(() -> {
             ThreadUtil.sleep(3000);
+            int page = pageFlag;
+            try {
 
-            // 记录上次消息id,防止循环查询分页过程中接收到了新邮件,出现邮件重复问题
-            List<String> lastMessageIdList = new ArrayList<>();
+                // 记录上次消息id,防止循环查询分页过程中接收到了新邮件,出现邮件重复问题
+                List<String> lastMessageIdList = new ArrayList<>();
 
-            int page = 0;
-            while (page < pages) {
-                MessageVo result = EmailEngineUtil.getMessageList(email, mailbox, page);
-                List<MessageVo.MessagesDTO> messagesDTOList = result.getMessages();
-                if (messagesDTOList.size() > 0) {
-                    // 批量保存邮件信息
-                    List<EmailMessage> emailMessageList = this.saveBatchMessage(emailInfoId, email, lastMessageIdList, messagesDTOList);
+                while (page < pages) {
 
-                    // 更新同步邮件进度
-                    this.synchronizationProgress(email, messagesDTOList);
+                    // 分页获取文件夹邮件
+                    MessageVo result = EmailEngineUtil.getMessageList(email, mailbox, page);
+
+                    List<MessageVo.MessagesDTO> messagesDTOList = result.getMessages();
+
+                    if (messagesDTOList.size() > 0) {
+
+                        // 批量保存邮件信息
+                        List<EmailMessage> emailMessageList = this.saveBatchMessage(emailInfoId, email, lastMessageIdList, messagesDTOList);
+
+                        // 更新同步邮件进度
+                        this.synchronizationProgress(email, messagesDTOList);
+
+                        // 记录上次保存的邮件id
+                        lastMessageIdList.clear();
+                        for (EmailMessage emailMessage : emailMessageList) {
+                            lastMessageIdList.add(emailMessage.getMessageId());
+                        }
 
-                    // 记录上次保存的邮件id
-                    lastMessageIdList.clear();
-                    for (EmailMessage emailMessage : emailMessageList) {
-                        lastMessageIdList.add(emailMessage.getMessageId());
                     }
+                    page++;
 
                     ThreadUtil.sleep(3000);
                 }
-                page++;
+
+            } catch (EmailEngineException e) {
+                log.error("下载失败,等待5分钟");
+                ThreadUtil.sleep(1000 * 60 * 5);
+
+                asyncReadEmail(emailInfoId, bindingVo, page);
+            } catch (Exception e) {
+                log.error("未知原因同步文件夹失败:{}", email, e);
             }
 
         });
+
     }
 
     /**
@@ -305,23 +321,22 @@ public class AccountServiceImpl implements IAccountService {
 
                 String newFileName = attachmentId + "." + FileUtil.getSuffix(attachment.getFilename());
 
+                EmailMessageAttachment emailMessageAttachment = new EmailMessageAttachment();
+                emailMessageAttachment.setEmailMessageId(emailMessageId);
+                emailMessageAttachment.setMessageId(messagesDTO.getId());
+                emailMessageAttachment.setName(attachment.getFilename());
+                emailMessageAttachment.setPath(email + "\\" + newFileName);
+                emailMessageAttachment.setAttachmentId(attachmentId);
+                emailMessageAttachment.setSize(attachment.getEncodedSize());
+                emailMessageAttachmentList.add(emailMessageAttachment);
+
                 // 下载附件
                 try {
-                    Boolean flag = RetryUtil.execute(() -> EmailEngineUtil.downloadAttachment(email, attachmentId, newFileName));
-
-                    if (flag) {
-                        EmailMessageAttachment emailMessageAttachment = new EmailMessageAttachment();
-                        emailMessageAttachment.setEmailMessageId(emailMessageId);
-                        emailMessageAttachment.setMessageId(messagesDTO.getId());
-                        emailMessageAttachment.setName(attachment.getFilename());
-                        emailMessageAttachment.setPath(email + "\\" + newFileName);
-                        emailMessageAttachment.setAttachmentId(attachmentId);
-                        emailMessageAttachment.setSize(attachment.getEncodedSize());
-                        emailMessageAttachmentList.add(emailMessageAttachment);
-                    }
-
+                    RetryUtil.execute(() -> EmailEngineUtil.downloadAttachment(email, attachmentId, newFileName));
                 } catch (Exception e) {
-                    log.error("下载附件失败:", e);
+                    log.error("下载附件失败:email:{},attachmentId:{}", email, attachmentId, e);
+
+                    RedisCache.set(RedisConstant.DOWNLOAD_FAIL_FILE_KEY + email + ":" + attachmentId, emailMessageAttachment);
                 }
 
             }

+ 31 - 46
src/main/java/com/fjhx/utils/EmailEngineUtil.java

@@ -5,7 +5,7 @@ import cn.hutool.core.lang.Assert;
 import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
-import com.fjhx.config.exception.ServiceException;
+import com.fjhx.config.exception.EmailEngineException;
 import com.fjhx.vo.*;
 import com.sun.istack.internal.NotNull;
 import lombok.extern.slf4j.Slf4j;
@@ -18,7 +18,6 @@ import org.springframework.web.client.RestTemplate;
 
 import java.io.*;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 @Slf4j
@@ -49,10 +48,10 @@ public class EmailEngineUtil {
 
                 HttpStatus.Series series = response.getStatusCode().series();
                 if (HttpStatus.Series.CLIENT_ERROR.equals(series)) {
-                    throw new ServiceException(result);
+                    throw new RuntimeException(result);
                 }
 
-                throw new RuntimeException(result);
+                throw new EmailEngineException(result);
             }
 
         });
@@ -93,14 +92,14 @@ public class EmailEngineUtil {
         delete("v1/account/" + email, new HashMap<>());
     }
 
-    /**
-     * 查看邮箱所有文件夹
-     */
-    public static List<EmailMailboxVo.MailboxesDTO> getMailboxList(String email) {
-        String url = "v1/account/" + email + "/mailboxes?counters=true";
-        EmailMailboxVo result = get(url, EmailMailboxVo.class);
-        return result.getMailboxes();
-    }
+    // /**
+    //  * 查看邮箱所有文件夹
+    //  */
+    // public static List<EmailMailboxVo.MailboxesDTO> getMailboxList(String email) {
+    //     String url = "v1/account/" + email + "/mailboxes?counters=true";
+    //     EmailMailboxVo result = get(url, EmailMailboxVo.class);
+    //     return result.getMailboxes();
+    // }
 
     /**
      * 查看文件夹的所有邮件
@@ -121,17 +120,21 @@ public class EmailEngineUtil {
     /**
      * 下载附件
      */
-    public static boolean downloadAttachment(String email, String attachmentId, String fileName) throws FileNotFoundException {
-        File file = new File(attachmentPath + email);
-        if (!file.exists()) {
-            boolean mkdir = file.mkdir();
-            Assert.isTrue(mkdir, "创建文件夹失败");
-            return false;
-        }
+    public static boolean downloadAttachment(String email, String attachmentId, String fileName) {
+        try {
+            File file = new File(attachmentPath + email);
+            if (!file.exists()) {
+                boolean mkdir = file.mkdir();
+                Assert.isTrue(mkdir, "创建文件夹失败");
+                return false;
+            }
 
-        FileOutputStream fileOutputStream = new FileOutputStream(attachmentPath + email + "\\" + fileName);
-        download("v1/account/" + email + "/attachment/" + attachmentId, fileOutputStream);
-        return true;
+            FileOutputStream fileOutputStream = new FileOutputStream(attachmentPath + email + "\\" + fileName);
+            download("v1/account/" + email + "/attachment/" + attachmentId, fileOutputStream);
+            return true;
+        } catch (Exception e) {
+            throw new EmailEngineException("下载附件失败");
+        }
     }
 
     public static void submit(SubmitVo submitVo) {
@@ -216,36 +219,18 @@ public class EmailEngineUtil {
     }
 
     public static <T> T get(String url, Class<T> cls) {
-        try {
-            return RetryUtil.execute(() -> restTemplate.getForObject(urlPrefix + url, cls), 5, 5000L);
-        } catch (ServiceException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        return RetryUtil.execute(() -> restTemplate.getForObject(urlPrefix + url, cls), 5, 5000L);
     }
 
     public static <T> T post(String url, Object paramObj, Class<T> cls) {
-        try {
-            return RetryUtil.execute(() -> restTemplate.postForObject(urlPrefix + url, paramObj, cls), 5, 3000L);
-        } catch (ServiceException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        return RetryUtil.execute(() -> restTemplate.postForObject(urlPrefix + url, paramObj, cls), 5, 3000L);
     }
 
     public static void delete(String url, Map<String, Object> map) {
-        try {
-            RetryUtil.execute(() -> {
-                restTemplate.delete(urlPrefix + url, map);
-                return null;
-            }, 5, 3000L);
-        } catch (ServiceException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        RetryUtil.execute(() -> {
+            restTemplate.delete(urlPrefix + url, map);
+            return null;
+        }, 5, 3000L);
     }
 
 }

+ 8 - 9
src/main/java/com/fjhx/utils/RetryUtil.java

@@ -1,7 +1,7 @@
 package com.fjhx.utils;
 
 import cn.hutool.core.thread.ThreadUtil;
-import com.fjhx.config.exception.ServiceException;
+import com.fjhx.config.exception.EmailEngineException;
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
@@ -12,7 +12,7 @@ public class RetryUtil {
      * 默认执行3次
      * 每次失败等待1秒
      */
-    public static <T> T execute(RetryRunnable<T> runnable) throws Exception {
+    public static <T> T execute(RetryRunnable<T> runnable) {
         return execute(runnable, 0, 3, 1000L);
     }
 
@@ -24,24 +24,23 @@ public class RetryUtil {
      * @param sleep    重试间隔
      * @param <T>      返回值类型
      * @return runnable执行结果
-     * @throws Exception runnable抛出的异常
      */
-    public static <T> T execute(RetryRunnable<T> runnable, int maxCount, Long sleep) throws Exception {
+    public static <T> T execute(RetryRunnable<T> runnable, int maxCount, Long sleep) {
         return execute(runnable, 0, maxCount, sleep);
     }
 
-    private static <T> T execute(RetryRunnable<T> runnable, int executeCount, int maxCount, Long sleep) throws Exception {
+    private static <T> T execute(RetryRunnable<T> runnable, int executeCount, int maxCount, Long sleep) {
         try {
             return runnable.run();
-        } catch (ServiceException e) {
-            throw e;
-        } catch (Exception e) {
+        } catch (EmailEngineException e) {
             if (executeCount >= maxCount) {
                 throw e;
             }
-            // log.warn("任务执行失败,已失败{}次,最多允许失败{}次,{}秒后开始重试", executeCount + 1, maxCount, sleep / 1000, e);
+            log.warn("任务执行失败,已失败{}次,最多允许失败{}次,{}秒后开始重试", executeCount + 1, maxCount, sleep / 1000, e);
             ThreadUtil.sleep(sleep);
             return execute(runnable, ++executeCount, maxCount, sleep);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
         }
     }
 

+ 0 - 5
src/main/java/com/fjhx/vo/ProgressVo.java

@@ -29,9 +29,4 @@ public class ProgressVo implements Serializable {
      */
     private Integer percentage;
 
-    /**
-     * 是否初始化
-     */
-    private Boolean init;
-
 }