Apa Yang Akan Saya Pelajari?
Pada tutorial kali ini, spesial dalam bahasa Indonesia, saya akan menjelaskan bagaimana cara membaca email pada suatu akun Google yang Anda miliki menggunakan program Java™. Selanjutnya, jika di dalam email itu ada lampiran berupa berkas zip, maka kita akan mengekstraknya ke direktori target yang telah ditentukan sebelumnya. Tetapi, sebelum Anda bisa mengikuti tutorial kali ini dengan baik, Anda harus menguasai tutorial sebelumnya yang terlampir pada Curriculum. Berikut adalah materi umum yang akan terkuasai dalam mengikuti tutorial ini.
Persyaratan
Pastikan Anda memasang (instalasi) perangkat lunak dan menyesuaikan pengaturan berikut:
Java™ Standard Edition Development Kit terbaru saat ini.
Akun Google yang Dijadikan Target.
Pastikan pada akun yang dijadikan target, untuk mengganti pengaturan Allow less secure apps menjadi On, di sini.
Tingkat Kesulitan
Dasar
InboxDefinisikan properti untuk mendapatkan koneksi ke server melalui SMTPS Gmail pada variabel statik GMAIL, seperti alamat host, port dan lainnya. Kemudian, buat sebuah metode dengan nama retrieve, yang akan menerima dua buah parameter, yaitu username dan password dari akun yang akan dilihat seluruh email-nya.
Berikut adalah kode untuk mengambil dan membaca semua email sekaligus yang ada di folder Inbox:
public static void retrieve(String username, String password) {
Session session = Session.getDefaultInstance(GMAIL);
try {
Store store = session.getStore("imaps");
store.connect(GMAIL.getProperty("mail.smtp.host"), username, password);
Folder inbox = store.getFolder("Inbox");
inbox.open(Folder.READ_ONLY);
/*
* Right now, the folder is ready
*/
{
inbox.getMessages();
}
inbox.close(false);
store.close();
}
catch(Throwable e) { e.printStackTrace(); }
}
private static final java.util.Properties GMAIL = new java.util.Properties();
static {
GMAIL.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
GMAIL.put("mail.smtp.socketFactory.port", "465");
GMAIL.put("mail.smtp.ssl.enable", "true");
GMAIL.put("mail.smtp.auth", "true");
GMAIL.put("mail.smtp.host", "smtp.gmail.com");
GMAIL.put("mail.smtp.port", "465");
}
Program akan terus mengambil dan membaca email dari akun target sampai pengguna memberikan input 0 (nol). Di sini akan digunakan kelas java.io.BufferedReader untuk membaca setiap input sebagai baris dari pengguna melalui konsol. Cara menciptakan objek pembaca input adalah:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)`.
Selanjutnya, jika pengguna memberikan input angka apa pun, maka program pembaca email ini akan melewatkan beberapa email yang akan dibaca sebanyak angka yang diberikan. Maka, kode di atas akan menjadi seperti berikut:
public static void retrieve(String username, String password) {
Session session = Session.getDefaultInstance(GMAIL);
try {
Store store = session.getStore("imaps");
store.connect(GMAIL.getProperty("mail.smtp.host"), username, password);
Folder inbox = store.getFolder("Inbox");
inbox.open(Folder.READ_ONLY);
String line;
int i = 0, n = inbox.getMessageCount();
try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
do {
print(inbox.getMessage(n -= (i + 1)));
System.out.print("To stop, type \"0\" (zero) or type any positive number to jump: ");
line = reader.readLine();
try{ i = Integer.parseInt(line); }
catch(Throwable e) { i = 0; }
}
while(!line.equals("0"));
}
inbox.close(false);
store.close();
}
catch(Throwable e) { e.printStackTrace(); }
}
Pada tutorial sebelumnya, kita telah mendaftarkan tiga fungsi untuk menangani berkas dengan tipe multipart/*, gambar dan selain itu semua. Maka akan ditambahkan sebuah fungsi lagi untuk menangani berkas zip.
Periksa MimeType
Tambahkan sebuah variabel statik ZIP untuk menyimpan konstanta application/zip dan pada metode print(Part) selalu periksa tipe dari konten, jika sesuai dengan ZIP atau application/x-rar-compressed lakukan proses ekstraksi. Berikut adalah logikanya:
private static final Map<String, Function<Object, Void>> FUNCTIONS = new java.util.HashMap<>();
private static final String ZIP = "application/zip";
. . .
else if(part.isMimeType(ZIP) || part.isMimeType("application/x-rar-compressed"))
FUNCTIONS.get(ZIP).apply(part);
. . .
Fungsi Ekstraksi Berkas Zip
Tambahkan kode berikut:
FUNCTIONS.put(ZIP, content -> {
BodyPart body;
Path newSrc, parent;
InputStream in;
FileOutputStream out;
try {
/*
* Selalu minta ke pengguna di direktori mana berkas akan disimpan dan diekstrak
*/
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
body = (BodyPart) content;
System.out.print("Enter path and file name for attachment \"" + body.getFileName() + "\": ");
newSrc = Paths.get(reader.readLine());
parent = newSrc.getParent();
/*
* Selalu periksa dan buatkan direktori baru jika pengguna
* memberikan direktori yang tidak pernah ada.
*/
if(Files.notExists(parent))
Files.createDirectories(parent);
out = new FileOutputStream(newSrc.toFile());
in = body.getInputStream();
} catch(Throwable e) {
e.printStackTrace();
return null;
}
final byte[] BYTES = new byte[2048];
try {
/*
* Proses download
*/
for(int length;(length = in.read(BYTES)) > -1;)
out.write(BYTES, 0, length);
out.close();
System.out.println("Download attachment was successful");
/**
* Proses ekstraksi berkas yang telah selesai ter-download
*/
ZipIOStream.unzip(true, parent, newSrc);
System.out.println("Extraction of " + newSrc + " was successful");
} catch(Throwable e) {
e.printStackTrace();
}
return null;
});
Pada kelas ZipIOStream yang telah terdefinisikan sebelumnya di sini, buat sebuah metode privat baru dengan nama unzip yang akan menerima parameter java.util.zip.ZipInputStream sebagai zipIn, dan java.nio.file.Path sebagai direktori target. Dan berikut ini adalah kodenya:
private static void unzip(ZipInputStream zipIn, Path target) throws Throwable {
ZipEntry entry = zipIn.getNextEntry();
final byte[] BYTES = new byte[2048];
for(Path newPath, parent; entry != null; entry = zipIn.getNextEntry()) {
String name = entry.getName();
newPath = target.resolve(name);
if(entry.isDirectory() || name.charAt(name.length() - 1) == separatorChar)
Files.createDirectories(newPath);
else {
if(Files.notExists(parent = newPath.getParent()))
Files.createDirectories(parent);
Files.createFile(newPath);
try(FileOutputStream out = new FileOutputStream(newPath.toFile());
FileLock lock = out.getChannel().lock()) {
for(int length; (length = zipIn.read(BYTES)) > -1; )
out.write(BYTES, 0, length);
lock.release();
}
}
}
}
Metode di atas hanya dapat mengekstrak sebuah berkas zip, karena hal ini metode tersebut didefinisikan privat. Selanjutnya kita akan mendefinisikan sebuah metode global yang akan dapat mengekstrak banyak berkas sekaligus. Berikut adalah kodenya:
/**
* Mengekstrak berkas zip.
* @param thrown - Apakah akan melemparkan Exception jika terjadi kesalahan, atau tidak.
* @param target - Direktori target di mana hasil ekstraksi akan dimuat.
* @param source - Berkas-berkas zip yang akan diekstrak.
* @return - {@code True} jika proses ekstraksi berhasil, sebaliknya {@code false}.
*/
public static boolean unzip(boolean thrown, Path target, Path... source) {
if(Files.notExists(target))
try {
Files.createDirectories(target);
} catch(Throwable e) {
if(thrown) throw new RuntimeException(e);
return false;
}
else if(Files.isRegularFile(target))
target = target.getParent();
boolean b = true;
for(Path p : source)
try(ZipInputStream reader = new ZipInputStream(new FileInputStream(p.toFile()))) {
unzip(reader, target);
} catch(Throwable e) {
if(thrown) throw new RuntimeException(e);
b = false;
}
return b;
}
Pengujian ini masih menggunakan metode Main yang sama seperti sebelumnya.
Email Target
Berikut adalah email target yang akan dibaca kontennya, di-download (Test.zip), dan akhirnya diekstrak.
Log
Hasil
Selamat! Akhirnya kita berhasil men-download berkas zip dan mengekstraknya kembali, serta menyelesaikan tutorial ini dengan baik.
Share with Heart.