Pengembangan Server HTTP Java Menggunakan JDK HttpServer

Tutorial kali ini akan membahas tentang bagaimana menggunakan modul jdk.httpserver untuk pengembangan server HTTP dengan bahasa pemrograman java. Modul ini sangat berguna untuk pengembangan embedded server atau aplikasi web sederhana. Modul ini tersedia dalam Java Development Kit, yang memungkinkan implementasi HTTP tanpa melibatkan library pihak ketiga. Dalam tutorial ini akan dijelaskan pengkodean dasar server HTTP dan bagaimana menangani request menggunakan beragam class yang tersedia dalam modul jdk.httpserver.

Pengantar

Hypertext Transfer Protocol (HTTP) adalah protokol komunikasi yang umum digunakan dalam aplikasi web. Fungsi protokol ini disediakan di beragam bahasa pemrograman. Spesifik untuk bahasa pemrograman java, protokol ini didukung melalui ketersediaan modul jdk.httpserver (lihat dokumentasi). Contoh implementasi sederhana dari modul tersebut adalah SimpleFileServer yang bisa dieksekusi menggunakan perintah jwebserver (lihat tulisan sebelumnya).

Modul ini terdiri atas dua paket, dimana class-class pokok terdapat pada paket com.sun.net.httpserver (lihat dokumentasi). Untuk mempersingkat tutorial ini, pembahasan akan difokuskan pada class dalam paket tersebut.

Contoh Program

Direktori Project

Untuk mempermudah dalam pembuatan program, kita susun struktur direktori project seperti berikut :

httpserver-exc
+- source
+- class

Dalam folder httpserver-exc, kita siapkan dua folder source untuk menyimpan kode program .java dan folder class untuk menampung file .class hasil proses kompilasi. Untuk mempermudah proses kompilasi dan eksekusi program, kita akan gunakan dua buah file batch dengan kode berikut ini :

@echo off
IF EXIST class. RD /S /Q class
DIR /S /B source\*.java > sources.txt
javac @sources.txt -d class
DEL sources.txt

Ketikkan kode diatas kemudian simpan dengan nama compile.bat pada folder httpserver-exc.

@echo off
java -cp class com.sad301.exc.httpserver.Main

Ketikkan kode diatas kemudian simpan dengan nama exec.bat pada folder httpserver-exc.

Berikutnya kita akan membutuhkan file module-info.java. Didalam file tersebut, kita perlu menyebutkan modul yang akan digunakan didalam program, dalam hal ini adalah modul jdk.httpserver. Ketikkan kode dibawah kemudian simpan dengan nama module-info.java dalam folder source.

module httpserver.exc {
  requires jdk.httpserver;
}

Sampai tahap ini, direktori project program adalah sebagai berikut :

httpserver-exc
+- compile.bat
+- exec.bat
+- class
+- source
   +- module-info.java

Class HttpServer

Disini kita akan mulai mengetikkan kode program java, dimulai dengan class utama yang akan menjadi entry point dari program. Ketikkan kode program dibawah, kemudian simpan dengan nama Main.java pada folder source.

package com.sad301.exc.httpserver;

import com.sun.net.httpserver.*;
import java.io.*;
import java.net.*;

public class Main {
  public static void main(String[] args) {
    // Kode selanjutnya diketik pada baris ini
  }
}

Didalam class tersebut, kita gunakan objek HttpServer (lihat dokumentasi) yang akan melayani permintaan HTTP pada saat program dijalankan. Untuk membentuk objek HttpServer, class ini menyediakan beberapa metode statik. Metode yang kita gunakan disini adalah HttpServer.create(InetSocketAddress addr, int backlog). Dalam pemanggilannya, metode ini berpeluang menghasilkan eksepsi IOException sehingga harus dipanggil dalam pernyataan try dan catch.

Perhatikan contoh dibawah :

try {
  HttpServer server = HttpServer.create(new InetSocketAddress(9091), 0);
  // kode selanjutnya diketik pada baris ini
}
catch(IOException exc) {
  exc.printStackTrace();
}

Metode ini menggunakan dua parameter, yaitu objek InetSocketAddress dan nilai socket backlog dengan tipe integer.

Parameter InetSocketAddress (lihat dokumentasi) mengindikasikan alamat dan/atau port yang diasosiasikan dengan server tersebut. Pada contoh diatas, kita hanya menyebutkan nomor port 9091. Konfigurasi ini memungkinkan akses ke server dari perangkat manapun dalam jaringan.

Parameter kedua yaitu socket backlog mengatur berapa banyak koneksi masuk yang akan dilayani oleh server. Nilai 0 mengindikasikan bahwa server akan menggunakan nilai default dalam sistem operasi.

Pemetaan URL dan Penanganan Request

Setelah membuat dan mengkonfigurasikan objek server, tahap berikutnya adalah memetakan tiap URL didalam server dan menentukan bagaimana server akan menangani request yang masuk ke URL tersebut.

Untuk tahap ini kita gunakan metode createContext(String path, HttpHandler handler) dari objek HttpServer. metode ini terdiri atas dua parameter, yaitu :

  • Nilai string path yang mengindikasikan direktori, file atau resource
  • Interface HttpHandler menentukan bagaimana request ke path akan ditangani

Dalam interface HttpHandler (lihat dokumentasi) terdapat satu signature metode yang harus didefinisikan yaitu handle(HttpExchange exchange). Didalam parameter HttpExchange (lihat dokumentasi) kita bisa mengakses informasi perihal request dan menentukan bagaimana meresepon request tersebut.

Karena HttpHandler adalah interface dengan 1 buah metode, kita bisa langsung definisikan implementasinya dalam bentuk ekspresi lambda (lihat tulisan sebelumnya). Perhatikan contoh kode dibawah :

server.createContext("/", exchange -> {
  // kode selanjutnya diketik pada baris ini
});

Sampai disini kita bisa mulai melayani request dari client. Disini kita tidak mencoba mendapatkan informasi mendetail seputar request, tetapi hanya mengirimkan response berupa halaman web tiap kali ada request yang diterima.

Disini kita akan gunakan 3 buah metode didalam HttpExchange, yaitu :

  • getResponseHeaders(). Metode ini mengembalikan objek Headers yang merepresentasikan header dari response. Objek tersebut kita gunakan untuk men-set nilai header Content-Type dari pesan response yang akan dikirimkan.
  • sendResponseHeaders(int rCode, long responseLength). Metode ini bertujuan untuk mengirimkan header dari response. Metode ini menggunakan dua parameter yaitu kode HTTP (rCode) dan panjang dari pesan response (responseLength).
  • getResponseBody(). Metode ini mengembalikan objek OutputStream untuk fungsi pengirimkan pesan response kepada client.

Perhatikan contoh kode berikut :

String pesan = "<!DOCTYPE html>" +
  "<html lang=\"id\">" +
  "<head><title>Selamat Datang</title></head>" +
  "<body><h1>Selamat Datang</h1><p>Halaman ini berasal dari server HTTP java</p></body>" +
  "</html>";
exchange.getResponseHeaders().set("Content-Type", "text/html");
exchange.sendResponseHeaders(200, pesan.length());
OutputStream out = exchange.getResponseBody();
out.write(pesan.getBytes());
out.close();

Mengaktifkan Server HTTP

Langkah terakhir adalah mengaktifkan server yang sudah dikonfigurasikan sebelumnya. Disini kita cukup memanggil metode start() dari objek HttpServer.

Dibawah ini adalah kode program selengkapnya

package com.sad301.exc.httpserver;

import com.sun.net.httpserver.*;
import java.io.*;
import java.net.*;

