shaoguo 7 meses atrás
pai
commit
d1ff61b678

+ 94 - 72
src/main/java/com/sqx/modules/resumes/service/impl/ResumesServiceImpl.java

@@ -744,155 +744,177 @@ public class ResumesServiceImpl extends ServiceImpl<ResumesDao, Resumes> impleme
     }
 
 
+    /**
+     * 发送简历邮件
+     * @param resumesId 简历ID
+     * @param to 收件人邮箱
+     * @param resumesName 简历名称
+     * @param resumesAttachmentId 简历附件ID
+     */
     public void sendEmail(Long resumesId, String to, String resumesName, Long resumesAttachmentId) {
-        // 入参非空校验
-//        if (StringUtils.isEmpty(to) || StringUtils.isEmpty(resumesName)) {
-//            log.error("邮件发送入参异常:收件人/简历名称为空,to={}, resumesName={}", to, resumesName);
-//            return;
-//        }
+        // to = "18064109218@163.com";
+        // 1. 入参校验优化
+        if (StringUtils.isEmpty(to)) {
+            log.error("邮件发送失败:收件人邮箱为空,resumesId={}", resumesId);
+            return;
+        }
+        // resumesName = resumesName + ".pdf";
+        if (StringUtils.isEmpty(resumesName)) {
+            log.error("邮件发送失败:简历名称为空,resumesId={}, to={}", resumesId, to);
+            return;
+        }
+        if (!to.matches("^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$")) {
+            log.error("邮件发送失败:收件人邮箱格式不正确,resumesId={}, to={}", resumesId, to);
+            return;
+        }
 
-//        to="18064109218@163.com";
-        // 1. 读取配置(保留原有逻辑)
+        // 2. 读取配置
         String from = commonInfoService.findOne(308).getValue();
         String authCode = commonInfoService.findOne(309).getValue();
         String host = commonInfoService.findOne(427).getValue();
 
-        // 配置非空校验
+        // 配置校验
         if (StringUtils.isEmpty(from) || StringUtils.isEmpty(authCode)) {
-            log.error("发件人邮箱/授权码配置为空,from={}, authCode={}", from, authCode);
+            log.error("邮件发送失败:发件人邮箱/授权码配置为空,from={}", from);
             return;
         }
         if (StringUtils.isEmpty(host)) {
-            host = "smtp.163.com"; // 兜底默认值
+            host = "smtp.163.com"; // 默认值
             log.warn("邮件服务器配置为空,使用默认值:smtp.163.com");
         }
 
-        // 2. 核心配置修复(解决465端口连接问题)
+        // 3. 邮件配置优化
         Properties properties = new Properties();
         properties.setProperty("mail.smtp.host", host);
         properties.setProperty("mail.smtp.port", "465");
         properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
-        properties.setProperty("mail.smtp.socketFactory.port", "465"); // 新增:绑定SocketFactory端口
-        properties.setProperty("mail.smtp.socketFactory.fallback", "false"); // 新增:禁止降级非SSL
-        properties.setProperty("mail.smtp.ssl.enable", "true"); // 新增:强制开启SSL(解决isSSL false)
+        properties.setProperty("mail.smtp.socketFactory.port", "465");
+        properties.setProperty("mail.smtp.socketFactory.fallback", "false");
+        properties.setProperty("mail.smtp.ssl.enable", "true");
         properties.setProperty("mail.transport.protocol", "smtp");
-        properties.setProperty("mail.debug", "true");
+        properties.setProperty("mail.debug", "true"); // 生产环境关闭调试
         properties.setProperty("mail.smtp.auth", "true");
-        properties.setProperty("mail.mime.charset", "UTF-8"); // 新增:防止中文乱码
+        properties.setProperty("mail.mime.charset", "UTF-8");
 
-        // 3. 创建Session(修复授权码重复读取问题)
-        Session session = Session.getDefaultInstance(properties, new Authenticator() {
+        // 4. Session创建优化:使用getInstance提高线程安全性
+        Session session = Session.getInstance(properties, new Authenticator() {
             @Override
             public PasswordAuthentication getPasswordAuthentication() {
-                return new PasswordAuthentication(from, authCode); // 直接用已读取的authCode,避免重复查库
+                return new PasswordAuthentication(from, authCode);
             }
         });
 
         try {
-            // 4. 构建邮件(保留原有逻辑,仅修复附件处理)
+            // 5. 构建邮件
             MimeMessage message = new MimeMessage(session);
 
-            // 设置发件人(保留原有逻辑)
+            // 设置发件人
             InternetAddress fromMail = new InternetAddress(from);
-            String name = commonInfoService.findOne(12).getValue();
-            fromMail.setPersonal(MimeUtility.encodeText((StringUtils.isEmpty(name) ? "系统管理员" : name) + "<" + from + ">"));
+            String senderName = commonInfoService.findOne(12).getValue();
+            fromMail.setPersonal(MimeUtility.encodeText((StringUtils.isEmpty(senderName) ? "系统管理员" : senderName) + "<" + from + ">"));
             message.setFrom(fromMail);
 
-            // 设置收件人(保留原有逻辑)
-            InternetAddress toMail = new InternetAddress(to);
-            Address[] allRecipients = {toMail};
-            message.setRecipients(Message.RecipientType.TO, allRecipients);
+            // 设置收件人(优化:使用单个收件人方法)
+            message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
 
-            // 设置主题(保留原有逻辑)
+            // 设置主题和发送时间
             message.setSubject("收到一封投递简历:" + resumesName + ",请您查收!");
             message.setSentDate(new Date());
 
-            // 混合内容(保留原有逻辑)
+            // 混合内容
             MimeMultipart msgMultipart = new MimeMultipart("mixed");
             message.setContent(msgMultipart);
 
-            // 文本内容(保留原有逻辑)
+            // 文本内容
             MimeBodyPart htmlPart = new MimeBodyPart();
             htmlPart.setContent("收到一封简历投递:" + resumesName + ",请您查收!", "text/html;charset=UTF-8");
             msgMultipart.addBodyPart(htmlPart);
 
-            // 5. 附件处理(核心修复:网络URL转本地文件)
+            // 6. 附件处理优化
             if (resumesAttachmentId != null) {
                 ResumesAttachment resumesAttachment = resumesAttachmentService.getById(resumesAttachmentId);
                 if (resumesAttachment != null) {
                     String url = resumesAttachment.getAttachmentAddress();
                     if (StringUtils.isNotEmpty(url)) {
-                        // 修复:网络URL先下载到本地临时文件
-                        File localFile = downloadUrlToLocal(url);
-                        if (localFile != null && localFile.exists()) {
+                        try {
+                            // 直接使用URLDataSource,避免本地下载
+                            URL attachmentUrl = new URL(url);
                             MimeBodyPart filePart = new MimeBodyPart();
-                            FileDataSource file_datasource = new FileDataSource(localFile);
-                            DataHandler dh = new DataHandler(file_datasource);
+                            URLDataSource dataSource = new URLDataSource(attachmentUrl);
+                            DataHandler dh = new DataHandler(dataSource);
                             filePart.setDataHandler(dh);
-                            // 附件名编码(保留原有逻辑)
-                            filePart.setFileName(MimeUtility.encodeText(dh.getName()));
+                            
+                            // 优化文件名处理
+                            String fileName = dh.getName();
+                            if (StringUtils.isEmpty(fileName)) {
+                                fileName = "简历-" + resumesName + ".pdf";
+                            } else if (!fileName.contains(".")) {
+                                fileName += ".pdf";
+                            }
+                            filePart.setFileName(MimeUtility.encodeText(fileName, "UTF-8", null));
+                            
                             msgMultipart.addBodyPart(filePart);
-                            localFile.deleteOnExit(); // 新增:JVM退出时删除临时文件
-                        } else {
-                            log.error("附件下载失败,跳过附件发送:url={}", url);
+                            log.debug("添加简历附件成功:resumesId={}, fileName={}", resumesId, fileName);
+                        } catch (MalformedURLException e) {
+                            log.error("附件URL格式错误:resumesId={}, url={}", resumesId, url, e);
+                        } catch (Exception e) {
+                            log.error("附件处理失败:resumesId={}, url={}", resumesId, url, e);
                         }
                     } else {
-                        log.error("简历附件地址为空:resumesAttachmentId={}", resumesAttachmentId);
+                        log.warn("简历附件地址为空:resumesId={}, attachmentId={}", resumesId, resumesAttachmentId);
                     }
                 } else {
-                    log.error("未查询到简历附件:resumesAttachmentId={}", resumesAttachmentId);
+                    log.warn("未查询到简历附件:resumesId={}, attachmentId={}", resumesId, resumesAttachmentId);
                 }
             }
 
-            // 6. 发送邮件(修复:真正调用发送方法
+            // 7. 发送邮件(优化:使用try-finally确保资源释放
             message.saveChanges();
             
-            // 使用Transport对象发送邮件
-            Transport transport = session.getTransport("smtp");
+            Transport transport = null;
             try {
+                transport = session.getTransport("smtp");
                 transport.connect(host, 465, from, authCode);
                 transport.sendMessage(message, message.getAllRecipients());
                 log.info("邮件发送成功:resumesId={}, to={}, resumesName={}", resumesId, to, resumesName);
             } finally {
                 if (transport != null) {
-                    transport.close();
+                    try {
+                        transport.close();
+                    } catch (MessagingException e) {
+                        log.error("关闭邮件传输连接失败:{}", e.getMessage(), e);
+                    }
                 }
             }
 
         } catch (AuthenticationFailedException e) {
-            log.error("邮件发送认证失败:检查授权码是否正确,from={}, to={}, error={}", from, to, e.getMessage(), e);
+            log.error("邮件发送认证失败:请检查授权码是否正确,from={}, to={}", from, to, e);
+        } catch (javax.mail.SendFailedException e) {
+            // 单独处理发送失败异常
+            String failedAddresses = "";
+            if (e.getInvalidAddresses() != null && e.getInvalidAddresses().length > 0) {
+                StringBuilder sb = new StringBuilder();
+                for (javax.mail.Address addr : e.getInvalidAddresses()) {
+                    sb.append(addr.toString()).append(", ");
+                }
+                if (sb.length() > 0) {
+                    sb.setLength(sb.length() - 2);
+                }
+                failedAddresses = sb.toString();
+            }
+            log.error("邮件发送失败:收件人地址无效,无效地址={}, 错误信息={}, resumesId={}", 
+                      failedAddresses, e.getMessage(), resumesId, e);
         } catch (MessagingException e) {
-            log.error("邮件发送失败:from={}, to={}, error={}", from, to, e.getMessage(), e);
+            log.error("邮件发送失败:SMTP服务器错误,from={}, to={}", from, to, e);
         } catch (Exception e) {
-            log.error("发送邮件异常:resumesId={}, 异常信息={}", resumesId, e.getMessage(), e);
+            log.error("邮件发送异常:resumesId={}, to={}, resumesName={}", resumesId, to, resumesName, e);
         }
     }
 
     /**
      * 辅助方法:下载网络URL到本地临时文件(仅新增此方法,不改动原有逻辑)
      */
-    private File downloadUrlToLocal(String url) {
-        try {
-            // 创建临时文件
-            File tempFile = File.createTempFile("resume_", url.contains(".") ? url.substring(url.lastIndexOf(".")) : ".pdf");
-            tempFile.deleteOnExit();
-
-            // 下载URL内容到本地
-            URL netUrl = new URL(url);
-            try (InputStream in = netUrl.openStream();
-                 FileOutputStream out = new FileOutputStream(tempFile)) {
-                byte[] buffer = new byte[1024 * 8];
-                int len;
-                while ((len = in.read(buffer)) != -1) {
-                    out.write(buffer, 0, len);
-                }
-            }
-            return tempFile;
-        } catch (Exception e) {
-            log.error("下载网络文件失败:url={}", url, e);
-            return null;
-        }
-    }
+
 
 
     public String exportPdf(Long resumesId) {