Dian's Blog

{ while (true) { doLearning(); } }

Loading...

Memanfaatkan Struts Action Mapper untuk Membuat Clean URL

Posted on 29 September 2010 by Dian Aditya

Ini merupakan salah satu favorit saya yang ada di Struts yaitu ActionMapper. Biar lebih jelas berikut saya kutip sedikit dari dokumentasi Struts2.

ActionMapper interface menyediakan pemetaan antara HTTP Request dan Action Invocation Request atau sebaliknya.

Lebih sederhananya dengan mengimplementasikan ActionMapper ini kita dapat menentukan action class yang akan dieksekusi berdasarkan HttpServletRequest yang kita terima.

Sebagai contoh saya ingin mengubah gaya url seperti berikut ini

http://domain/project/employe?id=1234

menjadi

http://domain/project/employe/1234

sehingga saya menentukan bahwa baris setelah nama project merupakan nama action (/employee) dan baris setelah nama action adalah id (/1234).

Berikut kodenya

  1: package com.mervpolis.dwx.struts.mapper;
  2: 
  3: import java.util.HashMap;
  4: 
  5: import javax.servlet.http.HttpServletRequest;
  6: 
  7: import org.apache.struts2.dispatcher.mapper.ActionMapping;
  8: import org.apache.struts2.dispatcher.mapper.DefaultActionMapper;
  9: 
 10: import com.opensymphony.xwork2.config.ConfigurationManager;
 11: 
 12: public class MyCustomMapper extends DefaultActionMapper {
 13: 
 14: 	public ActionMapping getMapping(HttpServletRequest request,
 15: 			ConfigurationManager configManager) {
 16: 
 17: 		ActionMapping mapping = super.getMapping(request, configManager);
 18: 		/**
 19: 		 * Ketika bukan action yang dipanggil 
 20: 		 * ex: http://domain/project/gambar.jpg
 21: 		 */
 22: 		if (mapping == null)
 23: 			return mapping;
 24: 
 25: 		if (mapping.getParams() == null)
 26: 			mapping.setParams(new HashMap<String, Object>());
 27: 
 28: 		// Menambil url path
 29: 		String path = request.getServletPath().substring(1);
 30: 		// Memotong-motong path diantara karakter '/'
 31: 		String actions[] = path.split("/");
 32: 
 33: 		// Array terakhir sebagai id
 34: 		String id = actions[actions.length - 1];
 35: 		// Array sebelum id sebagai actionName
 36: 		String actionName = actions[actions.length - 2];
 37: 
 38: 		mapping.setName(actionName);
 39: 		mapping.getParams().put("id", id);
 40: 
 41: 		return mapping;
 42: 	}
 43: }
 44: 

Selanjutnya tinggal mendaftarkan ActionMapper dengan menambahkan properti pada struts.properties

  1: struts.mapper.class=com.mervpolis.dwx.struts.mapper.MyCustomMapper

atau dalam struts.xml

  1: <constant name="struts.mapper.class" value="com.mervpolis.dwx.struts.mapper.MyCustomMapper" />

Kemudian action class cukup membuat method setId(String id) untuk mendapatkan id dari url, tidak hanya action class, dengan memanipulasi ActionMapper ini kita dapat pula menentukan method yang akan dieksekusi ketika action class dipanggil.

Hibernate Event Listener

Posted on 19 September 2010 by Dian Aditya

Barusan saya baca-baca tentang database trigger dan sempat coba-coba, malas juga ternyata nulis kodenya yang begitu banyak :p benar-benar programmer yang buruk, hehehehe... Dan seperti apa yang saya inginkan, tuink... sangat tepat, ternyata hibernate juga menyediakan fasilitas yang mirip seperti trigger pada database, yaitu Hibernate Event. Sebuah mekanisme yang akan otomatis dijalankan apabila pemicu dipanggil. Untuk penjelasan lebih lanjut tentang event dan trigger bisa lihat di sini dan di sini (lagi-lagi males nulis :p).

Langsung saja ke kasusnya...

Saya mempunyai dua buah entity yaitu Produk dan CatatanAktivitasProduk. Dan saya akan membuat sebuah mekanisme agar hibernate secara otomatis manambahkan baris data pada CatatanAktivitasProduk ketika user melakukan transaksi (CRUD) data terhadap table Produk. Baris data berupa tanggal transaksi, aktivitas (lihat, tambah, perbarui, ataupun hapus), dan id produk yang terpengaruh akibat transaksi yang dilakukan oleh user tersebut.