public class Main {
  public static void main(String[] args) throws IOException {
    HttpServer server = HttpServer.create(new InetSocketAddress(9091), 0);
    server.createContext("/", exchange -> {
      String pesan = "<!DOCTYPE html>" +
        "<html lang=\"id\">" +
        "<head><title>Selamat Datang</title></head>" +
        "<body><h1>Selamat Datang</h1><p>Halaman ini berasal dari server HTTP java</p></body>" +
        "</html>";
      exchange.getResponseHeaders().set("Content-Type", "text/html");
      exchange.sendResponseHeaders(200, pesan.length());
      OutputStream out = exchange.getResponseBody();
      out.write(pesan.getBytes());
      out.close();
    });
    server.start();
    System.out.println("Server listening at 9091");
  }
}

Compile kode program diatas menggunakan perintah compile.bat dan eksekusi program dengan perintah exec.bat. Pada saat dijalankan, program akan menampilkan text “Server listening at 9091”. Setelah mengeksekusi program, jalankan aplikasi web browser kemudian ketikkan alamat http://127.0.0.1:9091 pada kotak address bar.

Fungsi Penanggalan dalam Program Java Menggunakan Class LocalDate

Tulisan kali ini akan membahas tentang penggunaan class LocalDate untuk fungsi penanggalan dalam program java. Class ini dapat digunakan untuk mendapatkan informasi tanggal yang kemudian dapat ditampilkan dalam format yang diinginkan.

Pengantar

Class LocalDate terdapat pada modul/paket java.base/java.time dimulai dari java versi 1.8 (lihat dokumentasi API). Untuk menggunakan class tersebut, kita perlu menyebutkan klausa import sebelum deklarasi class java.

import java.time.LocalDate;

Konstruksi Objek

Dikarenakan class LocalDate tidak memiliki konstruktor publik, pembentukan objek hanya bisa dilakukan melalui beberapa metode statis. Metode-metode yang paling mudah digunakan adalah sebagai berikut :

  1. Metode LocalDate.now(). Metode ini akan mengembalikan objek LocalDate yang merepresentasikan tanggal hari ini
  2. Metode LocalDate.of(int year, int month, int dayOfMonth). Metode .of() dipanggil dengan menyebutkan 3 nilai parameter integer secara berurutan yaitu tahun, bulan, dan tanggal. Metode ini akan mengembalikan objek LocalDate yang merepresentasikan tahun, bulan dan tanggal yang disebutkan
  3. Metode LocalDate.parse(CharSequence text). Metode ini dipanggil dengan menyebutkan nilai parameter text yaitu tanggal yang diinginkan dalam bentuk String. Teks tanggal dalam parameter harus ditulis dengan format tahun-bulan-tanggal sebagai contoh 1971-05-12
  4. Metode LocalDate.parse(CharSequence text, DateTimeFormatter formatter). Sama seperti metode .parse() sebelumnya. Yang membedakan, pada metode ini kita bisa menentukan sendiri format tanggal yang ingin digunakan

Sebagai contoh :

LocalDate date1 = LocalDate.now();
LocalDate date2 = LocalDate.of(1981, 02, 14);
LocalDate date3 = LocalDate.parse("1971-05-12");
LocalDate date4 = LocalDate.parse("12/05/1971", DateTimeFormatter.ofPattern("dd/MM/yyyy"));

Mendapatkan Informasi Tanggal

Objek LocalDate menyimpan sejumlah informasi (yang umum dibutuhkan yaitu tanggal, bulan, dan tahun) yang dapat diakses menggunakan metode-metode objek berikut :

  1. Metode .getYear(). Metode ini akan mengembalikan informasi tahun dengan tipe integer
  2. Metode .getMonthValue() akan mengembalikan informasi bulan dengan tipe integer
  3. Metode .getMonth() akan mengembalikan informasi bulan dengan tipe Month. Class Month terdapat pada paket java.time, class ini akan berguna jika kita membutuhkan nama bulan dari objek LocalDate
  4. Metode .getDayOfMonth() akan mengembalikan informasi tanggal dalam bulan dengan tipe integer
  5. Metode .getDayOfWeek() akan mengembalikan informasi hari dalam minggu dengan tipe DayOfWeek. Class DayOfWeek juga terdapat pada paket java.time, class ini akan berguna jika kita membutuhkan nama hari dari objek LocalDate

Perhatikan contoh kode program berikut :

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.Locale;

public class ContohLocalDate1 {

	public static void main(String[] args) {
		DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd/MM/yyyy");
		LocalDate localDate = LocalDate.parse("12/12/2012", fmt);
		int tahun = localDate.getYear();
		int bulan = localDate.getMonthValue();
		int tanggal = localDate.getDayOfMonth();

		System.out.println(String.format("Tahun : %d, Bulan : %d, Tanggal : %d", tahun, bulan, tanggal));

		Month month = localDate.getMonth();
		DayOfWeek dayOfWeek = localDate.getDayOfWeek();

		Locale idLocale = new Locale("id", "ID"); // locale indonesia
		String namaBulan = month.getDisplayName(TextStyle.FULL, idLocale);
		String namaHari = dayOfWeek.getDisplayName(TextStyle.FULL, idLocale);

		System.out.println(String.format("%s, %d %s %d", namaHari, tanggal, namaBulan, tahun));
	}

}

Program diatas akan mengembalikan output berikut :

Tahun : 2012, Bulan : 12, Tanggal : 12
Rabu, 12 Desember 2012

Cara lain untuk mendapatkan informasi dari objek LocalDate adalah dengan menggunakan metode .get(TemporalField field). TemporalField dalam metode tersebut adalah sebuah inteface dalam paket java.time.temporal. Untuk memanggil metode .get(), kita cukup gunakan implementasi dari TemporalField. Salah satu yang cukup mudah digunakan adalah tipe enum ChronoField yang berisi field-field umum untuk informasi tanggal.

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.util.Locale;

public class ContohLocalDate2 {

	public static void main(String[] args) {
		LocalDate date = LocalDate.parse("1945-08-17");
		int year = date.get(ChronoField.YEAR);
		int month = date.get(ChronoField.MONTH_OF_YEAR);
		int dayOfMonth = date.get(ChronoField.DAY_OF_MONTH);
		int dayOfWeek = date.get(ChronoField.DAY_OF_WEEK);

		Locale idn = new Locale("id", "ID"); // locale indonesia
		String monthName = Month.of(month).getDisplayName(TextStyle.FULL, idn);
		String dayName = DayOfWeek.of(dayOfWeek).getDisplayName(TextStyle.FULL, idn);

		String txt = String.format("%s, %d %s %d", dayName, dayOfMonth, monthName, year);
		System.out.println(txt);
	}

}

Menampilkan Tanggal Menggunakan Format Tertentu

Pada contoh sebelumnya, kita sudah mencoba menampilkan tanggal dengan cara mengambil informasi dari field-field dalam objek LocalDate. Cara lain yang bisa kita gunakan untuk menampilkan tanggal adalah dengan menggunakan metode objek .format(DateTimeFormatter formatter). Class DateTimeFormatter dalam metode tersebut terdapat pada paket java.time.format (lihat dokumentasi), class ini menyediakan fungsi formatting untuk objek-objek tanggal dan waktu.

