Rabu, 14 Oktober 2009

Belajar Grails (bagian kedua)

Pada bagian sebelumnya, kita telah selesai menginstalasi software yang di perlukan untuk menjalankan Grails. Pada bagian kedua ini, kita akan mulai belajar membuat aplikasi sederhana menggunakan Grails.

Misalnya kita akan membuat sebuah aplikasi untuk merekam daftar teman-teman kita. Dengan data-data yang akan di masukkan berupa nama, alamat, nomor telpon, nomor handphone, tanggal lahir. Struktur data yang akan di buat adalah sebagai berikut:

Daftar Teman
  1. nama: alphanumerik dengan panjang maksimal 40 karakter.
  2. alamat: alphanumerik dengan panjang maksimal 80 karakter.
  3. nomor telpon: numerik dengan panjang maksimal 20 karakter.
  4. nomor handphone: numerik dengan panjang maksimal 20 karakter.
  5. tanggal lahir: date.
Sekarang marilah kita mulai membuat aplikasi. Buka konsol (*nix) atau command prompt (Windows). Sebaiknya anda berada dalam sebuah folder/direktori yang di khususkan untuk pemrograman. Misalnya folder/direktori program. Kemudian ketikkan perintah berikut:
>grails create-app teman
Welcome to Grails 1.1.1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: c:\grails

Base Directory: C:\source
Running script c:\grails\scripts\CreateApp_.groovy
Environment set to development
    [mkdir] Created dir: C:\source\teman\src
    [mkdir] Created dir: C:\source\teman\src\java
    [mkdir] Created dir: C:\source\teman\src\groovy
    [mkdir] Created dir: C:\source\teman\grails-app
    [mkdir] Created dir: C:\source\teman\grails-app\controllers
    [mkdir] Created dir: C:\source\teman\grails-app\services
    [mkdir] Created dir: C:\source\teman\grails-app\domain
    [mkdir] Created dir: C:\source\teman\grails-app\taglib
    [mkdir] Created dir: C:\source\teman\grails-app\utils
    [mkdir] Created dir: C:\source\teman\grails-app\views
    [mkdir] Created dir: C:\source\teman\grails-app\views\layouts
    [mkdir] Created dir: C:\source\teman\grails-app\i18n
    [mkdir] Created dir: C:\source\teman\grails-app\conf
    [mkdir] Created dir: C:\source\teman\test
    [mkdir] Created dir: C:\source\teman\test\unit
    [mkdir] Created dir: C:\source\teman\test\integration
    [mkdir] Created dir: C:\source\teman\scripts
    [mkdir] Created dir: C:\source\teman\web-app
    [mkdir] Created dir: C:\source\teman\web-app\js
    [mkdir] Created dir: C:\source\teman\web-app\css
    [mkdir] Created dir: C:\source\teman\web-app\images
    [mkdir] Created dir: C:\source\teman\web-app\META-INF
    [mkdir] Created dir: C:\source\teman\lib
    [mkdir] Created dir: C:\source\teman\grails-app\conf\spring
    [mkdir] Created dir: C:\source\teman\grails-app\conf\hibernate
[propertyfile] Creating new property file: C:\source\teman\application.properties
     [copy] Copying 1 resource to C:\source\teman
    [unjar] Expanding: C:\source\teman\grails-shared-files.jar into C:\source\teman
   [delete] Deleting: C:\source\teman\grails-shared-files.jar
     [copy] Copying 1 resource to C:\source\teman
    [unjar] Expanding: C:\source\teman\grails-app-files.jar into C:\source\teman

   [delete] Deleting: C:\source\teman\grails-app-files.jar
     [move] Moving 1 file to C:\source\teman
     [move] Moving 1 file to C:\source\teman
     [move] Moving 1 file to C:\source\teman
Installing plug-in hibernate-1.1.1
    [mkdir] Created dir: C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\plugins\hibernate-1.1.1
    [unzip] Expanding: C:\Documents and Settings\Oz\.grails\1.1.1\plugins\grails-hibernate-1.1.1.zip into C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\plugins\hibernate-1.1.1