Pertama berikut entity yang saya butuhkan.

  1: package com.mervpolis.dwx.hibernate.entity;
  2: 
  3: import javax.persistence.Column;
  4: import javax.persistence.Entity;
  5: import javax.persistence.GeneratedValue;
  6: import javax.persistence.GenerationType;
  7: import javax.persistence.Id;
  8: import javax.persistence.Table;
  9: 
 10: @Entity
 11: @Table
 12: public class Produk {
 13: 
 14: 	@Id
 15: 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 16: 	private long id;
 17: 
 18: 	@Column
 19: 	private String nama;
 20: 
 21: 	@Column
 22: 	private long harga;
 23: 
 24: 	@Column
 25: 	private String deskripsi;
 26: 
 27: 	public long getId() {
 28: 		return id;
 29: 	}
 30: 
 31: 	public void setId(long id) {
 32: 		this.id = id;
 33: 	}
 34: 
 35: 	public String getNama() {
 36: 		return nama;
 37: 	}
 38: 
 39: 	public void setNama(String nama) {
 40: 		this.nama = nama;
 41: 	}
 42: 
 43: 	public long getHarga() {
 44: 		return harga;
 45: 	}
 46: 
 47: 	public void setHarga(long harga) {
 48: 		this.harga = harga;
 49: 	}
 50: 
 51: 	public String getDeskripsi() {
 52: 		return deskripsi;
 53: 	}
 54: 
 55: 	public void setDeskripsi(String deskripsi) {
 56: 		this.deskripsi = deskripsi;
 57: 	}
 58: 
 59: }
  1: package com.mervpolis.dwx.hibernate.entity;
  2: 
  3: import java.sql.Timestamp;
  4: 
  5: import javax.persistence.Column;
  6: import javax.persistence.Entity;
  7: import javax.persistence.GeneratedValue;
  8: import javax.persistence.GenerationType;
  9: import javax.persistence.Id;
 10: import javax.persistence.JoinColumn;
 11: import javax.persistence.ManyToOne;
 12: import javax.persistence.Table;
 13: 
 14: @Entity
 15: @Table
 16: public class CatatanAktivitasProduk {
 17: 
 18: 	@Id
 19: 	@GeneratedValue(strategy=GenerationType.IDENTITY)
 20: 	private long id;
 21: 
 22: 	@ManyToOne
 23: 	@JoinColumn(name = "produk_id")
 24: 	private Produk produk;
 25: 
 26: 	@Column
 27: 	private String aktivitas;
 28: 
 29: 	@Column
 30: 	private Timestamp tanggal;
 31: 
 32: 	public long getId() {
 33: 		return id;
 34: 	}
 35: 
 36: 	public void setId(long id) {
 37: 		this.id = id;
 38: 	}
 39: 
 40: 	public Produk getProduk() {
 41: 		return produk;
 42: 	}
 43: 
 44: 	public void setProduk(Produk produk) {
 45: 		this.produk = produk;
 46: 	}
 47: 
 48: 	public String getAktivitas() {
 49: 		return aktivitas;
 50: 	}
 51: 
 52: 	public void setAktivitas(String aktivitas) {
 53: 		this.aktivitas = aktivitas;
 54: 	}
 55: 
 56: 	public Timestamp getTanggal() {
 57: 		return tanggal;
 58: 	}
 59: 
 60: 	public void setTanggal(Timestamp tanggal) {
 61: 		this.tanggal = tanggal;
 62: 	}
 63: 
 64: }

Dan selanjutnya adalah membuat listenernya yang akan otomatis melakukan aksi ketika user melakukan CRUD terhadap table Produk. Untuk contoh saya akan membuat listener yang akan menjalankan event setelah user melakukan insert data terhadap table Produk.

  1: package com.mervpolis.dwx.hibernate.event;
  2: 
  3: import java.sql.Timestamp;
  4: 
  5: import org.hibernate.Session;
  6: import org.hibernate.event.PostInsertEvent;
  7: import org.hibernate.event.PostInsertEventListener;
  8: 
  9: import com.mervpolis.dwx.hibernate.entity.CatatanAktivitasProduk;
 10: import com.mervpolis.dwx.hibernate.entity.Produk;
 11: 
 12: public class ProdukEventListener implements PostInsertEventListener {
 13: 
 14: 	@Override
 15: 	public void onPostInsert(PostInsertEvent event) {
 16: 		if (event.getEntity() instanceof Produk) {
 17: 			CatatanAktivitasProduk aktivitasProduk = new CatatanAktivitasProduk();
 18: 			Session session = event.getSession();
 19: 
 20: 			aktivitasProduk.setAktivitas("tambah");
 21: 			aktivitasProduk.setProduk((Produk) event.getEntity());
 22: 			aktivitasProduk
 23: 					.setTanggal(new Timestamp(System.currentTimeMillis()));
 24: 
 25: 			session.saveOrUpdate(aktivitasProduk);
 26: 		}
 27: 	}
 28: 
 29: }