Objek DateTimeFormatter didapatkan melalui pemanggilan salah satu metode statis yang disediakan dalam class tersebut, berikut ini adalah beberapa metode yang cukup mudah digunakan :

  1. Metode DateTimeFormatter.ofLocalizedDate(FormatStyle dateStyle). Metode ini akan mengembalikan objek DateTimeFormatter dengan format tanggal berpatokan pada nilai enumerasi FormatStyle yaitu FULL, LONG, MEDIUM dan SHORT (lihat dokumentasi).
  2. Metode DateTimeFormatter.ofPattern(String pattern). Metode ini akan mengembalikan objek DateTimeFormatter menggunakan format tanggal sebagaimana ditentukan pada pattern (pola tanggal). Argument pattern sendiri adalah rangkaian huruf dan simbol yang memiliki arti masing-masing, Sebagai contoh, dd/MMMM/yyyy akan memformat tanggal 1981-01-03 menjadi 03/January/1981
  3. Metode DateTimeFormatter.ofPattern(String pattern, Locale locale). Sama seperti metode .ofPattern() sebelumnya tetapi spesifik pada locale yang ditentukan

Perhatikan contoh berikut :

DateTimeFormatter fmt = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
LocalDate date = LocalDate.parse("2001-11-09");
System.out.println(date.format(fmt));

Mendapatkan Tanggal pada Periode Waktu Tertentu

Fungsi lain yang disediakan dalam LocalDate adalah untuk mendapatkan tanggal setelah atau sebelum periode waktu tertentu. Sebagai contoh, semisal kita ingin mengetahui tanggal dalam periode 1 tahun, 3 bulan dan 10 hari yang akan datang (atau sebaliknya) sejak hari ini.

Untuk fungsi ini kita bisa gunakan dua metode berikut :

  1. .plus(TemporalAmount amountToAdd) untuk mendapatkan tanggal yang akan datang (lihat dokumentasi).
  2. .minus(TemporalAmount amountToAdd) untuk mendapatkan tanggal yang lalu (lihat dokumentasi).

Parameter TemporalAmount pada kedua metode diatas adalah sebuah interface. Implementasi yang paling mudah digunakan dari interface tersebut adalah class Period yang dapat dikonstruksikan dengan metode statis Period.of(int years, int months, int days).

Perhatikan contoh berikut :

import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class ContohLocalDate4 {

	public static void main(String[] args) {
		Locale idn = new Locale("id", "ID");
		DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MMMM yyyy", idn);
		Period p = Period.of(1, 3, 10); // periode 1 tahun, 3 bulan, dan 10 hari
		LocalDate hariIni = LocalDate.now();
		LocalDate hariBerikut = hariIni.plus(p);
		LocalDate hariLalu = hariIni.minus(p);
		System.out.printf(
			"Hari ini tanggal %s. %d tahun, %d bulan, dan %d hari yang akan datang sejak hari ini adalah %s\n",
			hariIni.format(fmt), p.getYears(), p.getMonths(), p.getDays(), hariBerikut.format(fmt)
		);
		System.out.printf(
			"Hari ini tanggal %s. %d tahun, %d bulan, dan %d hari yang lalu sejak hari ini adalah %s\n",
			hariIni.format(fmt), p.getYears(), p.getMonths(), p.getDays(), hariLalu.format(fmt)
		);
	}
}

Program diatas akan menampilkan output seperti berikut :

Hari ini tanggal 30 Mei 2022. 1 tahun, 3 bulan, dan 10 hari yang akan datang sejak hari ini adalah 09 September 2023
Hari ini tanggal 30 Mei 2022. 1 tahun, 3 bulan, dan 10 hari yang lalu sejak hari ini adalah 18 Februari 2021

Mendapatkan Periode Waktu Antara Dua Tanggal

Sebelumnya kita telah mengetahui bagaimana mendapatkan tanggal berdasarkan periode waktu. Untuk pembahasan ini kita akan coba mendapatkan periode waktu antara dua tanggal. Sebagai contoh, kita ingin mengetahui berapa umur seseorang terhitung dari tanggal lahirnya sampai tanggal hari ini.

Untuk fungsi ini kita bisa gunakan metode .until(ChronoLocalDate endDateExclusive). Parameter ChronoLocalDate pada metode tersebut adalah sebuah interface, dengan class implementasi LocalDate. Parameter ini mengindikasikan tanggal batas akhir dari periode yang ingin didapatkan (lihat dokumentasi).

Perhatikan contoh kode program :

import java.time.format.DateTimeFormatter;
import java.time.LocalDate;
import java.time.Period;
import java.util.Locale;

public class ContohLocalDate5 {
	public static void main(String[] args) {
		Locale idn = new Locale("id", "ID");
		DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MMMM yyyy", idn);
		LocalDate birthDate = LocalDate.of(1998, 2, 18); // Tanggal lahir 18 Februari 1998
		LocalDate todayDate = LocalDate.now(); // tanggal hari ini
		Period p = birthDate.until(todayDate);
		System.out.printf(
			"Hari ini tanggal %s, jika anda lahir pada tanggal %s maka anda telah berumur %d tahun, %d bulan, dan %d hari",
			todayDate.format(fmt), birthDate.format(fmt), p.getYears(), p.getMonths(), p.getDays()
		);
	}
}

Program tersebut akan menampilkan output sebagai berikut :

Hari ini tanggal 31 Mei 2022, jika anda lahir pada tanggal 18 Februari 1998 maka anda telah berumur 24 tahun, 3 bulan, dan 13 hari

Cara lain yang bisa digunakan adalah dengan memanggil metode statis Period.between(LocalDate startDateInclusive, LocalDate endDateExclusive).

Perhatikan contoh kode berikut ini :

Period p = Period.between(LocalDate.parse("1945-08-17"), LocalDate.now());
System.out.printf(
	"Indonesia telah merdeka selama %d tahun, %d bulan dan %d hari",
	p.getYears(), p.getMonths(), p.getDays()
);

Menggunakan Perintah jwebserver

Tulisan kali ini akan membahas tentang bagaimana menggunakan perintah jwebserver untuk mengeksekusi web server sederhana. jwebserver merupakan tool command line yang disediakan dalam rilis Java Development Kit (JDK) versi 18. Tool ini menyediakan fitur minimum HTTP server, yang bisa digunakan untuk sekedar melayani permintaan berupa file statis pada direktori yang ditentukan. Tool ini akan sangat bermanfaat untuk keperluan testing dan debugging aplikasi web sisi client yang berbasis HTML, CSS dan JavaScript.

Merujuk ke dokumentasinya, jwebserver hanya melayani request dengan metode HEAD dan GET, metode lain akan direspon dengan kode 501 atau 405. Yang artinya, fungsi HTML form submit dengan metode POST tidak bisa digunakan.

Untuk menggunakan jwebserver, pastikan JDK 18 sudah terinstall di perangkat yang kita gunakan. Untuk memeriksa versi JDK, kita bisa gunakan perintah java -version.

C:\Users\User>java -version
java version "18" 2022-03-22
Java(TM) SE Runtime Environment (build 18+36-2087)
Java HotSpot(TM) 64-Bit Server VM (build 18+36-2087, mixed mode, sharing)

JDK 18 bisa didapatkan di halaman download dari website resminya. Untuk instalasi dan konfigurasinya, anda bisa ikuti tutorial pada halaman ini. Pastikan variable sistem JAVA_HOME dan PATH sudah dikonfigurasikan dengan benar.

Untuk ekesekusinya, kita cukup ketikkan perintah jwebserver di jendela aplikasi Command Prompt. Pada saat dieksekusi, web server akan menampilkan output seperti dibawah

image

Secara default, jwebserver hanya melayani permintaan pada alamat IP 127.0.0.1 (localhost) pada port 8000. Sedangkan direktori file yang dilayani adalah direktori tempat jwebserver dieksekusi (current directory).

Konfigurasi diatas dapat diubah dengan menggunakan opsi-opsi berikut :

  • --bind-address (disingkat -b) berfungsi untuk mengubah alamat IP yang akan melayani permintaan HTTP.
  • --port (disingkat -p) berfungsi untuk mengubah nomor port HTTP
  • --directory (disingkat -d) berfungsi untuk mengubah direktori dari file yang akan dilayani

