14 March 2009

Menggunakan Spring Framework dalam Membuat DAO Layer.

Dalam pembangunan sebuah project Java J2EE ataupun J2SE, terkadang ada suatu blok yang berfungsi untuk mengatur segala sesuatu yang berhubungan dengan database. Koneksi ke database, fetching result dari query-query yang di supply, diatur dalam blok ini. Dengan design program yang seperti ini kita akan lebih mudah untuk mendeteksi error yang mungkin saja terjadi pada aplikasi kita nantinya.

Bagi para developer Java yang sudah terbiasa menggunakan menggunakan database sebagai salah satu bagian komponen aplikasi yang dibuatnya, tentu tidak punya kesulitan untuk membuat blok yang berfungsi sebagai pengakses database atau database accessor, dan kemudian menempatkan blok tersebut di dalam rangkaian arsitektur design aplikasi.

Ketika membuat blok untuk mengakses database ini, banyak cara yang bisa digunakan, salah satunya adalah menggunakan Spring Framework. Ya, jika pada kesempatan yang lalu, kita mencoba mengakses property file menggunakan Spring Framework, kali ini kita juga akan menggunakan Spring Framework pula untuk mengakses database, dan kemudian membuat blok database accessor atau lebih dikenal dengan DAO layer menggunakan framework tersebut.

Ok, langsung saja percobaan ini kita lakukan. Oh ya..,Dalam percobaan kali ini kita akan menggunakan Database MySQL sebagai databasenya(emang dari kemaren MySQL melulu….:P). Tahap pertama yang akan kita lakukan adalah membuat sebuah table lengkap dengan isinya dalam sebuah database pada MySQL. Tabel tersebut kita beri nama web_account dan berisi sekitar 10 sampai 20 data didalam rownya, sementara untuk field-fieldnya silahkan buat sesuai dengan keinginan kita. Tapi nantinya field-field dalam table ini akan jadi suatu bagian dalam kode-kode programnya, sehingga field-field ini harus lebih tersusun dengan rapi. Atau bisa juga copy paste SQL Source berikut ini:


CREATE TABLE `web_account` (
`USERNAME` varchar(30) NOT NULL DEFAULT '',
`PASSWORD` varchar(30) NOT NULL DEFAULT '',
`CREATE_TIME` datetime DEFAULT NULL,
`CREATE_USER` varchar(30) DEFAULT NULL,
`UPDATE_TIME` datetime DEFAULT NULL,
`UPDATE_USER` varchar(30) DEFAULT NULL,
PRIMARY KEY (`USERNAME`)
);

INSERT INTO `web_account` VALUES ('admin','adminya33','2009-03-15 08:32:21','admin','2009-03-15 08:32:21','admin'),('andre','andre456','2009-03-15 08:34:53','admin','2009-03-15 08:34:53','admin'),('fitri','fitri54','2009-03-15 08:33:22','admin','2009-03-15 08:33:22','admin'),('ganteng','ganteng99','2009-03-15 08:34:21','admin','2009-03-15 08:34:21','admin'),('gerry','gerry87','2009-03-15 08:33:41','admin','2009-03-15 08:33:41','admin'),('gue','guelagi','2009-03-15 08:33:56','admin','2009-03-15 08:33:56','admin'),('hebat','hebatlah','2009-03-15 08:34:36','admin','2009-03-15 08:34:36','admin'),('heru','heur334','2009-03-15 08:32:54','admin','2009-03-15 08:32:54','admin'),('joe','joe77','2009-03-15 08:32:39','admin','2009-03-15 08:32:39','admin'),('kasep','sekap25','2009-03-15 08:33:08','admin','2009-03-15 08:33:08','admin'),('linux','linux09','2009-03-15 08:35:22','admin','2009-03-15 08:35:22','admin'),('mojo','monk123','2009-03-15 08:31:50','admin','2009-03-15 08:31:50','admin');

Dari tabel tersebut kita harus membuat sebuah class yang mempunyai property class yang mampu merepresentasikan field-field yang ada pada tabel. Tujuan dibuatnya class ini adalah untuk menampung isi dari tabel itu. Pada pemakaiannya nanti class ini akan menjadi sebuah variabel object baik itu objeck array ataupun single object.