Selanjutnya adalah mendaftarkan listener pada konfigurasi hibernate (hibernate.cfg.xml).

  1: <?xml version="1.0" encoding="UTF-8"?>
  2: <!DOCTYPE hibernate-configuration PUBLIC
  3: 		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  4: 		"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
  5: <hibernate-configuration>
  6:     <session-factory>
  7:         <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
  8:         <property name="hibernate.connection.password">admin</property>
  9:         <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
 10:         <property name="hibernate.connection.username">root</property>
 11:         <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 12:         <property name="hibernate.hbm2ddl.auto">update</property>
 13:         <property name="hibernate.show_sql">true</property>
 14: 
 15: 		<mapping class="com.mervpolis.dwx.hibernate.entity.Produk"/>
 16: 		<mapping class="com.mervpolis.dwx.hibernate.entity.CatatanAktivitasProduk"/>
 17: 
 18: 		<listener class="com.mervpolis.dwx.hibernate.event.ProdukEventListener" type="post-insert"/>
 19:     </session-factory>
 20: </hibernate-configuration>

Selanjutnya saya akan mencoba menjalankan sebuah kode yang akan melakukan insert data terhadap table produk.

  1: package com.mervpolis.dwx.hibernate;
  2: 
  3: import org.hibernate.Session;
  4: import org.hibernate.SessionFactory;
  5: import org.hibernate.cfg.AnnotationConfiguration;
  6: 
  7: import com.mervpolis.dwx.hibernate.entity.Produk;
  8: 
  9: public class InsertData {
 10: 	public static void main(String[] args) {
 11: 		SessionFactory factory = new AnnotationConfiguration().configure()
 12: 				.buildSessionFactory();
 13: 		Session session = factory.openSession();
 14: 
 15: 		Produk produk = new Produk();
 16: 
 17: 		session.getTransaction().begin();
 18: 		produk.setNama("Sendal Jepit");
 19: 		produk.setHarga(2000);
 20: 		produk.setDeskripsi("Sendal yang dijepit");
 21: 		session.saveOrUpdate(produk);
 22: 		session.getTransaction().commit();
 23: 	}
 24: }
 25: 

Dan apa yang terjadi ketika kode diatas saya jalankan? Secara otomatis hibernate akan menjalankan perintah yang saya taruh pada listener. Nahlho mana buktinya? Ada baiknya bila anda buktikan sendiri dengan mencoba membuat mekanisme seperti di atas :) selamat mencoba.