Sebagai contoh, semisal kita ingin mengeksekusi web server agar bisa diakses dari perangkat lain dalam jaringan 192.168.0.0 (dengan alamat IP perangkat server 192.168.0.17) pada port 8080, dan melayani file pada direktori C:\my-static-site. Perintah yang kita gunakan adalah sebagai berikut :

C:\Users\User>jwebserver --bind-address 192.168.0.17 --port 8080 --directory C:\my-static-site

Pemrograman Java dengan Apache Ant

Tulisan kali ini akan membahas tentang penggunaan Apache Ant dalam pemrograman java. Apache Ant merupakan tool yang fungsi utamanya adalah untuk mengotomatiskan proses dalam pembuatan program java. Tool ini akan bermanfaat jika kita terpaksa harus membuat program dalam sistem operasi yang tidak memiliki antarmuka grafis (GUI) atau tidak ingin menggunakan aplikasi IDE (NetBeans, Eclipse, dan sejenisnya).

Instalasi dan Konfigurasi

Apache Ant bisa di-download dari alamat url http://ant.apache.org/bindownload.cgi, dan disediakan dalam format berkas .zip dan .tar.gz. Download format berkas yang bisa anda gunakan kemudian ekstrak di direktori yang anda inginkan.

Untuk bisa menggunakan Apache Ant, kita perlu membuat variabel sistem dengan nama %ANT_HOME% dan menambahkan folder bin dari direktori Apache Ant kedalam variabel %PATH%. Perhatikan langkah-langkah berikut :

Diasumsikan kita mengestrak berkas yang sudah didownload sebelumnya pada direktori C:\Program Files\, maka nilai variabel %ANT_HOME% adalah C:\Program Files\apache-ant-1.10.1 (versi yang saya gunakan adalah 1.10.1).

Dalam direktori Apache Ant terdapat folder dengan nama bin yang berisi file-file yang bisa dieksekusi. Nilai yang akan kita tambahkan ke dalam variabel %PATH% adalah C:\Program Files\apache-ant-1.10.1\bin.

Direktori Apache Ant

Variabel sistem dapat disetting melalui Control PanelSystem and SecuritySystemAdvanced System Settings ⇒ Pada jendela System Properties klik tombol Environment Variables. Untuk menambah variabel baru klik tombol New dan untuk memodifikasi variabel yang sudah ada klik tombol Edit. Hasil akhir dari konfigurasi adalah sebagai berikut :

Variabel ANT_HOME

Variabel PATH

Kita bisa menguji hasil konfigurasi melalui aplikasi Command Prompt dengan mengetikkan perintah ant, seperti berikut :

Command Prompt

Menggunakan Apache Ant

Apache Ant menggunakan sebuah file XML dengan nama build.xml. File build.xml berisi sebuah project dan sebuah project menampung paling sedikit satu buah target. Target akan menampung satu atau lebih elemen perintah yang harus dikerjakan.

Contoh sederhana dari file build.xml adalah sebagai berikut :

<?xml version="1.0"?>
<project name="HelloWorldGUI" basedir="." default="init">   <!-- project  -->
  <target name="init">                                      <!-- target   -->
    <mkdir dir="classes"/>                                  <!-- task 1   -->
    <mkdir dir="dist"/>                                     <!-- task 2   -->
  </target>
</project>

Penjelasan :

  • Elemen project terdiri atas beberapa atribut, yaitu :
    • name merupakan nama dari project
    • basedir mengindikasikan direktori dari project. simbol titik ( . ) mengindikasikan project berada di direktori saat ini (current directory)
    • default berisi nama dari target yang akan dieksekusi secara default.
  • Elemen target menggunakan satu buah atribut name yaitu nama dari target tersebut.
  • Elemen target terdiri atas 2 buah perintah (task) mkdir yang digunakan untuk membuat folder. Daftar lengkap dari task dapat dilihat pada halaman manual yang disediakan.

Eksekusi dua atau lebih target secara berurutan dapat dilakukan dengan memanfaatkan atribut depends. Perhatikan contoh berikut :

<target name="A"></target>
<target name="B" depends="A"></target>

Pada contoh diatas, target B bergantung (depends) kepada target A. Tiap kali kita memanggil target B, Apache Ant akan mengerjakan task pada target A baru kemudian mengerjakan task pada target B.

Contoh Program

Dalam contoh ini kita akan membuat sebuah program java menggunakan Apache Ant. Kita tentukan direktori project yaitu C:\HelloWorldGUI. Dalam direktori tersebut, kita membuat sebuah folder baru dengan nama src yang nantinya akan menampung kode program java. Selain itu kita juga membuat file build.xml seperti berikut :

<?xml version="1.0"?>
<project name="HelloWorldGUI" basedir="." default="build">

  <target name="clean">
    <delete dir="classes"/>
    <delete dir="dist"/>
  </target>

  <target name="init">
    <mkdir dir="classes"/>
    <mkdir dir="dist"/>
  </target>

  <target name="build" depends="clean,init">
    <javac includeAntRuntime="false" srcdir="src" destdir="classes"/>
  </target>

  <target name="test" depends="build">
    <java classpath="classes" classname="com.sad301.Main" fork="true" spawn="true"/>
  </target>

  <target name="dist" depends="build">
    <jar destfile="dist/HelloWorldGUI.jar" basedir="classes"/>
  </target>

</project>

Sampai disini kita bisa lanjutkan ke penulisan kode program. Ketikkan kode berikut kemudian simpan pada folder src dengan nama Main.java.

package com.sad301;

import javax.swing.*;

public class Main extends JFrame {

  public Main() {
    setTitle("Hello World GUI");
    setSize(400, 400);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
      (new Main()).setVisible(true);
    });
  }

}

Berdasarkan file build.xml diatas, kita memiliki 5 pilihan target yaitu :

  1. clean ⇒ target ini akan menghapus folder classes dan dist
  2. init ⇒ target ini akan membuat folder dengan nama classes dan dist
  3. build ⇒ target ini akan meng-compile kode program yang tersimpan di folder src dan menyimpan file .class hasil kompilasi di folder classes. Target ini juga akan mengerjakan clean dan init
  4. test ⇒ target ini menjalankan program java yang tersimpan di folder classes. Target ini juga akan mengerjakan build
  5. dist ⇒ target ini mengepak file-file .class menjadi file .jar didalam folder dist. Target ini juga akan mengerjakan build

Jalankan kembali aplikasi command prompt, kemudian pindah ke direktori C:\HelloWorldGUI. Pada direktori tersebut kita bisa eksekusi Apache Ant dengan menyebutkan salah satu dari 5 target diatas, sebagai contoh :

ant dist

Output dari perintah diatas adalah sebagai berikut :

Command Prompt 2

Java & MySQL (4) – Menggunakan Data Access Object

Melanjutkan tulisan-tulisan sebelumnya tentang penggunaan database MySQL dalam aplikasi Java, kali ini kita akan belajar tentang Data Access Object (DAO).

Sederhananya, Data Access Object (DAO) adalah “objek” yang menjadi perantara antarmuka aplikasi dengan database. Karena sifatnya sebagai perantara, objek ini harus menyediakan metode-metode yang menunjang proses aplikasi yang berhubungan dengan database.

Proses paling dasar yang umumnya terjadi didalam aplikasi yang hubungannya dengan database antara lain :

  1. Membuat/menambah data (create)
  2. Mengambil/menampilkan data (retrieve)
  3. Memperbaharui data (update)
  4. Menghapus data (delete)