Class ini akan kita buat dengan menggunakan class POJO(Plain Old Java Object) sederhana saja, berikut source code dari class ini:

package org.mojo.spring.entity;

import java.util.Date;

/**
* Created by IntelliJ IDEA.
* User: Mojo
* Date: Mar 15, 2009
* Time: 8:45:10 AM
* To change this template use File | Settings | File Templates.
*/
public class WebAccount {
private String userName;
private String password;
private Date createDate;
private String createUser;
private Date updateDate;
private String updateUser;

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public Date getCreateDate() {
return createDate;
}

public void setCreateDate(Date createDate) {
this.createDate = createDate;
}

public String getCreateUser() {
return createUser;
}

public void setCreateUser(String createUser) {
this.createUser = createUser;
}

public Date getUpdateDate() {
return updateDate;
}

public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}

public String getUpdateUser() {
return updateUser;
}

public void setUpdateUser(String updateUser) {
this.updateUser = updateUser;
}

public String toString() {
return "WebAccount{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
", createDate=" + createDate +
", createUser='" + createUser + '\'' +
", updateDate=" + updateDate +
", updateUser='" + updateUser + '\'' +
'}';
}
}

Tibalah saatnya kita pada pembuatan DAO Layer menggunakan Spring Framework, jangan lupa untuk men-download library-library yang diperlukan seperti library Spring, library MySQL Connector, dan library common-logging untuk bisa mengikuti percobaan ini. library common-logging harus ikut juga di masukkan dalam percobaan kita kali ini, sebab Spring Framework mempunyai kertergantungan yang sangat tinggi terhadap library ini, sementara library MySQL Connector, kita pakai karena database yang kita pakai untuk percobaan ini adalah database MySQL(lagi-lagi MySQL…:P).

Untuk DAO Layer yang akan kita buat dibawah ini, kita akan membatasi hanya pada method mengambil banyaknya baris(select count(1)) dan mengambil data(Select *) yang ada pada tabel saja, method lainnya seperti insert, update atau delete, silahkan nanti dikembangkan sendiri sesuai dengan keinginan. Untuk method select count(1) skenarionya adalah method ini akan mempunyai kembalian (return) berupa type data Integer, sementara untuk method select * akan mempunyai kembalian (return) berupa list. Mari perhatikan kode-kode berikut ini.

package org.mojo.spring.dao.JdbcDao;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.mojo.spring.entity.WebAccount;

import javax.sql.DataSource;
import java.util.List;
import java.util.ArrayList;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet;

/**
* Created by IntelliJ IDEA.
* User: Mojo
* Date: Mar 15, 2009
* Time: 8:46:57 AM
* To change this template use File | Settings | File Templates.
*/
public class WebAccountJdbcDAO extends JdbcDaoSupport {
private DataSource ds;
private JdbcTemplate tpl;

public int getNumOfWebAccount() {
logger.info("getNumOfWebAccount");
int iRes = 0;
ds = getDataSource();
tpl = new JdbcTemplate(ds);
String sQuery = "SELECT COUNT(1) from web_account";
try {
iRes = tpl.queryForInt(sQuery);
logger.info("Result of getNumOfWebAccount : " + iRes);
} catch (Exception e) {
logger.info("Exception in getNumOfWebAccount()" + e.getMessage());
}
return iRes;
}

public List<WebAccount> getWebAccountList(boolean flagLimit, int limit) {
final List<WebAccount> result = new ArrayList();
final int iLimit = limit;
ds = getDataSource();
JdbcTemplate tpl = new JdbcTemplate(ds);
String sQuery = "SELECT * FROM web_account";

if (flagLimit) {
sQuery += " LIMIT ? ";
}

class PreparedStatementHandler implements PreparedStatementSetter {
public void setValues(PreparedStatement ps) throws SQLException {
int n = 0;
ps.setInt(++n, iLimit);
}
}

class ServiceHandler implements RowCallbackHandler {
public void processRow(ResultSet rs) throws SQLException {
WebAccount wa = new WebAccount();
wa.setUserName(rs.getString("USERNAME"));
wa.setPassword(rs.getString("PASSWORD"));
wa.setCreateDate(rs.getDate("CREATE_TIME"));
wa.setCreateUser(rs.getString("CREATE_USER"));
wa.setUpdateDate(rs.getDate("UPDATE_TIME"));
wa.setUpdateUser(rs.getString("UPDATE_USER"));
result.add(wa);
}
}

if (flagLimit) {
tpl.query(sQuery, new PreparedStatementHandler(), new ServiceHandler());
}else {
tpl.query(sQuery, new ServiceHandler());
}
return result;
}

}