Menggunakan Spring Annotation (Struts2-Spring #2)

Posted on 08 September 2010 by Dian Aditya

Ini lanjutan dari blog saya yang kemarin tentang Integrasi Struts2 dengan Spring Framework, dan yang ingin saya sharing kali ini gak akan jauh berbeda dari topik kemarin, yaitu tentang salah satu fitur dari Spring Framework yang sudah ada sejak versi 2.5 yaitu annotation. Dalam hal ini saya akan mencontohkan bagaimana melakukan autowiring terhadap DataSource (gak jauh dari yang kemarin, cuma ganti jadi anotasi doank).

Kali ini saya membuat kasus (lohloh bikin kasus) dimana saya memiliki sebuah Data Access Object (DAO) untuk melakukan transaksi database, dan DAO ini membutuhkan DataSource untuk dapat melakukan tugasnya yang akan digunakan oleh Controller untuk menyampaikannya kepada Viewer Layer. Hehehehe?. Saya juga bingung gimana menggambarkannya.

Langsung berangkat ke TKP.

Berikut sedikit modifikasi dari applicationContext-jdbc.xml

  1: <?xml version="1.0" encoding="UTF-8"?>
  2: <beans xmlns="http://www.springframework.org/schema/beans"
  3: 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  4: 	xmlns:p="http://www.springframework.org/schema/p"
  5: 	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  6: 		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  7: 
  8: 	<context:component-scan base-package="com.mervpolis.dwx" />
  9: 
 10: 	<bean id="dataSource"
 11: 		class="org.springframework.jdbc.datasource.DriverManagerDataSource"
 12: 		p:driverClassName="com.mysql.jdbc.Driver" p:username="root"
 13: 		p:password="admin" p:url="jdbc:mysql://localhost:3306/test" />
 14: 
 15: </beans>

Nah ada satu baris mantra yang ditambahkan di situ yang berfungsi untuk melakukan scan terhadap semua class yang mengandung anotasi seperti @Autowired @Service @Component dll.

ItemDao.java

  1: package com.mervpolis.dwx.struts2spring.dao;
  2: 
  3: import java.sql.ResultSet;
  4: 
  5: public interface ItemDao {
  6: 	void saveItem(String name, String price);
  7: 
  8: 	ResultSet getAllItems();
  9: }

Berikut implementasinya

  1: package com.mervpolis.dwx.struts2spring.dao;
  2: 
  3: import java.sql.Connection;
  4: import java.sql.PreparedStatement;
  5: import java.sql.ResultSet;
  6: import java.sql.SQLException;
  7: 
  8: import javax.sql.DataSource;
  9: 
 10: import org.springframework.beans.factory.annotation.Autowired;
 11: import org.springframework.stereotype.Service;
 12: 
 13: /**
 14:  * Sama dengan
 15:  * <code>&lt;bean id="itemDao" class="com.mervpolis.dwx.struts2spring.dao.ItemDaoImpl"&gt;</code>
 16:  *
 17:  */
 18: @Service
 19: public class ItemDaoImpl implements ItemDao {
 20: 
 21: 	/**
 22: 	 * Nah setternya diganti dengan yang satu ini
 23: 	 */
 24: 	@Autowired
 25: 	private DataSource dataSource;
 26: 
 27: 	public void saveItem(String name, String price) {
 28: 		try {
 29: 			Connection connection = dataSource.getConnection();
 30: 
 31: 			String sql = "INSERT INTO item (name, price) VALUES (?, ?)";
 32: 			PreparedStatement statement = connection.prepareStatement(sql);
 33: 			statement.setString(1, name);
 34: 			statement.setString(2, price);
 35: 
 36: 			statement.executeUpdate();
 37: 		} catch (SQLException e) {
 38: 			e.printStackTrace();
 39: 		}
 40: 	}
 41: 
 42: 	public ResultSet getAllItems() {
 43: 		try {
 44: 			Connection connection = dataSource.getConnection();
 45: 
 46: 			ResultSet resultSet = connection.prepareStatement(
 47: 					"SELECT * FROM item").executeQuery();
 48: 
 49: 			return resultSet;
 50: 		} catch (SQLException e) {
 51: 			e.printStackTrace();
 52: 
 53: 			return null;
 54: 		}
 55: 	}
 56: 
 57: }
 58: 

Sudah mulai terlihat bedanya, untuk melakukan injection sudah tidak menggunakan setter lagi, tetapi dengan menggunakan @Autowired, sedangkan untuk pembuatan bean-nya digunakan @Service.

Sekarang tingga; menyuntikkan DAOnya ke controller

  1: package com.mervpolis.dwx.struts2spring.action;
  2: 
  3: import java.sql.Connection;
  4: import java.sql.ResultSet;
  5: import java.util.ArrayList;
  6: import java.util.HashMap;
  7: import java.util.List;
  8: import java.util.Map;
  9: 
 10: import javax.sql.DataSource;
 11: 
 12: import org.apache.struts2.convention.annotation.Action;
 13: import org.apache.struts2.convention.annotation.Result;
 14: import org.apache.struts2.convention.annotation.Results;
 15: import org.springframework.beans.factory.annotation.Autowired;
 16: 
 17: import com.mervpolis.dwx.struts2spring.dao.ItemDao;
 18: import com.mervpolis.dwx.struts2spring.datasource.DataSourceAware;
 19: import com.opensymphony.xwork2.ActionSupport;
 20: 
 21: /**
 22:  * @author Dian Aditya
 23:  *
 24:  */
 25: @Results({ @Result(name = ActionSupport.SUCCESS, type = "velocity", location = "/view/item/item_list.vm") })
 26: public class ItemController extends ActionSupport {
 27: 
 28: 	private List result = new ArrayList();
 29: 	private String id;
 30: 
 31: 	/**
 32: 	 * Inject lagi
 33: 	 */
 34: 	@Autowired
 35: 	private ItemDao itemDao;
 36: 
 37: 	@Action("/item/show")
 38: 	public String show() throws Exception {
 39: 		if (itemDao == null) {
 40: 			addActionError("Gagal menyuntik itemDao");
 41: 		} else {
 42: 			ResultSet resultSet = itemDao.getAllItems();
 43: 			while (resultSet.next()) {
 44: 				Map data = new HashMap();
 45: 				data.put("name", resultSet.getString("name"));
 46: 				data.put("price", resultSet.getString("price"));
 47: 				result.add(data);
 48: 			}
 49: 		}
 50: 
 51: 		return SUCCESS;
 52: 	}
 53: 
 54: 	public String getId() {
 55: 		return id;
 56: 	}
 57: 
 58: 	public void setId(String id) {
 59: 		this.id = id;
 60: 	}
 61: 
 62: 	public List getResult() {
 63: 		return result;
 64: 	}
 65: }
 66: 

Dan coba dijalankan, hasilnya tidak akan jauh beda dari contoh sebelumnya.

 

Sedikit bonus :p berikut contoh tanpa menggunakan anotasi.

  1: <?xml version="1.0" encoding="UTF-8"?>
  2: <beans xmlns="http://www.springframework.org/schema/beans"
  3: 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  4: 	xmlns:p="http://www.springframework.org/schema/p"
  5: 	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  6: 		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  7: 
  8: 	<bean id="dataSource"
  9: 		class="org.springframework.jdbc.datasource.DriverManagerDataSource"
 10: 		p:driverClassName="com.mysql.jdbc.Driver" p:username="root"
 11: 		p:password="admin" p:url="jdbc:mysql://localhost:3306/test" />
 12: 
 13: 	<bean id="itemDao" class="com.mervpolis.dwx.struts2spring.dao.ItemDaoImpl"
 14: 		p:dataSource-ref="dataSource" />
 15: 
 16: </beans>

Atau secara sederhananya mungkin juga seperti ini.

  1: // org.springframework.jdbc.datasource.DriverManagerDataSource
  2: DriverManagerDataSource dataSource = new DriverManagerDataSource();
  3: dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  4: dataSource.setUsername("root");
  5: dataSource.setPassword("admin");
  6: dataSource.setUrl("jdbc:mysql://localhost:3306/test");
  7: 
  8: // javax.sql.DataSource
  9: DataSource source = dataSource;
 10: 
 11: // com.mervpolis.dwx.struts2spring.dao.ItemDaoImpl
 12: ItemDaoImpl daoImpl = new ItemDaoImpl();
 13: daoImpl.setDataSource(source);
 14: 
 15: // com.mervpolis.dwx.struts2spring.dao.ItemDao
 16: ItemDao itemDao = daoImpl;

Cape juga ternyata, selamat menikmati hidangannya.

Meruvian Menyambut Idul Fitri 1431 H

Posted on 01 September 2010 by Dian Aditya

Hari ini merupakan hari ke dua saya di Meruvian Camp Depok dalam rangka kunjungan rutin. Menyenangkan ternyata walaupun saya sempat merasa sebagian dari mereka bakalan terusik dengan selembar checklist yang saya bawa :P Dan mulai dari kemarin malam hingga siang ini, merupakan moment yang cukup menarik menurut saya. Dimulai dari pemilihan kepala suku (setiap bulan ada kepala suku baru yang bertanggung jawab menjaga stabilitas nasional) hingga pagi ini sebelum kegiatan wajib dimulai. Sangat berkesan dimana pagi ini diadakan ritual semacam babat alas, mungkin yang satu ini lebih cocok disebut babat lumut atau mungkin sapu jogan. Apalah namanya, yang jelas ritual ini dilakuakan atas kesadaran semua penduduk Meruvian Depok untuk menyambut Hari kemenangan 1 Syawal 1431 H yang tinggal mengitung hari. Berikut beberapa foto ketika ritual sedang berlangsung.

 

Kepala suku baru sedang memberi contoh bagaimana cara merawat benda keramat yang paling sering dibutuhkan dalam keadaan darurat :D

Senyum itu ibadah lho?.

Ikutan nampang juga (ikutan bantuin maksudnya)

Sikat dan karbol, salah satu senjata yang ampuh untuk membasmi kuman

Dan akhirnya ritual diakhiri dengan pembersihan camp secara menyeluruh

Cukup kagum saya dengan kegiatan tersebut, dan memang inilah pelajaran yang terpenting diluar kompetensi mereka sebagai calon software developer (atau mungkin sudah) yaitu nilai kemandirian dan tanggung jawab terhadap lingkungan. Coding bakalan lebih tenang kalo tempatnya mendukung, betul gak?.