Keempat proses diatas biasa dikenal dengan istilah CRUD. DAO tidak terbatas hanya pada keempat proses tersebut, kita bisa saja menambah proses-proses lain sesuai dengan kasus yang dihadapi.

Contoh Kode Program

Perhatikan kode SQL berikut :

DROP DATABASE IF EXISTS sampledb;
CREATE DATABASE sampledb;
USE sampledb;

CREATE TABLE kontak (
  no INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  namaDepan VARCHAR(18) NOT NULL,
  namaBelakang VARCHAR(18) NOT NULL,
  alamat TEXT,
  noTelepon VARCHAR(18),
  email VARCHAR(32)
);

Struktur tabel diatas dapat dimodelkan menjadi class java seperti berikut :

public class Kontak {

  private int no;
  private String namaDepan;
  private String namaBelakang;
  private String alamat;
  private String noTelepon;
  private String email;

  // setter
  public void setNo(int no) { this.no = no; }
  public void setNamaDepan(String namaDepan) { this.namaDepan = namaDepan; }
  public void setNamaBelakang(String namaBelakang) { this.namaBelakang = namaBelakang; }
  public void setAlamat(String alamat) { this.alamat = alamat; }
  public void setNoTelepon(String noTelepon) { this.noTelepon = noTelepon; }
  public void setEmail(String email) { this.email = email; }

  // getter
  public int getNo() { return this.no; }
  public String getNamaDepan() { return this.namaDepan; }
  public String getNamaBelakang() { return this.namaBelakang; }
  public String getAlamat() { return this.alamat; }
  public String getNoTelepon() { return this.noTelepon; }
  public String getEmail() { return this.email; }

}

Sampai disini, kita bisa lanjutkan dengan membuat class DAO untuk mengakses tabel kontak.

Aplikasi yang kita buat bisa saja berurusan dengan lebih dari 1 tabel, dalam kondisi ini kita akan membutuhkan lebih dari 1 DAO. Jika dalam aplikasi terdapat lebih dari 1 DAO, maka tiap-tiap DAO harus mengikuti standard CRUD yang telah kita tentukan. Standard yang dimaksud disini dapat diterapkan dalam bentuk interface.

public interface DataDAO<T> {
  void doCreate(T t) throws java.sql.SQLException;
  java.util.List<T> doRetrieve() throws java.sql.SQLException;
  void doUpdate(T t) throws java.sql.SQLException;
  void doDelete(T t) throws java.sql.SQLException;
}

Class DAO yang mengimplementasikan interface diatas harus menyediakan setidaknya 4 buah metode yaitu :

  1. doCreate()
  2. doRetrieve()
  3. doUpdate(), dan
  4. doDelete().

Interface diatas dapat diimplementasikan seperti berikut :

import java.sql.*;
import java.util.*;

public class KontakDAO implements DataDAO<Kontak> {

  private Connection koneksi;

  public KontakDAO(Connection koneksi) {
    this.koneksi = koneksi;
  }

  @Override
  public void doCreate(Kontak t) throws SQLException {
    String sql = "INSERT INTO kontak(namaDepan, namaBelakang, alamat, noTelepon, email) VALUES (?, ?, ?, ?, ?)";
    PreparedStatement pstmt = koneksi.prepareStatement(sql);
    pstmt.setString(1, t.getNamaDepan());
    pstmt.setString(2, t.getNamaBelakang());
    pstmt.setString(3, t.getAlamat());
    pstmt.setString(4, t.getNoTelepon());
    pstmt.setString(5, t.getEmail());
    pstmt.executeUpdate();
    pstmt.close();
  }

  @Override
  public List<Kontak> doRetrieve() throws SQLException {
    List<Kontak> temp = new ArrayList<>();
    String sql = "SELECT * FROM kontak";
    Statement stmt = koneksi.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
    while(rs.next()) {
      Kontak k = new Kontak();
      k.setNo(rs.getInt("no"));
      k.setNamaDepan(rs.getString("namaDepan"));
      k.setNamaBelakang(rs.getString("namaBelakang"));
      k.setAlamat(rs.getString("alamat"));
      k.setNoTelepon(rs.getString("noTelepon"));
      k.setEmail(rs.getString("email"));
      temp.add(k);
    }
    rs.close();
    stmt.close();
    return temp;
  }

  @Override
  public void doUpdate(Kontak t) throws SQLException {
    String sql = "UPDATE kontak SET namaDepan=?, namaBelakang=?, alamat=?, noTelepon=?, email=? WHERE no=?";
    PreparedStatement pstmt = koneksi.prepareStatement(sql);
    pstmt.setString(1, t.getNamaDepan());
    pstmt.setString(2, t.getNamaBelakang());
    pstmt.setString(3, t.getAlamat());
    pstmt.setString(4, t.getNoTelepon());
    pstmt.setString(5, t.getEmail());
    pstmt.setInt(6, t.getNo());
    pstmt.executeUpdate();
    pstmt.close();
  }

  @Override
  public void doDelete(Kontak t) throws SQLException {
    String sql = "DELETE FROM kontak WHERE no=?";
    PreparedStatement pstmt = koneksi.prepareStatement(sql);
    pstmt.setInt(1, t.getNo());
    pstmt.executeUpdate();
    pstmt.close();
  }

}

Sampai tahap ini kita sudah memiliki class java yang bertugas untuk menangani proses aplikasi terhadap database khususnya pada tabel kontak. Selebihnya kita dapat menggunakan class tersebut pada program seperti pada contoh berikut :

import java.sql.*;

public class Main {

  static String url = "jdbc:mysql://127.0.0.1:3306/sampledb";
  static String user = "root";
  static String password = "p455w0rd";

  public static void main(String[] args) {
    try {
      DriverManager.registerDriver(new com.mysql.jdbc.Driver());
      Connection koneksi = DriverManager.getConnection(url, user, password);
      Kontak k = new Kontak();
      k.setNamaDepan("John");
      k.setNamaBelakang("Doe");
      k.setAlamat("Kendari");
      k.setNoTelepon("+624013123123");
      k.setEmail("john.doe@sample.com");
      KontakDAO ktkDao = new KontakDAO(koneksi);
      ktkDao.doCreate(k);
    }
    catch(SQLException exc) {
      System.err.println(exc.toString());
    }
  }

}

Java & MySQL (3) – Menggunakan Stored Procedure MySQL dan CallableStatement

Tutorial kali ini akan membahas tentang stored procedure MySQL dan pemanggilannya dalam aplikasi java dengan menggunakan objek CallableStatement.

MySQL Stored Procedure

Stored procedure pada intinya merupakan prosedur yang tersimpan di dalam database. Prosedur tersebut dapat menampung 1 atau lebih pernyataan SQL yang saling berhubungan.

Syntax pembuatan stored procedure adalah sebagai berikut :

CREATE PROCEDURE [nama_prosedur]
(
  IN|OUT param_1 [tipe_data],
  ...
  IN|OUT param_n [tipe_data],
)
BEGIN
  [pernyataan sql 1];
  [pernyataan sql 2];
  [pernyataan sql n];
END

Sebagai contoh, perhatikan script SQL berikut :

DROP DATABASE IF EXISTS sample;
CREATE DATABASE sample;
USE sample;

CREATE TABLE barang (
	kode VARCHAR(18) NOT NULL,
	nama TEXT NOT NULL,
	kategori VARCHAR(32) NOT NULL,
	harga INT NOT NULL,
	jumlah INT NOT NULL DEFAULT 1,
	primary key (kode)
);

CREATE TABLE penjualan (
	no INT NOT NULL AUTO_INCREMENT,
	tanggal TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
	kode_barang VARCHAR(18) NOT NULL,
	jumlah INT NOT NULL DEFAULT 1,
	PRIMARY KEY (no),
	FOREIGN KEY (kode_barang) REFERENCES barang (kode)
);

