Xử lý tệp đính kèm email là một yêu cầu phổ biến. Tuy nhiên, trong thực tế, nguồn của các tệp đính kèm có thể khác nhau:
- Tệp cục bộ: Đọc trực tiếp từ hệ thống tệp của máy chủ
- URL trực tuyến: Tệp đính kèm là một tài nguyên HTTP, cần tải xuống trước
Nếu phương thức dịch vụ email chỉ hỗ trợ các tệp kiểu File, trong khi dữ liệu nguồn là một URL, bạn cần xử lý thêm
| Phương án | Tình huống áp dụng | Ưu điểm | Nhược điểm |
|---|---|---|---|
| Phương án 1: Tải tệp rồi gửi | sendMultiMail chỉ chấp nhận File | - Tương thích với mọi phương thức xử lý File, đảm bảo tệp đính kèm sẵn sàng | - Cần lưu trữ tạm, chiếm dụng dung lượng đĩa |
| Phương án 2: Chỉnh sửa sendMultiMail để hỗ trợ URL | sendMultiMail hỗ trợ URL đính kèm | - Không cần lưu trữ tệp, giảm IO | - Cần chỉnh sửa sendMultiMail, và URL có thể không còn hiệu lực |
Học từ thực tế:
- Tệp cục bộ
Khi tệp đính kèm là tệp cục bộ, bạn có thể sử dụng đối tượng File trực tiếp truyền vào phương thức gửi email:
List<File> danhSachTepDinhKem = Collections.singletonList(new File("D:\\hinh\\test.jpg"));
Truyền vào phương thức sendMultiMail:
Long idThongDiep = dichVuGuiMail.sendMultiMail(
danhSachNguoiNhan, getIdNguoiDangNhap(), loaiNguoiDung.ADMIN,
maMau, thamSoMau, danhSachTepDinhKem);
- URL trực tuyến
new File(String path) chỉ có thể xử lý đường dẫn tệp cục bộ, nhưng nếu dữ liệu trả về là URL HTTP (ví dụ: http://example.com/image.jpg), sẽ ném ra ngoại lệ FileNotFoundException, vì Java coi đây là đường dẫn không hợp lệ
Giải pháp:
- Phương án 1: Tải tệp URL về máy cục bộ, sau đó truyền vào dưới dạng File Ưu điểm: ✅ Tương thích với mọi phương thức xử lý File.✅ Đảm bảo tệp được tải hoàn chỉnh trước khi gửi. Nhược điểm: ❌ Có thể gây ra chi phí IO đĩa, đặc biệt khi có nhiều tệp đính kèm.❌ Cần lưu trữ tệp tạm, tăng gánh nặng đĩa máy chủ.
- Phương án 2: Chỉnh sửa phương thức sendMultiMail để hỗ trợ trực tiếp URL Ưu điểm:✅ Tránh lưu trữ cục bộ, sử dụng trực tiếp tài nguyên trực tuyến.✅ Giảm chi phí IO, phù hợp với gửi email quy mô lớn. Nhược điểm: ❌ Cần phương thức sendMultiMail hỗ trợ URL đính kèm.❌ URL có thể hết hạn, ảnh hưởng đến hiệu lực lâu dài nội dung email.
Có thể sử dụng java.net.URL và Files.copy để tải tệp:
import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
public class CongCuTaiTep {
public static File taiTepTuUrl(String urlTep) throws IOException {
URL url = new URL(urlTep); // Tạo đối tượng URL
File tepTam = File.createTempFile("dinhkem_", ".jpg"); // Tạo tệp tạm
try (InputStream vao = url.openStream()) {
Files.copy(vao, tepTam.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
return tepTam;
}
}
Tải xuống rồi gửi email Khi gửi email, trước tiên tải tệp đính kèm:
// Xử lý tệp đính kèm, tải hình ảnh HTTP về cục bộ
List<File> danhSachTepDinhKem = new ArrayList<>();
try {
File tepTaiXuong = CongCuTaiTep.taiTepTuUrl(thongTinHinhAnh.getImgCntrF());
danhSachTepDinhKem.add(tepTaiXuong);
} catch (IOException e) {
e.printStackTrace(); // Ghi log lỗi
}
// Gửi email
Long idThongDiep = dichVuGuiMail.sendMultiMail(danhSachNguoiNhan, getIdNguoiDangNhap(), loaiNguoiDung.ADMIN,
maMau, thamSoMau, danhSachTepDinhKem);
Phương thức sendMultiMail sử dụng javax.mail, có thể chỉnh sửa để hỗ trợ URL:
import javax.activation.DataHandler;
import javax.activation.URLDataSource;
import javax.mail.internet.MimeBodyPart;
import java.net.URL;
public class CongCuTaoMail {
public static MimeBodyPart taoTepDinhKemTuUrl(String urlTep) throws Exception {
MimeBodyPart phanTepDinhKem = new MimeBodyPart();
URL url = new URL(urlTep);
phanTepDinhKem.setDataHandler(new DataHandler(new URLDataSource(url)));
phanTepDinhKem.setFileName("tep_dinh_kem.jpg"); // Có thể đặt tên động theo thực tế
return phanTepDinhKem;
}
}
- Mẹo bổ sung
Các tệp tải xuống tạm thời
Windows: Thường lưu trữ tại C:\Users\Tên người dùng\AppData\Local\Temp Linux / macOS: Thường lưu trữ tại /tmp/
Không muốn lưu trữ trong thư mục tạm hệ thống, mà muốn đặt vào thư mục tùy chỉnh, có thể chỉnh sửa phương thức taiTepTuUrl:
public static File taiTepTuUrl(String urlTep, String thuMucLuu) throws IOException {
URL url = new URL(urlTep);
// Đảm bảo thư mục tồn tại
File thuMuc = new File(thuMucLuu);
if (!thuMuc.exists()) {
thuMuc.mkdirs();
}
// Chỉ định đường dẫn tệp tải xuống
File tep = new File(thuMucLuu + File.separator + "tep_dinh_kem.jpg");
// Tải tệp
try (InputStream vao = url.openStream()) {
Files.copy(vao, tep.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
return tep;
}
Cách sử dụng:
File tep = taiTepTuUrl("http://example.com/image.jpg", "D:\\dinhkem");
System.out.println("Đường dẫn tệp đã lưu: " + tep.getAbsolutePath());
Vấn đề lại phát sinh! Lượng dữ liệu liên tục tăng, làm thế nào để tạo tác vụ định kỳ dọn dẹp? Xem bài viết trước của tôi:
- Phân tích chi tiết @Scheduled và SchedulingConfigurer trong Java (kèm Demo)
- Phân tích chi tiết tác vụ định kỳ crontab (kèm Demo | thực tế dọn dẹp Tomcat)
- Phân tích tác vụ định kỳ trong Mysql (Event)
- Hướng dẫn chi tiết về aioschedule trong Python
Tôi đang triển khai trên Linux, nên sử dụng crontab để dọn dẹp định kỳ
Cần dọn dẹp mỗi giờ!
Câu lệnh thực hiện chính:
0 * * * * find /tmp -name "dinhkem_*" -exec rm -rf {} \;