Mari kita bahas kode-kode diatas. Pada baris paling atas kode tersebut ada deklarasi lokasi dimana class ini berada, kemudian pada baris-baris selanjutnya kita mengimport class-class dari library Spring Framework dan library java default lain yang kita butuhkan nantinya.

package org.mojo.spring.dao.JdbcDao;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.mojo.spring.entity.WebAccount;

import javax.sql.DataSource;
import java.util.List;
import java.util.ArrayList;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet;
………

Kita beri nama kelas ini dengan nama WebAccountJDBCDAO, ditandai dengan deklarasi class pada baris selanjutnya setelah comment, (Saya pakai InteliJidea sebagai IDE favorit saya). Tepat dibawah deklarasi class tersebut kita membuat dua buah variabel yang kita deklarasikan sebagai variabel ds bertype DataSource dan variabel tpl bertipe JdbcTemplate.

………
public class WebAccountJDBCDAO extends JdbcDaoSupport {
private DataSource ds;
private JdbcTemplate tpl;
………

Type data DataSource adalah class yang kita ambil dari package javax.sql, sementara JdbcTemplate adalah class yang kita ambil dari package spring, yaitu package org.springframework.jdbc.core.JdbcTemplate.

Kemudian mari kita lihat satu persatu method yang ada pada kode-kode tersebut. Method getNumOfWebAccount:

……
public int getNumOfWebAccount() {
logger.info("getNumOfWebAccount");
int iRes = 0;
ds = getDataSource();
tpl = new JdbcTemplate(ds);
String sQuery = "SELECT COUNT(1) from web_account";
try {
iRes = tpl.queryForInt(sQuery);
logger.info("Result of getNumOfWebAccount : " + iRes);
} catch (Exception e) {
logger.info("Exception in getNumOfWebAccount()" + e.getMessage());
}
return iRes;
}
……

Pada method ini kita melihat, query yang akan di eksekusi hanyalah query sederhana yaitu “select count(1) from web_account”. Jika kita mengeksekusi query ini pada konsol MySQL, hasil dari query ini adalah banyaknya baris yang ada pada tabel web_account yang kita miliki. Pada method ini kita menempatkan hasil query tersebut ke sebuah variabel yang bernama iRes, dimana variabel tersebut bertype-data integer. Sementara jika kita menyusun langkah yang ada pada method ini, maka langkah-langkahnya adalah sebagai berikut:

  1. membuat variabel iRes bertype integer.

  2. menginisialisasi variabel ds dengan cara memanggil interface getDatasource.

  3. membuat object JdbcTemplate baru dengan parameter ds.

  4. membuat sebuah variabel String dengan nama sQuery dan langsung mengisinya.

  5. mengeksekusi query tersebut dalam blok try-catch dan kemudian memasukan hasil dari query tersebut ke dalam variabel iRes.