-- Pembuatan Stored Procedure
DELIMITER &
CREATE PROCEDURE tambah_penjualan (IN _kdBarang VARCHAR(18), IN _jmlBarang INT)
BEGIN
	SET @stok := (SELECT jumlah FROM barang WHERE kode = _kdBarang);
	INSERT INTO penjualan (kode_barang, jumlah) VALUES (_kdBarang, _jmlBarang);
	UPDATE barang SET jumlah = (@stok - _jmlBarang) WHERE kode = _kdBarang;
END &
DELIMITER ;

-- Tambah stok barang
INSERT INTO barang VALUES ("MB001", "Asus X370-F Gaming", "Motherboard", 4500000, 8);

Pada script diatas, pembuatan prosedur dilakukan pada baris 24 sampai 31. Dalam prosedur tersebut kita menggunakan tahapan yang umumnya terjadi dalam transaksi penjualan yaitu, menambah record penjualan kedalam tabel penjualan yang dilanjutkan dengan pengurangan jumlah stok dalam tabel barang.

Prosedur tersebut menggunakan 2 buah parameter yaitu, _kdBarang merupakan kode dari barang yang terjual, dan _jmlBarang yaitu berapa banyak barang yang terjual.

Proses yang terjadi dalam prosedur adalah sebagai berikut :

  1. Mengambil jumlah stok saat ini dari barang yang memiliki kode _kdBarang
  2. Menambah record penjualan kedalam tabel penjualan
  3. Memperbaharui jumlah barang dengan kode _kdBarang yaitu jumlah stok saat ini dikurangi jumlah terjual

Pemanggilan Prosedur

Prosedur diatas dapat dipanggil dengan menggunakan perintah :

CALL tambah_penjualan("MB001", 2);

Prosedur tersebut akan menambah record penjualan barang dengan kode MB001 dan memperbaharui jumlah stok barang MB001 menjadi 6 yaitu hasil pengurangan dari stok saat ini (8) dan jumlah terjual (2)

Pemanggilan Prosedur Melalui Aplikasi Java

Untuk memanggil prosedur MySQL dari aplikasi java, kita dapat menggunakan objek CallableStatement.

Objek CallableStatement terbentuk melalui metode prepareCall() dari objek Connection. Metode prepareCall() menggunakan 1 parameter String yaitu perintah pemanggilan prosedur.

Perhatikan contoh berikut :

import java.sql.*;

public class CallableStatementSample {

  static String url = "jdbc:mysql://127.0.0.1:3306/sample";
  static String user = "root";
  static String password = "";

  public static void main(String[] args) {
    try {
      DriverManager.registerDriver(new com.mysql.jdbc.Driver());
      Connection koneksi = DriverManager.getConnection(url, user, password);
      CallableStatement cstmt = koneksi.prepareCall("{CALL tambah_penjualan(?, ?)}");
      cstmt.setString(1, "MB001");
      cstmt.setInt(2, 2);
      cstmt.executeUpdate();
      cstmt.close();
      koneksi.close();
    }
    catch(SQLException exc) {
      System.err.println(exc.toString());
    }
  }

}

Java & MySQL (2) – Menggunakan PreparedStatement

Melanjutkan tulisan sebelumnya tentang dasar koneksi java dan mysql, pada tulisan kali ini saya akan membahas tentang penggunaan objek PreparedStatement untuk eksekusi query SQL. Untuk lebih memahamkan pembaca, saya akan mencoba menggunakan satu studi kasus sederhana.

Membuat Database

Ketikkan kode SQL berikut, simpan dengan nama dbinventory.sql dan eksekusi menggunakan client MySQL melalui Command Prompt.

DROP DATABASE IF EXISTS dbinventory;
CREATE DATABASE dbinventory;
USE dbinventory;

CREATE TABLE parts (
  kode VARCHAR(12) NOT NULL,
  nama TEXT NOT NULL,
  jumlah INT NOT NULL DEFAULT 1,
  tgl_masuk TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  kondisi ENUM('baik','rusak') NOT NULL DEFAULT 'baik',
  PRIMARY KEY (kode)
);

Import Class

Class java yang perlu kita import adalah sebagai berikut :

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

Registrasi Driver & Koneksi Database

Seperti sebelumnya kita perlu meregistrasi driver dan mengkoneksikan aplikasi ke database

try {
  DriverManager.registerDriver(new com.mysql.jdbc.Driver());
  Connection koneksi = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/namadb", "root", "p455w0rd");
}
catch(SQLException exc) {
  System.err.println(exc.toString());
}

Membuat Objek PreparedStatement

Objek PreparedStatement dibentuk menggunakan metode prepareStatement() dari objek koneksi yang sudah dibentuk sebelumnya.

Metode prepareStatement() menggunakan satu parameter String yaitu query SQL yang akan dieksekusi.

Disini kita coba menambah data baru kedalam tabel parts.

try {
  DriverManager.registerDriver(new com.mysql.jdbc.Driver());
  Connection koneksi = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/namadb", "root", "p455w0rd");
  String sql = "INSERT INTO parts(kode, nama) VALUES (?, ?) ";
  PreparedStatement ps = koneksi.prepareStatement(sql);
}
catch(SQLException exc) {
  System.err.println(exc.toString());
}

Perhatikan penggunaan simbol tanda tanya (?) pada pernyataan SQL diatas. Simbol tersebut akan mewakili nilai kolom dari data baru yang akan kita masukkan ke dalam tabel parts. Simbol tanda tanya pertama akan mewakili nilai untuk kolom kode dan simbol tanda tanya kedua akan mewakili nilai untuk kolom nama. Untuk kolom lain akan menggunakan nilai default sebagaimana disebutkan dalam pembuatan tabel sebelumnya.

Pemberian Nilai dan Eksekusi Pernyataan SQL

Pemberian nilai kolom dilakukan dengan menggunakan metode setXxx(id, value) dari objek PreparedStatement :

  1. xxx digantikan oleh tipe data dari nilai yang akan dimasukkan. Jika semisal tipe data kolom tabel adalah CHAR, VARCHAR, atau TEXT, maka metode yang digunakan adalah setString(). Metode lain yang dapat digunakan adalah setInt(), setFloat(), setDouble(), setBlob(), dan seterusnya
  2. id adalah index parameter dengan tipe integer. Untuk tanda tanya pertama kita gunakan nilai 1, untuk tanda tanya kedua digunakan nilai 2, dst
  3. value adalah nilai dari kolom.

Eksekusi pernyataan SQL dilakukan dengan menggunakan metode executeUpdate().

Perhatikan potongan kode berikut :

String sql = "INSERT INTO parts(kode, nama) VALUES (?, ?) ";
PreparedStatement ps = koneksi.prepareStatement(sql);
ps.setString(1, "MBAS01AM4");                     // kolom kode
ps.setString(2, "ASUS ROG Strix X370-F Gaming");  // kolom nama
ps.executeUpdate();                               // eksekusi pernyataan sql
ps.close();

Untuk mengambil data dari tabel kita gunakan metode executeQuery(), sebagai contoh :

String sql = "SELECT * FROM parts WHERE jumlah < ?";
PreparedStatement ps = koneksi.prepareStatement(sql);
int jumlah = 5;
ps.setInt(1, jumlah);
ResultSet rs = ps.executeQuery();

Contoh Program

Sebagai contoh latihan perhatikan kode program berikut ini :

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.Scanner;

public class PreparedStatementSample {

  private static final String url = "jdbc:mysql://127.0.0.1:3306/dbinventory";
  private static final String user = "root";
  private static final String password = "";