Executing hibernate-1.1.1 plugin post-install script ...
Plugin hibernate-1.1.1 installed
Created Grails Application at C:\source/teman
Perintah di atas akan membuat sebuah folder/direktori baru di mana kita akan bekerja didalamnya. Struktur folder/direktori yang di hasilkan seperti berikut:
├───.settings
├───grails-app
│   ├───conf
│   │   ├───hibernate
│   │   └───spring
│   ├───controllers
│   ├───domain
│   ├───i18n
│   ├───services
│   ├───taglib
│   ├───utils
│   └───views
│       └───layouts
├───lib
├───scripts
├───src
│   ├───groovy
│   └───java
├───test
│   ├───integration
│   └───unit
└───web-app
    ├───css
    ├───images
    │   └───skin
    ├───js
    │   └───prototype
    ├───META-INF
    └───WEB-INF
        └───tld
Sekarang kita bahas secara singkat struktur folder/direktori di atas.
  • grails-app: folder/direktori adalah tempat kode program (Groovy) yang merupakan inti dari aplikasi yang kita buat.
    • conf: disini file-file konfigurasi aplikasi kita di letakkan.
    • controllers: di sini kita letakkan file-file yang berkaitan dengan proses bisnis aplikasi kita.
    • domain: file-file yang berkaitan dengan definisi tabel-tabel di database ada disini.
    • i18n: untuk internasionalisasi aplikasi kita.
    • services: jika aplikasi yang dibuat membutuhkan web service, disinilah tempatnya.
    • views: disini file-file yang digunakan menampilkan data-data dan hasil dari proses bisnis.
  • lib: jika anda ingin menambahkan pustaka lain, maka letakkan di sini.
  • src: di dalam folder/direktori ini anda bisa menambahkan file-file Java atau Groovy yang diperlukan oleh aplikasi anda.
  • web-app: disini tempat file-file html, javascript, css dan gambar untuk aplikasi anda.
    • css: folder/tempat file css anda.
    • images: folder/direktori tempat file gambar anda.
    • js: folder/direkrori tempat file JavaScript anda.
Masuk ke dalam folder/direktori teman. Kemudian ketik perintah berikut:
teman>grails run-app
Welcome to Grails 1.1.1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: c:\grails

Base Directory: C:\source\teman
Running script c:\grails\scripts\RunApp.groovy
Environment set to development
    [mkdir] Created dir: C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\classes
  [groovyc] Compiling 6 source files to C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\classes
    [mkdir] Created dir: C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\resources\grails-app\i18n
[native2ascii] Converting 11 files from C:\source\teman\grails-app\i18n to C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\resources\grails-app\i18n
     [copy] Copying 1 file to C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\classes
     [copy] Copied 2 empty directories to 2 empty directories under C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\resources
Running Grails application..
Server running. Browse to http://localhost:8080/teman
Buka browser favorit anda dan masukkan alamat [http://localhost:8080/teman]. Jika tidak ada kesalahan, maka akan tampil seperti berikut:
grails02-01
Mungkin diantara anda ada yang bertanya, 'aplikasi belum dibuat kok sudah bisa di jalankan?'. Ya, itulah salah satu kelebihan Grails di bandingkan framework MVC lainnya. ;-)

Nah, sekarang mari kita mulai melengkapi aplikasi kita dengan membuat sebuah kelas domain (atau model dalam definisi MVC). Kelas domain yang akan kita buat adalah 'Daftar Teman' sesuai dengan rancangan yang telah kita buat di atas. Tetap di folder/direktori teman, ketikkan perintah berikut:

teman>grails create-domain-class daftarTeman
Welcome to Grails 1.1.1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: c:\grails

Base Directory: C:\source\teman
Running script c:\grails\scripts\CreateDomainClass.groovy
Environment set to development
Created DomainClass for DaftarTeman
Created Tests for DaftarTeman

Perintah diatas akan menghasilkan sebuah file DaftarTeman.groovy di folder/direktori grails-app/domain. Yang isinya seperti berikut:

class DaftarTeman {

    static constraints = {
    }
}
Ubahlah file DaftarTeman.groovy diatas sehingga menjadi seperti:

class DaftarTeman {
    String nama
    String alamat
    String nomorHP
    String nomorTelpon
    Date tanggalLahir

    static constraints = {
        nama(size:0..40, nullable: false)
        alamat(size:0..80, nullable: true)
        nomorHP(size:0..20, nullable: true)
        nomorTelpon(size:0..20, nullable: true)
        tanggalLahir()
    }
    
    String toString() {
        "$nama"
    }
}

Setelah perubahan atas file DaftarTeman.groovy selesai dan telah di simpan, kita kembali ke folder/direktori teman. Kemudian ketik perintah berikut:
teman>grails generate-all daftarTeman
Welcome to Grails 1.1.1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: c:\grails