  6. membuat statemen kembalian dari method tsb.

Sementara untuk baris-baris yang berisi logger, hanyalah sebagai sebuah cara kita untuk meninggalkan jejak, agar jika ada error yang terjadi kita bisa tahu persis pada baris mana error itu terjadi.

Kemudian mari kita bahas methode yang kedua yaitu method getWebAccountList. Pada method ini kita membuat dua buah class dalam(Inner Class), dengan tujuan untuk lebih membatasi agar kode-kode yang kita buat lebih terlihat rapi:

…….
class PreparedStatementHandler implements PreparedStatementSetter {
public void setValues(PreparedStatement ps) throws SQLException {
int n = 0;
ps.setInt(++n, iLimit);
}
}

class ServiceHandler implements RowCallbackHandler {
public void processRow(ResultSet rs) throws SQLException {
WebAccount wa = new WebAccount();
wa.setUserName(rs.getString("USERNAME"));
wa.setPassword(rs.getString("PASSWORD"));
wa.setCreateDate(rs.getDate("CREATE_TIME"));
wa.setCreateUser(rs.getString("CREATE_USER"));
wa.setUpdateDate(rs.getDate("UPDATE_TIME"));
wa.setUpdateUser(rs.getString("UPDATE_USER"));
result.add(wa);
}
}
…….

Jika kita melihat kode-kode pada dua buah inner class tersebut, masing-masing class ini ternyata menangani dua fungsi yang penting. Fungsi dari kelas pertama menangani PrepareStatement, class ini meng-implements PreparedStatementSetter milik Spring Framework. Dan kelas kedua menangani penempatan hasil query ke dalam variable WebAccount, kelas ini meng-implements RowcallbackHandler yang juga milik Spring Framework.

Pada kelas pertama kita meng-override method setValues milik class PreparedStatementHandler sebagai syarat implementasi. Dan kelas kedua kita juga harus meng-override method processRow sebagai syarat implementasi class RowCallBackHandler. Kemudian mari kita lihat kode-kode utama pada method getWebAccountList yang tadi kita buat.

……
public List<WebAccount> getWebAccountList(boolean flagLimit, int limit) {
final List<WebAccount> result = new ArrayList();
final int iLimit = limit;
ds = getDataSource();
JdbcTemplate tpl = new JdbcTemplate(ds);
String sQuery = "SELECT * FROM rss_feeder";

if (flagLimit) {
sQuery += " LIMIT ?";
}
……..
……..
……..
if (flagLimit) {
tpl.query(sQuery, new PreparedStatementHandler(), new ServiceHandler());
} else {
tpl.query(sQuery, new ServiceHandler());
}
return result;
}
……

Pada kode-kode utama method diatas kita mempunyai kembalian dari method ini berupa list dan dua buah parameter yaitu flagLimit bertype boolean dan limit bertype integer. Langkah awal dari penyusunan methode ini sama dengan langkah awal penyusunan methode sebelumnya getNumOfWebAccount tadi, hanya saja karena ada dua parameter pada method ini, maka kita buat sedikit logic programming disini, yaitu pada baris branching. Pada baris branching kita buat sebuah logic apabila nilai yang ada pada variabel flagLimit adalah true maka query yang ada kita tambahkan dengan string “LIMIT ?” sehingga menjadi “SELECT * FROM web_account limit ?”, jika flagLimit adalah false maka query akan tetap seperti yang pertama kali di inisialisasikan.

Titik-titik yang ada di tengah kode-kode utama ini merupakan kode-kode inner class yang sudah kita bahas sebelumnya diatas. Kemudian kita tiba pada kode dimana pada baris eksekusi query dilakukan. Pada baris ini juga ada branching yang akan memutuskan akan menggunakan inner class PreparedStatementHandler atau tidak, keputusan penggunaan tergantung pada nilai dari flagLimit, silahkan analisis sendiri kode branching tersebut. Dan akhir dari method ini adanya statement kembalian dari methode ini yang berupa list di wakili oleh variabel result.

Demikianlah cara kita untuk menggunakan Spring Framework dalam pembuatan DAO Layer. Selanjutnya kita akan mencoba menggunakan DAO layer tersebut untuk dipakai dalam sebuah program Java Console.

Untuk bisa menggunakan DAO Layer tersebut, kita harus membuat file konfigurasi Spring Framework. Langsung saja kita buat file ini dengan nama “applicationContext.xml”, seperti pada posting artikel sebelumnya yang juga menggunakan Spring Framework, kita akan meletakkan file ini didalam sebuah folder config yang terletak sejajar dengan folder src pada project percobaan kita kali ini. Di bawah ini adalah kode-kode file konfigurasi Spring Framework tsb.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!--Data Source-->
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/java_spring"/>
<property name="username" value="root"/>
<property name="password" value="root99"/>
</bean>

<bean id="webAccountDAO" class="org.mojo.spring.dao.JdbcDao.WebAccountJdbcDAO">
<property name="dataSource" ref="ds"/>
</bean>
</beans>

Perhatikan pada file konfigurasi tersebut, bean pertama yg kita buat adalah ds, bean ini adalah bean yang berfungsi untuk mengakses database MySQL, bean ini memakai class yang dimilki oleh Spring Framework yaitu class DriverManagerDataSource. Kemudian karena ini adalah accessor Spring untuk mengakses database, maka kita harus mensupply property-property yang berhubungan dengan database tersebut, seperti username, url, password, dan driverClassName dari database yang akan kita pakai sesuai dengan yang ada pada setting database kita.

Kemudian untuk bean kedua adalah bean yang akan mewakili DAO Layer yang kita buat tadi. Property yang harus diisi oleh bean ini adalah property dataSource, sementara referensi dari property bean ini adalah bean ds yang sebelumnya kita buat tadi.

Dan penggunaan dalam aplikasi Java Console untuk DAO Layer tersebut bisa kita lihat pada kode-kode berikut ini:

package org.mojo.spring.application;

import org.mojo.spring.dao.JdbcDao.WebAccountJdbcDAO;
import org.mojo.spring.entity.WebAccount;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import java.util.List;

/**
* Created by IntelliJ IDEA.
* User: Mojo
* Date: Mar 15, 2009
* Time: 11:05:55 AM
* To change this template use File | Settings | File Templates.
*/
public class SpringReadDatabase {

private WebAccountJdbcDAO dao = null;
public static void main(String[] args) {
//call SpringConfiguration File
ApplicationContext ctx = new FileSystemXmlApplicationContext("config/applicationContext.xml");
SpringReadDatabase app = new SpringReadDatabase();

//call Desired bean
app.dao = (WebAccountJdbcDAO) ctx.getBean("webAccountDAO");

//declare Variable
WebAccount[] waList = null;

//getNumOfWebAccount
int i = app.dao.getNumOfWebAccount();
System.out.println("Num Rows : " + i);

//getWebAccountList
List<WebAccount> list = app.dao.getWebAccountList(false,0);

//convert List to ObjectArray
if (list.size() > 0) {
waList = new WebAccount[list.size()];
for (short j = 0; j < list.size(); j++) {
waList[j] = list.get(j);
}
}

//iterate ObjectArray to PrintOut to console
for (int j = 0; j < waList.length; j++) {
WebAccount webAccount = waList[j];
System.out.println("Name : " + webAccount.getUserName());
System.out.println("Password : " + webAccount.getPassword());
System.out.println("FullWebAccount : " + webAccount);
}


}

public void setDao(WebAccountJdbcDAO dao) {
this.dao = dao;
}
}

Demikianlah cara penggunaan DAO Layer yang kita buat tadi dalam aplikasi Java Console. Untuk pembahasannya silahkan di analisa sendiri, agar kita lebih tajam memahami dan menganalisa kode-kode sebuah program yang kita buat.


Semoga Bermanfaat

Menteng, 15 Maret 2009


josescalia

5 comments:

Unknown said...

nice post mas..btw saya ga liat ada post tentang jsf nih :)

framework favoritnya sekarang apa? hehe.

JoseScalia said...

Iya nih mas...
Saya agak kesulitan juga cari ide buat posting JSF...he..he.he..(alasan..bilang aja ga bisa..ha...ha..ha..)

thnks

MASHDUQI said...

Mojo..mojo..ga cuma teori tapi prakteknya juga good...
Gw kalah...dgn tantangan gw dulu...dunia kita beda.

Anonymous said...

Tolong artikel Mysql dari dasar ke sampai Expert dibnyakin dong soalnya saya gagap Mysql

Steve said...

good posting bang!

ini sangt membantu saya..!kl bsa bhas jg penggunaan spring dalam membangun web service, soalnya saya lg mau bljr web service mengugunakan spring ne..!!

mhon bantuanya!:)