  public static void main(String[] args) {
    try {
      DriverManager.registerDriver(new com.mysql.jdbc.Driver());
      Connection c = DriverManager.getConnection(url, user, password);
      String sql = "INSERT INTO parts (kode, nama, jumlah) VALUES (?, ?, ?)";
      PreparedStatement pstmt = c.prepareStatement(sql);
      Statement stmt = c.createStatement();
      Scanner sc = new Scanner(System.in);
      while(true) {
        System.out.println("\nAplikasi Inventarisasi");
        System.out.println("[1] Tambah data");
        System.out.println("[2] Tampilkan data");
        System.out.println("[3] Keluar");
        System.out.print("Pilihan [1/2/3] : ");
        int pil = sc.nextInt();
        switch(pil) {
          case 1:
            tambahData(sc, pstmt);
            break;
          case 2:
            tampilkanData(stmt);
            break;
          case 3:
            System.out.println("\nTerima Kasih");
            System.exit(0);
            break;
        }
      }
    }
    catch(SQLException exc) {
      System.err.println(exc.toString());
    }
  }

  public static void tambahData(Scanner sc, PreparedStatement pstmt) throws SQLException {
    System.out.println("\nTambah data");
    System.out.print("Kode : ");
    String kode = sc.next();
    System.out.print("Nama : ");
    String nama = sc.next();
    System.out.print("Jumlah : ");
    int jumlah = sc.nextInt();
    pstmt.setString(1, kode);
    pstmt.setString(2, nama);
    pstmt.setInt(3, jumlah);
    pstmt.executeUpdate();
  }

  public static void tampilkanData(Statement stmt) throws SQLException {
    System.out.println("\nInventarisasi Saat Ini");
    ResultSet rs = stmt.executeQuery("select * from parts");
    int i = 1;
    while(rs.next()) {
      String kode = rs.getString("kode");
      String nama = rs.getString("nama");
      int jumlah = rs.getInt("jumlah");
      String fmt = "[%s] Kode: %-10s Nama: %-20s Jumlah: %-10s\n";
      System.out.printf(fmt, i, kode, nama, jumlah);
      i++;
    }
  }

}

Java & MySQL (1) – Koneksi database dan Statement

Pada tutorial ini kita akan belajar menghubungkan aplikasi java dengan database MySQL dengan API Java Database Connectivity (JDBC).

Import Class

Terdapat beberapa class yang harus diimport kedalam program java

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

Registrasi Driver

Driver untuk database MySQL disediakan dalam paket MySQL Connector/J yang bisa didownload dari halaman ini. Ekstrak file .zip atau .tar.gz yang sudah didownload, kemudian tempatkan file-file .jar kedalam CLASSPATH. Untuk registrasi driver sendiri dilakukan dengan menggunakan metode statik DriverManager.registerDriver().

try {
  DriverManager.registerDriver(new com.mysql.jdbc.Driver());
}
catch(SQLException exc) {
  System.err.println("Terjadi error : " + exc.toString());
}

Koneksi ke Database

Untuk membentuk koneksi ke database kita gunakan metode statik DriverManager.getConnection(). Metode ini akan mengembalikan objek Connection.

try {
  DriverManager.registerDriver(new com.mysql.jdbc.Driver());
  Connection koneksi = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/namadb", "root", "p455w0rd");
}
catch(SQLException exc) {
  System.err.println("Terjadi error : " + exc.toString());
}

Membuat Objek Statement

Untuk bisa mengeksekusi perintah SQL, kita membutuhkan objek Statement, objek ini didapatkan dengan menggunakan metode createStatement() dari objek koneksi yang sudah terbentuk sebelumnya.

try {
  DriverManager.registerDriver(new com.mysql.jdbc.Driver());
  Connection koneksi = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/namadb", "root", "p455w0rd");
  Statement stmt = koneksi.createStatement();
}
catch(SQLException exc) {
  System.err.println("Terjadi error : " + exc.toString());
}

Eksekusi Perintah SQL

Perintah SQL terbagi menjadi dua kelompok yaitu :

  1. Perintah Query : adalah perintah-perintah SQL yang mengembalikan hasil seperti SELECT, SHOW, dan DESC
  2. Perintah Update : adalah perintah-perintah SQL yang tidak mengembalikan hasil seperti INSERT, UPDATE, DELETE, dan DROP

Untuk perintah-perintah query kita gunakan metode executeQuery(), sedangkan untuk perintah-perintah SQL update kita gunakan metode executeUpdate(). Kedua metode disediakan dalam objek stmt yang sudah terbentuk sebelumnya.

Eksekusi Perintah Query

Metode executeQuery() akan mengembalikan objek ResultSet.

try {
  DriverManager.registerDriver(new com.mysql.jdbc.Driver());
  Connection koneksi = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/namadb", "root", "p455w0rd");
  Statement stmt = koneksi.createStatement();
  ResultSet rs = stmt.executeQuery("SELECT * FROM namatabel");
}
catch(SQLException exc) {
  System.err.println("Terjadi error : " + exc.toString());
}

Eksekusi Perintah Update

Metode executeUpdate() akan mengembalikan nilai integer, yaitu jumlah row yang terdampak dari perintah SQL.

try {
  DriverManager.registerDriver(new com.mysql.jdbc.Driver());
  Connection koneksi = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/namadb", "root", "p455w0rd");
  Statement stmt = koneksi.createStatement();
  int row = stmt.executeUpdate("INSERT INTO namatabel VALUES ('nilaikolom1', 'nilaikolom2')");
  System.out.println("Jumlah baris baru : " + row); // 1
}
catch(SQLException exc) {
  System.err.println("Terjadi error : " + exc.toString());
}

Memproses ResultSet

Objek ResultSet dapat diproses dengan menggunakan perulangan while. Metode yang digunakan bersama perulangan ini adalah metode next() yang mengembalikan nilai boolean true jika masih terdapat data dalam ResultSet dan false jika sudah tidak ada data dalam ResultSet.

Selebihnya untuk mendapatkan nilai kolom, kita gunakan perintah getXxx() dengan parameter nama atau index kolom, dimana xxx adalah tipe data dari kolom tabel. Misalnya tipe data kolom adalah CHAR, VARCHAR, atau TEXT, kita gunakan metode getString(), semisal tipe data kolom adalah INT kita gunakan metode getInt();

try {
  DriverManager.registerDriver(new com.mysql.jdbc.Driver());
  Connection koneksi = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/namadb", "root", "p455w0rd");
  Statement stmt = koneksi.createStatement();
  ResultSet rs = stmt.executeQuery("SELECT * FROM namatabel");
  while(rs.next()) {
    String nama = rs.getString("nama");
    int umur = rs.getInt("umur");
    System.out.println(nama);
    System.out.println(umur);
  }
}
catch(SQLException exc) {
  System.err.println("Terjadi error : " + exc.toString());
}

Kode Lengkap

Kode selengkapnya sebagai berikut :

// ExcJDBC01.java

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class ExcJDBC01 {

  public static void main(String[] args) {
    try {
      DriverManager.registerDriver(new com.mysql.jdbc.Driver());
      Connection koneksi = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/namadb", "root", "p455w0rd");
      Statement stmt = koneksi.createStatement();
      ResultSet rs = stmt.executeQuery("SELECT * FROM namatabel");
      while(rs.next()) {
        String nama = rs.getString("nama");
        int umur = rs.getInt("umur");
        System.out.println(nama);
        System.out.println(umur);
      }
    }
    catch(SQLException exc) {
      System.err.println("Terjadi error : " + exc.toString());
    }
  }

}

Parsing XML Dengan Java

Pada postingan kali ini, saya akan menuliskan sedikit tentang salah satu teknik parsing XML dengan menggunakan bahasa pemrograman java. Saya tidak akan menjelaskan secara mendetail tentang apa itu XML, selengkapnya bisa anda baca melalui website-website berikut :

Parsing sendiri adalah sebuah istilah yang merujuk kepada proses ekstraksi data/informasi dari sebuah struktur dokumen.

Sederhananya, proses parsing XML dilakukan dengan mentransformasikan file XML menjadi Document Object Model (DOM). Dari DOM tersebut kita dapat melakukan penelusuran (traverse) di tiap-tiap node hingga menemukan data yang diinginkan.

Sebagai contoh, semisal kita memiliki file XML dengan struktur berikut :

<?xml version="1.0" encoding="UTF-8"?>
<daftar-kontak>
  <kontak id="1">
    <nama>Ahmad</nama>
    <alamat>Kendari</alamat>
    <phone>12345</phone>
  </kontak>
  <kontak id="2">
    <nama>Budi</nama>
    <alamat>Makassar</alamat>
    <phone>90876</phone>
  </kontak>
  <kontak id="3">
    <nama>Dharmawan</nama>
    <alamat>Surabaya</alamat>
    <phone>213423</phone>
  </kontak>
</daftar-kontak>

Untuk mengambil data dari file tersebut, saya menggunakan kode java seperti dibawah ini :

package com.sad301.exc;

import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XMLParsing {

  public static void main(String[] args) {
    new XMLParsing();
  }

  public XMLParsing() {
    try {
      tryParse();
    }
    catch(Exception exc) {
      exc.printStackTrace();
    }
  }

  private void tryParse() throws Exception {
    File file = new File("daftar-kontak.xml");
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document d = db.parse(file);
    // ambil root node dari DOM
    Element elRoot = d.getDocumentElement();
    // ambil child node dari root dengan tag <kontak>
    NodeList nlKontak = elRoot.getElementsByTagName("kontak");
    // loop disemua child node
    for(int i=0; i<nlKontak.getLength(); i++) {
      Element elKontak = (Element)nlKontak.item(i);
      NodeList nlNama = elKontak.getElementsByTagName("nama");
      NodeList nlAlamat = elKontak.getElementsByTagName("alamat");
      NodeList nlPhone = elKontak.getElementsByTagName("phone");
      String id = elKontak.getAttribute("id");
      String nama = nlNama.item(0).getTextContent();
      String alamat = nlAlamat.item(0).getTextContent();
      String phone = nlPhone.item(0).getTextContent();
      String str = id + ":" + nama + ":" + alamat + ":" + phone;
      System.out.println(str);
    }
  }

}

Dan hasilnya adalah sebagai berikut :

sample

Referensi

Komunikasi Serial Java & Arduino Dengan RXTX

Setelah sekian lama menganggur diatas meja kerja, akhirnya Arduino Uno milik saya bisa dioprek lagi. Misinya kali ini adalah untuk membuat perangkat ini berkomunikasi dengan aplikasi java dengan tujuan untuk menerima data dari perangkat tersebut.

Model Uji Coba

Agar tidak memakan waktu terlalu lama, uji coba ini akan menggunakan model yang sederhana saja. Pada sisi Arduino, saya hanya menggunakan sebuah potentiometer. Nilai dari potentiometer tersebut akan dibaca melalui aplikasi java dan ditampilkan pada komponen JTextArea. Sebelum dapat membaca nilai dari arduino, user harus terlebih dahulu memilih port usb yang digunakan melalui komponen JComboBox.

Arduino

Seperti yang sudah disebutkan sebelumnya, pada sisi arduino kita akan menggunakan sebuah potentiometer. Komponen potentiometer sendiri memiliki 3 buah kaki, untuk menggunakannya kita perlu menghubungkan salah satu kaki (paling kanan atau paling kiri) ke pin 5V dari arduino, kaki tengah ke pin analog A0, dan sisanya ke pin GND. Untuk lebih jelasnya perhatikan ilustrasi dibawah.

arduino_sketch

Setelah menyambungkan potentiometer ke arduino, selanjutnya kita tinggal menuliskan kode sketch melalui Arduino IDE (download di http://arduino.cc/en/Main/Software) dan menguploadnya ke perangkat. Berikut kode sketch yang saya gunakan

int potPin = A0;
int potValue;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  potValue = analogRead(potPin);
  Serial.print(potValue);
  Serial.print(",");
  delay(15);
}

Konfigurasi RXTX

Sebelum masuk ke tahap coding program, kita terlebih dahulu harus melakukan konfigurasi library yang akan digunakan. Pada project ini kita akan menggunakan RXTX, yaitu library java yang memungkinkan komunikasi serial dan parallel antara perangkat dengan aplikasi java. Untuk penjelasan lebih lanjut, silahkan berkunjung ke website http://rxtx.qbang.org/wiki/index.php/Main_Page. Hal-hal yang perlu dilakukan adalah sebagai berikut :

  1. Download library RXTX dari websitenya http://rxtx.qbang.org/wiki/index.php/Download
  2. Extract file zip yang telah didownload
  3. Copy file rxtxSerial.dll dan rxtxParallel.dll ke folder C:\Program Files\java\jre7\bin
  4. Copy file RXTXcomm.jar ke direktori C:\Program Files\java\jre7\lib\ext

Program Java

Langkah terakhir adalah tahap coding program. Karena kode programnya lumayan panjang, saya hanya sebutkan bagian-bagian pentingnya saja. Pertama yang akan dibutuhkan oleh program adalah daftar port yang tersedia, kutipan kode untuk bagian ini adalah sebagai berikut :

Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
CBModelCommPortId model = new CBModelCommPortId(portEnum);

Daftar port yang sudah didapatkan akan ditampilkan dalam komponen JComboBox. Setelah user memilih port yang akan digunakan, selanjutnya tinggal menekan tombol yang akan mengeksekusi metode startConnection(). Kutipan kodenya adalah sebagai berikut :

private void startConnection() {
  try {
    String portId = (String)cbCommPortId.getSelectedItem();
    CommPortIdentifier commPortId = CommPortIdentifier.getPortIdentifier(portId);
    CommPort commPort = commPortId.open(getClass().getName(), 2000);
    if(commPort instanceof SerialPort) {
      serialPort = (SerialPort)commPort;
      serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
      isOpened = true;
      in = serialPort.getInputStream();
      serialPort.addEventListener(this);
      serialPort.notifyOnDataAvailable(true);
    }
  }
  catch(Exception exc) {
    taData.append(exc.toString()+"\n");
    bConnect.setSelected(false);
  }
}

Kemudian jika tombol yang sama ditekan lagi akan mengeksekusi metode stopConnection(). Kutipan kode dari metode tersebut adalah sebagai berikut :

private void stopConnection() {
  if(isOpened) {
    serialPort.close();
    serialPort.removeEventListener();
  }
}

Terakhir, karena class java yang dibuat mengimplementasikan interface SerialPortEventListener, kita perlu mendefinisikan metode serialEvent() dari interface tersebut. Kutipan kode yang saya gunakan adalah sebagai berikut :

public void serialEvent(SerialPortEvent arg0) {
  // TODO Auto-generated method stub
  int data;
  try {
    int len = 0;
    while((data=in.read()) > -1) {
      if(data==',') {
        break;
      }
      buffer[len++] = (byte)data;
    }
    taData.append(new String(buffer, 0, len) + "\n");
  }
  catch(IOException exc) {
    taData.append(exc.toString() + "\n");
  }
}

Berikut adalah cuplikasi gambar dari hasil eksekusi program

Java

Kode program selengkapnya dapat dilihat di https://github.com/sad301/SerialExc