Base Directory: C:\source\teman
Running script c:\grails\scripts\GenerateAll.groovy
Environment set to development
  [groovyc] Compiling 2 source files to C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\classes
  [groovyc] Compiling 1 source file to C:\Documents and Settings\Oz\.grails\1.1.1\projects\teman\classes
Generating views for domain class DaftarTeman ...
Generating controller for domain class DaftarTeman ...
Finished generation for domain class DaftarTeman

Perintah diatas men-generate file-file untuk views dan controller berdasarkan domain DaftarTeman.groovy. Jika anda buka file-file tersebut, isinya kurang lebih seperti berikut:
DaftarTemanController.groovy
class DaftarTemanController {
    
    def index = { redirect(action:list,params:params) }

    // the delete, save and update actions only accept POST requests
    static allowedMethods = [delete:'POST', save:'POST', update:'POST']

    def list = {
        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
        [ daftarTemanInstanceList: DaftarTeman.list( params ), daftarTemanInstanceTotal: DaftarTeman.count() ]
    }

    def show = {
        def daftarTemanInstance = DaftarTeman.get( params.id )

        if(!daftarTemanInstance) {
            flash.message = "DaftarTeman not found with id ${params.id}"
            redirect(action:list)
        }
        else { return [ daftarTemanInstance : daftarTemanInstance ] }
    }

    def delete = {
        def daftarTemanInstance = DaftarTeman.get( params.id )
        if(daftarTemanInstance) {
            try {
                daftarTemanInstance.delete(flush:true)
                flash.message = "DaftarTeman ${params.id} deleted"
                redirect(action:list)
            }
            catch(org.springframework.dao.DataIntegrityViolationException e) {
                flash.message = "DaftarTeman ${params.id} could not be deleted"
                redirect(action:show,id:params.id)
            }
        }
        else {
            flash.message = "DaftarTeman not found with id ${params.id}"
            redirect(action:list)
        }
    }

    def edit = {
        def daftarTemanInstance = DaftarTeman.get( params.id )

        if(!daftarTemanInstance) {
            flash.message = "DaftarTeman not found with id ${params.id}"
            redirect(action:list)
        }
        else {
            return [ daftarTemanInstance : daftarTemanInstance ]
        }
    }

    def update = {
        def daftarTemanInstance = DaftarTeman.get( params.id )
        if(daftarTemanInstance) {
            if(params.version) {
                def version = params.version.toLong()
                if(daftarTemanInstance.version > version) {
                    
                    daftarTemanInstance.errors.rejectValue("version", "daftarTeman.optimistic.locking.failure", "Another user has updated this DaftarTeman while you were editing.")
                    render(view:'edit',model:[daftarTemanInstance:daftarTemanInstance])
                    return
                }
            }
            daftarTemanInstance.properties = params
            if(!daftarTemanInstance.hasErrors() && daftarTemanInstance.save()) {
                flash.message = "DaftarTeman ${params.id} updated"
                redirect(action:show,id:daftarTemanInstance.id)
            }
            else {
                render(view:'edit',model:[daftarTemanInstance:daftarTemanInstance])
            }
        }
        else {
            flash.message = "DaftarTeman not found with id ${params.id}"
            redirect(action:list)
        }
    }

    def create = {
        def daftarTemanInstance = new DaftarTeman()
        daftarTemanInstance.properties = params
        return ['daftarTemanInstance':daftarTemanInstance]
    }

    def save = {
        def daftarTemanInstance = new DaftarTeman(params)
        if(!daftarTemanInstance.hasErrors() && daftarTemanInstance.save()) {
            flash.message = "DaftarTeman ${daftarTemanInstance.id} created"
            redirect(action:show,id:daftarTemanInstance.id)
        }
        else {
            render(view:'create',model:[daftarTemanInstance:daftarTemanInstance])
        }
    }
}
Dan, pada folder/direktori grails-app/views/daftarTeman akan terdapat beberapa file seperti tampak pada struktur folder/direktori di bawah ini.
|   error.gsp
|   index.gsp
|
+---daftarTeman
|       create.gsp
|       edit.gsp
|       list.gsp
|       show.gsp
|
\---layouts
        main.gsp

Nah, sekarang kita coba jalankan kembali aplikasi kita. Ketik perintah berikut,
teman>grails run-app
Welcome to Grails 1.1.1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: c:\grails

Base Directory: C:\source\teman
Running script c:\grails\scripts\RunApp.groovy
Environment set to development
  [groovyc] Compiling 1 source file to C:\Documents and Settings\Oz\.grails\1.1.
