首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> JSP 程式設計 >> 關於JSP

JSP SmartUpload 文件上傳與 JavaMail 郵件發送完整實戰代碼

     編輯:關於JSP

依賴準備

<!-- SmartUpload (舊項目常用,新項目建議 Apache Commons FileUpload / Servlet 3.0 Part) -->
<dependency>
    <groupId>com.jspsmart</groupId>
    <artifactId>smartupload</artifactId>
    <version>1.1</version>
</dependency>

<!-- JavaMail -->
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>

1. 文件上傳:Controller/Servlet 處理

@WebServlet("/tool/upload")
@MultipartConfig(maxFileSize = 10 * 1024 * 1024, maxRequestSize = 50 * 1024 * 1024) // Servlet 3.0 原生支持
public class UploadServlet extends HttpServlet {

    private static final String BASE_UPLOAD_DIR = "/data/uploads";

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String email = null;
        boolean success = true;
        String dataId = String.valueOf(System.currentTimeMillis());
        Path dataDir = Paths.get(BASE_UPLOAD_DIR, dataId, "data");
        Files.createDirectories(dataDir);

        // 解析 multipart 請求
        for (Part part : req.getParts()) {
            if (part.getSize() == 0) continue;

            String fileName = Paths.get(part.getSubmittedFileName()).getFileName().toString(); // 防路徑遍歷
            if (part.getName().equals("file")) { // 文件域
                Path target = dataDir.resolve(fileName);
                try (InputStream in = part.getInputStream()) {
                    Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
                }
            } else if (part.getName().equals("email")) { // 普通表單域
                email = new String(part.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
            }
        }

        req.setAttribute("success", success);
        req.setAttribute("email", email);
        req.getRequestDispatcher("/view/result.jsp").forward(req, resp);
    }
}

2. 郵件發送服務:支持附件、HTML 正文、異步發送

@Component
public class EmailService {

    @Value("${mail.host:smtp.163.com}") private String host;
    @Value("${mail.username}") private String username;
    @Value("${mail.password}") private String password;
    @Value("${mail.from}") private String from;

    public void sendWithAttachments(String to, String subject, String htmlContent, List<File> attachments) {
        try {
            Properties props = new Properties();
            props.put("mail.smtp.host", host);
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.port", "465");
            props.put("mail.smtp.socketFactory.port", "465");
            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");

            Session session = Session.getInstance(props, new Authenticator() {
                @Override protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(username, password);
                }
            });

            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(from));
            message.setRecipients(Message.RecipientType.TO, to);
            message.setSubject(subject, "UTF-8");

            // 構建 Multipart
            Multipart multipart = new MimeMultipart();

            // HTML 正文
            MimeBodyPart htmlPart = new MimeBodyPart();
            htmlPart.setContent(htmlContent, "text/html;charset=UTF-8");
            multipart.addBodyPart(htmlPart);

            // 附件
            if (attachments != null) {
                for (File file : attachments) {
                    MimeBodyPart attachPart = new MimeBodyPart();
                    attachPart.attachFile(file);
                    // 解決中文附件名亂碼
                    attachPart.setFileName(MimeUtility.encodeText(file.getName(), "UTF-8", "B"));
                    multipart.addBodyPart(attachPart);
                }
            }

            message.setContent(multipart);
            Transport.send(message);
        } catch (MessagingException | IOException | UnsupportedEncodingException e) {
            throw new RuntimeException("郵件發送失敗", e);
        }
    }

    // 異步發送版本
    @Async("emailExecutor")
    public CompletableFuture<Void> sendAsync(String to, String subject, String html, List<File> files) {
        sendWithAttachments(to, subject, html, files);
        return CompletableFuture.completedFuture(null);
    }
}

3. 前端頁面:表單上傳 + 進度提示

<form id="uploadForm" action="/tool/upload" method="post" enctype="multipart/form-data">
    <div class="form-group">
        <label>Email</label>
        <input type="email" name="email" class="form-control" required />
    </div>
    <div class="form-group">
        <label>文件</label>
        <input type="file" name="file" class="form-control" required />
    </div>
    <button type="submit" class="btn btn-primary">上傳並發送郵件</button>
</form>

<script>
$('#uploadForm').on('submit', function(e) {
    e.preventDefault();
    var formData = new FormData(this);
    $.ajax({
        url: '/tool/upload',
        type: 'POST',
        data: formData,
        processData: false,
        contentType: false,
        xhr: function() {
            var xhr = new window.XMLHttpRequest();
            xhr.upload.addEventListener('progress', function(evt) {
                if (evt.lengthComputable) {
                    var percent = Math.round(evt.loaded / evt.total * 100);
                    $('#progressBar').css('width', percent + '%').text(percent + '%');
                }
            }, false);
            return xhr;
        },
        success: function(resp) {
            alert('上傳成功,郵件發送中...');
        },
        error: function() { alert('上傳失敗'); }
    });
});
</script>

關鍵點總結

模塊關鍵點
上傳解析Servlet 3.0 @MultipartConfig + req.getParts() 零依賴、標準化;舊項目用 Commons FileUpload
文件名安全Paths.get(submittedFileName).getFileName() 防止 ../../etc/passwd 路徑遍歷
大文件流式複製 Files.copy(in, target),不載入內存;超大文件需分片上傳
郵件編碼MimeUtility.encodeText(filename, "UTF-8", "B") 解決中文附件名亂碼
SSL/TLS465 端口 + SSLSocketFactory,或 587 + STARTTLS
異步化@Async + 線程池,避免阻塞 HTTP 響應

現代替代建議

  • 上傳:Spring MVC MultipartFile、MinIO/S3 對象存儲、分片上傳庫 (Uppy、Plupload)。
  • 郵件:Spring Boot JavaMailSender 封裝、Thymeleaf 模板引擎渲染 HTML、隊列異步 (RabbitMQ/Kafka) + 重試補償。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved