Natty’s blog

Stay hungry. Stay foolish. — Steve Jobs

Archive for the ‘grails’ Category

[grails] WebAlbum: ตอนที่ 2 จบ domain class

Posted by natty on September 22, 2008

จาก ตอนที่ 1 เราแค่บอกว่าเราจะทำ domain class อะไรบ้าง แต่ก็เขียนไปแค่อันเดียว blog นี้เราจะเขียน domain class ที่เหลือให้หมดเลย หลักๆ จะอิงจาก tutorial เพราะจะได้เรียนรู้ไปในตัว

ครั้งที่แล้วมี User ไปแล้ว คราวนี้ก็เหลือ Album, Picture, Image

มาที่ Album กันก่อน

class Album implements Comparable {
    User user
    String caption
    String description
    SortedSet pictures
    Integer picturesCount = 0
    Date dateCreated = new Date()
    Date lastUpdated = new Date()

    static belongsTo = User
    static hasMany = [ pictures : Picture ]

    static optionals = [ 'description' ]

    static constraints = {
        caption(size: 1..40, blank: false)
        description()
    }

    int compareTo(obj) {
        obj.id.compareTo(id)
    }
} 

การ implement interface comparable คือเพื่อจะทำให้ object ภายใน Class Album สามารถ sort ได้ compare ได้ เนื่องจากเป็นลิสต์ของ album

static belongsTo = User
static hasMany = [ pictures : Picture ]

ตัวแปร belongsTo บอกว่า Album มีความสัมพันธ์กับ User แปลง่ายๆ ว่า Album ขึ้นกับ User เป็นความสัมพันธ์อีกด้านหนึ่ง และ Album ก็มีหลาย pictures จากตัวแปร hasMany

int compareTo(obj) {
        obj.id.compareTo(id)
    }

ด้านบนเป็น method เอาไว้ compare object ด้วยการใช้ id

ต่อมาก็เป็น Picture.groovy

class Picture implements Comparable {</pre>
User user
 Album album
 SortedSet images
 String file
 Integer operation
 String caption
 String description
 String contentType
 Integer width
 Integer height
 Date dateCreated = new Date()
 Date lastUpdated = new Date()
 Boolean confirmDelete

 static belongsTo = [ User, Album ]
 static hasMany = [ images : Image ]

 static optionals = [ 'caption', 'description' ]

 static transients = [ 'file', 'operation', 'confirmDelete' ]

 static constraints = {
 caption(size: 0..40)
 description()
 }

 static mapping = {
 images cascade: 'all-delete-orphan', inverse: true
 description type: 'text'
 user index: 'pictures_user_index', unique: false
 album index: 'pictures_album_index', unique: false
 }

 static final Integer NoOp = 0
 static final Integer RotateClockWise90 = 1
 static final Integer RotateAntiClockWise90 = 2
 static final Integer Rotate180 = 3
 static final Integer Flip = 4
 static final Integer Flop = 5

 int compareTo(obj) {
 obj.id.compareTo(id)
 }
}

ซึ่งหน้าตาก็คล้ายๆ กับ domain class อื่นๆ แต่มีส่วนที่ต่างคือส่วนที่เกี่ยวกับการ mapping และการประกาศ final variable

static mapping = {
        images cascade: 'all-delete-orphan', inverse: true
        description type: 'text'
        user index: 'pictures_user_index', unique: false
        album index: 'pictures_album_index', unique: false
    } 

ตรงนี้เป็นเรื่องของ GORM เกี่ยวกับ mapping DSL คือตั้งแต่ grails version 1.0 มาแล้วนั้น domain class สามารถถูก map เป็น schema อื่นๆ ได้โดยผ่าน ORM DSL เช่น เราอาจจะเปลี่ยนชื่อ table name ชื่อ column เรา enable caching ให้กับ mapping closure ได้ด้วย

image cascade น่าจะเป็นการกำหนด cascade ให้กับ image ของ picture object นี้ ให้เป็น all-delete-orphan และให้ inverse ได้ มี description ชนิด text มีการทำ index ไปที่ user และ album ที่เกี่ยวกับกับ picture นี้ ([variable] index)

เพิ่งแอบเห็น พี่ชาญวิทย์แปลเรื่อง mapping ไว้ให้แล้ว อ่านง่ายดี ภาษาเฉพาะทางสำหรับ mapping ใน GORM (ตอน 1)

ต่อไปก็เป็น Class Image ไม่ต้องอธิบายอะไรกันมากแล้ว คล้ายๆ กับที่ผ่านมา

class Image implements Comparable {
    User user
    Picture picture
    Integer size
    byte[] data
    String contentType
    Integer width
    Integer height
    Date dateCreated = new Date()
    Date lastUpdated = new Date()

    static belongsTo = [ User, Picture ]

    static mapping = {
        picture index: 'images_index', unique: true
        size index: 'images_index', unique: true
        data type: 'binary'
    }

    static constraints = {
        data(maxSize: MAX_SIZE)
    }

    static final Integer MAX_SIZE = 10 * 1024 * 1024

    static final Integer Original = 1
    static final Integer Large = 2
    static final Integer Medium = 3
    static final Integer Small = 4

    static final Integer[] Widths =  [ 0, 0, 500, 250, 100 ]
    static final Integer[] Heights = [ 0, 0, 500, 250, 100 ]

    static final String[] Names = [ '', 'Original', 'Large', 'Medium', 'Small' ]

    int compareTo(obj) {
        size.compareTo(obj.size)
    }

    String filename() {
        Image.filename(picture.id, size)
    }

    static String filename(long id, int size) {
        if (size == Original) {
            return "${id}-${Names[size]}.jpg"
        }
        else {
            return "${id}-${Names[size]}.png"
        }
    }
} 

ผ่านมา 2 ตอนแล้วไม่ได้รันซะที (ฮา) พยายามต่ออีกนิด มา generate controller และ view ให้กับ domain class ของเรากันดีกว่า เราจะใช้คำสั่ง grails generate-all กับ User, Album, Picture ส่วนกับ Image ไม่ต้อง เพราะมันจะเป็นแค่รูปๆ ที่แสดงขึ้นมา

grails generate-all User

หลังจากนั้นไปปรับไฟล์ grails-app/conf/DataSource.groovy นิดหน่อย เพื่อให้เก็บ HSQLDB เป็นไฟล์ใน db/devDB