1\projects\teman\classes
Running Grails application..
Server running. Browse to http://localhost:8080/teman
Jika anda buka browser dan memasukkan alamat [http://localhost:8080/teman]maka akan tampak tampilan seperti di bawah ini.

grails02-02

Dan seperti yang anda lihat, ada tambahan baru pada halaman yang kita buka. Jika kita klik [DaftarTemanController] maka akan tampil halaman seperti berikut,

grails02-03

Karena aplikasi kita baru saja di buat maka tidak ada data yang di tampilkan. Sekarang coba kita isi data, klik [New DaftarTeman] maka akan muncul form isian seperti di bawah ini,

grails02-04

Setelah data diisi,

grails02-04a

Dan kita klik [create] maka akan muncul halaman seperti ini,

grails02-04b

Dan jika kita klik [DaftarTeman List] maka akan muncul halaman berikut,

grails02-04c

Nah, sampai di sini dulu tutorial Grails bagian kedua. Pada bagian berikutnya akan kita bahas lebih rinci langkah-langkah di atas. Happy hacking!

6 komentar:

  1. nice info nih,
    tapi gmana cranya supaya ketika di save otomatis ngurangi nilai integer di table lain


    kasus nya seperti ini

    table 1 :
    kamar(nama_kamar,kapasitas,berisi)
    table2 :
    pasien(nama_pasien,nama_kamar,penyakit)

    ketika menginputkan data pasien,otomatis kapasitas ruangan berkurang satu.

    thank's before

    BalasHapus
  2. iya gan kasus ane juga hampir sama kaya yg di atas.....
    cuman ane nambahin data
    gmana tuh....

    BalasHapus
  3. Untuk kasus seperti itu, bisa menggunakan cara sebagai berikut:
    Pada waktu data pasien di simpan, data kamar juga diupdate.
    Contoh:
    def pasienInstance = new Pasien(params)
    if(!pasienInstance.hasErrors() && pasienInstance.save()) {
    def kamar = Kamar.findByNamaKamar(params.namaKamar)
    def kapasitas = kamar.kapasitas - 1
    kamar.kapasitas = kapasitas
    kamar.save()
    flash.message = "Pasien ${pasienInstance.nama} created"
    redirect(action:show,nama:pasienInstance.nama)
    } else {
    render(view:'create',model:[pasienInstance:pasienInstance])
    }

    Kira-kira logikanya seperti diatas.
    Happy coding. :D

    BalasHapus
  4. ane dapet error lagi ni gan

    "Cannot get property 'kapasitas' on null object"

    itu pas mau nyimpen nya

    ini script lengkap ane

    class Pasien {

    static constraints = {

    kode_pasien(blank:false)
    kamar()
    nama(blank:false)
    usia(blank:false,max:120,min:0)
    jenis_kelamin(inList:['LAKI-LAKI','PEREMPUAN'],blank:false)
    alamat(blank:false)
    penyakit(blank:false)
    }
    static searchable = true
    static belongsTo = [kamar:Kamar]
    static hasMany = [transaksi:Transaksi]
    Integer kode_pasien
    String nama
    Integer usia
    String jenis_kelamin
    String alamat
    String penyakit
    String toString(){
    return "${nama}, ( ${kode_pasien} )"
    }
    }










    package rsu

    class Kamar {
    static searchable = true
    static constraints = {
    kode_kamar()
    kelas()
    nama_ruangan()
    kapasitas()
    harga()
    berisi()
    }
    static hasMany = [pasien:Pasien,transaksi:Transaksi]
    Integer kode_kamar
    String kelas
    String nama_ruangan
    Integer kapasitas
    Integer harga
    Integer berisi
    String toString(){
    return "${nama_ruangan}, ( ${kapasitas} - - -${berisi} )"
    }
    }






    package rsu

    class Kamar {
    static searchable = true
    static constraints = {
    kode_kamar()
    kelas()
    nama_ruangan()
    kapasitas()
    harga()
    berisi()
    }
    static hasMany = [pasien:Pasien,transaksi:Transaksi]
    Integer kode_kamar
    String kelas
    String nama_ruangan
    Integer kapasitas
    Integer harga
    Integer berisi
    String toString(){
    return "${nama_ruangan}, ( ${kapasitas} - - -${berisi} )"
    }
    }


    mohon bantuannya .........

    BalasHapus
  5. ditunggu gan balesannya .....

    BalasHapus
  6. Sepertinya field kapasitas belum terisi. BTW, error itu muncul pas mau nyimpen apa?

    BalasHapus