eenvironments {
	development {
		dataSource {
			dbCreate = "update" // one of 'create', 'create-drop','update'
			url = "jdbc:hsqldb:file:db/devDB"
		}
	}

การเปลี่ยน url เพื่อเข้าใช้งาน อันนี้จะทำหรือไม่ทำก็ได้ หากเราไม่อยากเข้าผ่าน http://localhost:8080/WebAlbum แต่อยากเข้าผ่าน http://localhost:8080/natty อะไรแบบนี้ ก็ให้เพิ่ม web-jetty.xml

<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
  "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
  <Set name="contextPath">/</Set>
</Configure>

เฮ้อ เรื่องเยอะ กว่าจะได้รัน ซัดเลยจ้ะ grails run-app แล้วลองเข้าไปเยี่ยมเยียนดูซิ เรากำลังได้ application แล้ว

Posted in grails | Leave a Comment »

[grails] WebAlbum: ตอนที่ 1

Posted by natty on September 17, 2008

หลังจากที่พยายามจะทำ WebAlbum ให้เสร็จ แต่สรุปว่าก็ยังไม่เสร็จจนได้ ต้องกลับไปเริ่มที่ ลง plugin eclipse ก่อน – -”

แต่ก็ได้อะไรมาไม่มากก็น้อย เก็บบันทึกไว้ก่อนแล้วกัน

พยายามจะสร้าง WebAlbum ตาม tutorial โดยมี domain class ทั้งหมดคือ User, Album, Picture, Image โดยมีรายละเอียดดังนี้


class User {
    String name
    String motto
    String salt
    String password
    String passwordConfirmation
    SortedSet albums
    SortedSet pictures
    Integer albumsCount = 0
    Integer picturesCount = 0
    Date dateCreated = new Date()
    Date lastUpdated = new Date()

    static hasMany = [albums: Album, pictures: Picture]
    static transients = ['passwordConfirmation']
    static constraints = {
    name(size: 1..40, blank: false, unique: true)
    motto(size: 0..80, nullable: true)
    salt(maxSize: 40, blank: false, nullable: false)
    }

} 

สำหรับ class user อธิบายได้ว่า มี properties ต่างๆ เช่น name, motto…

property ที่เป็น date เมื่อ new date(); ขึ้นมา จะทำให้เกิดเป็น drop down ของวันที่ให้ในหน้า page

 static hasMany = [albums: Album, pictures: Picture]

hasMany คือตัวแปรที่บอกว่า มีความสัมพันธ์กับแบบ one to many คือ user มีได้หลาย Albums และหลาย Pictures

static transients = ['passwordConfirmation']

transient คือตัวแปรที่บอกว่า จะไม่ถูก persist ลง database

name(size: 1..40, blank: false, unique: true)
motto(size: 0..80, nullable: true)
salt(maxSize: 40, blank: false, nullable: false)

เป็นการกำหนดค่าให้กับ properties ของเราว่าจะแสดงอย่างไร เช่น สำหรับ name ให้มีขนาดไม่เกิน 40 characters ห้ามเป็นค่าว่าง และต้องเป็น unique ด้วย

โดย User page สำหรับ input จะหน้าตาดีประมาณนี้เลย

วันนี้พอแค่นี้ก่อน หิวข้าวแล้ว และขอไปลง plugin ให้สำเร็จก่อน ปวดตาเหลือเกินแลัวกับ edit plus ตอนต่อไปค่อยมาต่อ domain class อื่นๆ กัน ยาวเกินไปเดี๋ยวคนอ่านจะขี้เกียจอ่าน (ฮา ข้ออ้าง)

ท่าทางจะอีกยาวไกลกับ WebAlbum on grails…

Posted in grails | Leave a Comment »

Grails บน Windows ภาคสอง (simple domain class + controller)

Posted by natty on September 15, 2008

เฮ้อ เขียน blog แล้วรู้สึกผิด สัญญากับพี่แซนด์ว่าจะดู application ใน OFBiz ให้ แล้วไหงหนูมาบ้า grails อยู่ตรงนี้ – -”

ต่อๆ …

ก็ต่อจากคราวที่แล้วที่สร้าง application ไปแล้ว ก็ยังคงอ่าน quick start ต่อ มาถึงเรื่อง Datasource configuration ซึ่งดูไปดูมาก็เหมือนใน rails ที่เราจะมี standard environment หลังจากที่เราทำการสร้างแอพขึ้นมา (Development, TestData, and Production) โดยมันจะอยู่ในไฟล์ DataSource.groovy และโดย default แล้วมันก็จะใช้ HSQLDB เหมาะสำหรับการ test

และก็ลอง create domain class โดยการใช้คำสั่ง

cd my-project
grails create-domain-class

มันจะ prompt ให้เราใส่ชื่อ domain class เก๋ก็ใส่ Book มันก็จะ create Book.groovy มาให้ใน grails-app/domain ก็คือทำตามที่เค้าว่าทุกอย่าง

Note1: อย่าตั้งชื่อให้เหมือนคำที่เป็น keyword ใน database เช่น ชื่อ Group
Note2: หากตั้งชื่อเป็นตัวใหญ่นำหน้า 2 ตัวติดกัน จะทำให้เกิด error บนหน้า page แต่ตั้งเป็น MyCar แบบนี้อ่ะได้ มันไม่ติดกัน

Domain class เป็น persistent artifact สำหรับ persist ลง database ซึ่งมันก็คือ GORM นั่นเอง คราวนี้เราลองมาใส่ field ใน Book.groovy ของเรา

class Book {
	String title
	String author
}

ก่อนจะใส่ title กับ author เราจะเห็นแค่ class Book ตั้งอยู่เปล่าๆ ใน Book.groovy เท่านั้น
และเราก็มาสร้าง Test data กัน โดยที่ง่ายที่สุดให้ไปดูที่ <..>/grails-app/conf/BootStrap.groovy แล้วสร้างไว้ใน init

class BootStrap {

     def init = { servletContext ->
     // Create some test data
        new Book(author:"Stephen King",title:"The Shining").save()
        new Book(author:"James Patterson",title:"Along Came a Spider").save()
     }
     def destroy = {
     }
} 

สร้าง Controller

เค้าบอกว่า controller เนี่ยเป็นตัวกลางของ Grails applications ที่ควบคุม web requests และ URLS ของ request map ไปสู่ controller class และ closure ภายใน class ซึ่งก็เหมือนกันบ rails อีก

ให้เรารันคำสั่ง grails create-controller และพิมพ์ชื่อของ controller เข้าไป เช่นหากเราใส่ชื่อ Book มันก็จะได้ BookController.groovy แล้วเราก็จะเปลี่ยนให้มันใช้ dynamic scaffold ซึ่งจะ gen application ให้เราตอน runtime (คือถ้าไม่ทำเป็น dynamic เราก็สามารถ scaffold แบบ manual ได้เช่นกัน โดยใช้คำสั่ง grails generate-all ซึ่งมันจะไม่ replace default scaffolding ให้) โดยเราจะทำดังนี้ แต่ต้องแน่ใจว่า Book ต้องขึ้นต้นด้วย B ใหญ่

class BookController {
	def scaffold = Book
}

สตาร์ท Grails

เริ่มงาน app ของเรา โดยใช้คำสั่ง

grails run-app

มันจะ start ใน Jetty servlet ที่พอร์ต 8080 หากอยาก start ใน พอร์ตอื่นให้ใช้คำสั่ง grails -Dserver.port = 9090 run-app และหากอยากดูลิสต์ของหนังสือที่เราสร้างขึ้น ก็เข้าที่

http://localhost:8080/my-project/book/list

เค้าว่ากันว่ามันจะช้าใน development mode กว่าจะไปแต่ละ page ก็ใช้เวลาหลายนาที หลังจากนี้เราอาจจะเพิ่ม maximum heap size โดย set ที่ {{JAVA_OPTS}} ที่ตัวแปร ‘-Xmx512m’ เพื่อให้ maximum heap เป็น 512

วูปี้ๆ สำเร็จ โหย หน้าตามันดีกว่า rails เยอะแยะมากมายจริงๆ เล้ยยยยยย

อีกลิงค์น่าสนใจของ Grails

Posted in grails | 1 Comment »

Natty กับ Grails บน Windows (ภาคแรก: grails create-app)

Posted by natty on September 13, 2008

วันนี้หนู natty จะเริ่มใช้ grails แล้วนะคะ

ตะกี้ไปโหลดมาจาก ที่นี่ โดยเป็นแบบ Windows installer และทำการ install เสร็จแล้ว
ตอนนี้กำลังทำตาม ลิงค์นี้ เพื่อเริ่มต้นการใช้งาน grails แบบขั้นพื้นฐานโคดๆ
เค้าบอกว่าให้ set HOME ให้กับ grails เก๋ก็ set ไว้ที่ C:\grails-1.0.3 แล้วเค้าก็บอกให้ set HOME ให้ java ถ้ายังไม่มี แต่ของเก๋มีแล้วเลยข้ามขั้นตอนนี้ไป แล้วก็เพิ่มที่ PATH เป็น %GRAILS_HOME%\bin ก็เหมือนๆ กับการ set Path Java แหละนะ

แล้วเค้าก็จะให้เริ่มใช้งานแล้วล่ะ ให้ไป ลิงค์นี้

ด้วยความที่ใช้ Windows ก็เข้าไปที่ grails>grails environment
แล้วก็พิมพ์คำสั่ง grails create-app แล้วเค้าก็บอกว่า ใส่ project name ด้วย เก๋ก็เลยใส่ไปเป็น TestProject จากนั้น app ก็โดน create

แงๆ จบแค่นี้ก่อน ต้องไปธุระแล้ว

Posted in grails | 1 Comment »