Showing posts with label grails. Show all posts
Showing posts with label grails. Show all posts

30 March 2010

Grails-Security-Encryption

การเข้ารหัส (encryption) คือ การเปลี่ยนข้อความที่สามารถอ่านได้ (plain text) ไปเป็นข้อความที่ไม่สามารถอ่านได้ (cipher text) เพื่อเหตุผลด้านความปลอดภัย

ประโยชน์ของการเข้ารหัส

การเข้ารหัสนั้น นอกจากเป็นการทำให้ข้อมูลถูกสับเปลี่ยนเพื่อไม่ให้ผู้อื่นสามารถเข้าใจ และใช้ประโยชน์จากข้อมูลนั้นได้แล้ว การเข้ารหัสยังมีประโยชน์ในด้านอื่นๆ อีก เช่น สามารถนำมาประยุกต์ใช้ในการตรวจสอบว่าผู้ที่กำลังใช้เครือข่ายคอมพิวเตอร์ หรือทำรายการบนเว็บเพจเป็นผู้ที่เราต้องการติดต่อจริง ไม่ใช่ผู้อื่นที่แอบอ้างเข้ามาใช้ระบบ นอกจากนี้ยังสามารถนำไปใช้เป็นลายเซ็นดิจิตอลในการระบุ หรือยืนยันว่าอีเมล์หรือแฟ้มข้อมูลที่ส่งไปให้ผู้อื่นนั้นมาจากเราจริงๆ ได้อีกด้วย

วิธีการเข้ารหัสมีความสำคัญต่อ 3 ส่วนหลักของระบบการค้าทางอิเล็กทรอนิกส์ คือ  
  • 1. ระบบตรวจสอบว่าเป็นเอกสารจริง (Authentication)
  • 2. การพิสูจน์หลักฐานว่าได้กระทำการรายการจริง (Non-Repudiation)
  • 3. การรักษาสิทธิส่วนตัว (Privacy)

นอกจากนี้การเข้ารหัสยังนำไปใช้ในการตรวจสอบการแสดงตัว (Identification) ซึ่งอยู่ในการทำ Authentication โดยใช้พิสูจน์ว่าคนที่ส่งหรือรับข้อมูลนั้นเป็นบุคคลที่เขาอ้างตัวจริงๆ และยังสามารถตรวจสอบไปอีกขั้นว่าข้อมูลที่ส่งมานั้นได้ถูกดัดแปลงโดยผู้อื่นก่อนถึงมือเราหรือไม่

สำหรับในเรื่องของการพิสูจน์หลักฐานว่าได้กระทำรายการจริง (Non-Repudiation) จะมีความสำคัญอย่างมากต่อการทำรายการทางธุรกิจ เนื่องจากจะใช้เป็นหลักฐานป้องกันการปฏิเสธในภายหลังว่าไม่ได้เป็นผู้ส่ง / รับ แฟ้มข้อมูล หรือไม่ได้ทำรายการทางธุรกิจนั้นๆ >>>http://th.wikipedia.org/wiki/การเข้ารหัส


ศึกษาจากตัวอย่างนะครับ ก่อนอื่นสร้าง User,UserController
  1. grails create-domain-class User แล้วใส่ code ตามนี้

    class User {
    String login
    String password
    String role = "user"
    static constraints = {
    login(blank:false, nullable:false, unique:true)
    password(blank:false, password:true)
    role(inList:["admin", "user"])
    }
    static transients = ['admin']
    boolean isAdmin(){
    return role == "admin"
    }

    def beforeInsert = {
    password = password.encodeAsSHA()
    }

    String toString(){
    login
    }
    }

  2. grails create-controller User แล้วใส่ code ตามนี้

    class UserController {

    def login = {}
    def logout = {
    flash.message = "Goodbye ${session.user.login}"
    session.user = null
    redirect(action:"login")
    }
    def authenticate = {
    def user = User.findByLoginAndPassword(
    params.login, params.password.encodeAsSHA())
    if(user){
    session.user = user
    flash.message = "Hello ${user.login}!"
    redirect(controller:"race", action:"list")
    }else{
    flash.message =
    "Sorry, ${params.login}. Please try again."
    redirect(action:"login")
    }
    }


    static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

    def index = {
    redirect(action: "list", params: params)
    }

    def list = {
    params.max = Math.min(params.max ? params.int('max') : 10, 100)
    [userInstanceList: User.list(params), userInstanceTotal: User.count()]
    }

    def create = {
    def userInstance = new User()
    userInstance.properties = params
    return [userInstance: userInstance]
    }

    def save = {
    def userInstance = new User(params)
    if (userInstance.save(flush: true)) {
    flash.message = "${message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), userInstance.id])}"
    redirect(action: "show", id: userInstance.id)
    }
    else {
    render(view: "create", model: [userInstance: userInstance])
    }
    }

    def show = {
    def userInstance = User.get(params.id)
    if (!userInstance) {
    flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
    redirect(action: "list")
    }
    else {
    [userInstance: userInstance]
    }
    }

    def edit = {
    def userInstance = User.get(params.id)
    if (!userInstance) {
    flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
    redirect(action: "list")
    }
    else {
    return [userInstance: userInstance]
    }
    }

    def update = {
    def userInstance = User.get(params.id)
    if (userInstance) {
    if (params.version) {
    def version = params.version.toLong()
    if (userInstance.version > version) {
    userInstance.errors.rejectValue("version", "default.optimistic.locking.failure", [message(code: 'user.label', default: 'User')] as Object[], "Another user has updated this User while you were editing")
    render(view: "edit", model: [userInstance: userInstance])
    return
    }
    }
    userInstance.properties = params
    if (!userInstance.hasErrors() && userInstance.save(flush: true)) {
    flash.message = "${message(code: 'default.updated.message', args: [message(code: 'user.label', default: 'User'), userInstance.id])}"
    redirect(action: "show", id: userInstance.id)
    }
    else {
    render(view: "edit", model: [userInstance: userInstance])
    }
    }
    else {
    flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
    redirect(action: "list")
    }
    }

    def delete = {
    def userInstance = User.get(params.id)
    if (userInstance) {
    try {
    userInstance.delete(flush: true)
    flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
    redirect(action: "list")
    }
    catch (org.springframework.dao.DataIntegrityViolationException e) {
    flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
    redirect(action: "show", id: params.id)
    }
    }
    else {
    flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
    redirect(action: "list")
    }
    }
    }

  3. สร้างการ encode,decode ใน grails-app/utils ไฟล์ชื่อ UnderscoreCodec.groovy

    class UnderscoreCodec {
    static encode = {target->
    target.replaceAll(" ", "_")
    }
    static decode = {target->
    target.replaceAll("_", " ")
    }
    }

  4. สร้าง encryption ใน path เดียวกัน สร้างไฟล์ชื่อ SHACodec.groovy

    import java.security.MessageDigest
    class SHACodec{
    static encode = {target->
    MessageDigest md = MessageDigest.getInstance('SHA')
    md.update(target.getBytes('UTF-8'))
    return new String(md.digest()).encodeAsBase64()
    }
    }

  5. ทดสอบกันเลย...โดยสร้าง User ใหม่ซัก 1 คน แล้วมาดูกันซิว่า password จะ encrypt หรือไม่
    จากนั้น view ดู

    เรียบร้อย ตอนนี้เราก็สามารถทำ Encryption สำเร็จ

29 March 2010

Grails-Controller

ในการสร้าง controller มีอยู่หลายวิธีด้วยกัน โดยปรกติแล้วจะใช้คำสั่ง
grails create-controller ในการสร้าง controller ให้กับโดเมนของเรา
หรือจะใช้คำสั่ง
grails generate-all คำสั่งนี้จะสร้าง controller และ views ให้ ส่วนใหญ่ถ้าออกแบบเป็นเรื่องเป็นราวเค้าจะไม่ใช้ generate กัน จะสร้างขึ้นมาเอง เพื่อความกระชับของโค้ด

ความเข้าใจ URLs และ Controllers

คำอธิบายก็ดูจากรูปเลยครับเข้าใจได้ง่ายกว่า...
สามารถแก้ไขชื่อ application ได้นะครับ โดยเข้าไปที่ application.properties ใน
root folder ของ RaceTrack application

app.version=0.1
app.name=racetrack
app.servlet.version=2.4
app.grails.version=1.2
plugins.hibernate=1.2
plugins.tommcat=1.2

อยากได้ชื่อไหนก็ใส่ไปไหม่เลยครับ...

24 March 2010

Grails-Getting Data from Database

วันนี้ผมได้ศึกษาการดึงข้อมูลจาก Database มาแสดง ที่ web-application ได้แล้วครับ เพิ่งจะมาถึงบางอ้อ@_@
ใช้ตัวอย่างที่แล้วเรื่อง Database ต่อได้เลยนะครับ เอาหล่ะมาเริ่มกันเลย start xampp เลย...
จากนั้น ให้ไปแก้ไขไฟล์ DataSource.groovy ตามด้านล่างเลยครับ...

environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "update" //ส่วนนี้แก้ให้เป็น update
// NOTE: the JDBC connection string should be
// all on the same line.
url = "jdbc:mysql://localhost:3306/racetrack_dev?autoreconnect=true"
}
}

เหตุผลที่เปลี่ยนเฉพาะส่วนนี้ก็คือ เวลาที่เรา run grails เราจะอยู่ในส่วนของ Development นะครับ ตอนที่เรียก page ก็จะไปทำการ update ข้อมูล โดยดูดมาจาดฐานข้อมุลนั่นเอง...

ทดลองใส่ข้อมูลไว้ใน Database แล้วให้ grails ของเราอ่านข้อมูลมาแสดง มาดูกันสิว่าจะได้หรือไม่...
เพิ่มข้อมูลใน Race
เพิ่มเสร็จแล้ว run grails ขึ้นมา คลิกเข้าไปที่ RaceController

มีข้อมูลโผล่มาจริงๆด้วยแหะ! โอ้วมันจอร์ช จริงๆ

แล้วส่วนการทำงานมันอยู่ที่ไหน..?
อ๊ะแน่นอนครับ ผมก็สงสัยจึงได้ตามไปสืบหาดูว่า code มันอยู่ไหนน้อ.. จนพบครับ code ทำการดึง ข้อมูลและสร้าง page นั้นอยู่ที่../grails-1.2.1/src/grails/templates/scaffolding/list.gsp

เป็น tag ของ html,groovy,etc.. ใช้หลายๆตัว Gen page นั้นขึ้นมาสร้างเป็น row และ column ให้เราเห็นใน action ของ list นั่นเองครับ
เปิด code ดูเอาละกันนะครับ ยาวเกินกว่าที่ผมจะเอามาแสดงให้ดูได้

23 March 2010

Grails-Database

หลังจากที่ได้ลองเล่นดูคร่าวๆ แล้ว วันนี้จะมาเก็บข้อมูลใน Database กัน เก็บอย่างเดียวนะครับ ส่วนการอ่านข้อมูลที่เก็บไว้ออกมาแสดงนั้น ไว้คราวหน้าจะเอามาฝากครับ....(ป่าวหรอก ตอนนี้ยังไม่รู้เลยว่าทำไง อิอิ)

ตัวอย่างนี้ เราจะใช้ ubuntu 9.12 โปรแกรมที่ใช้เป็น xampp ซึ่งมีมาให้อยู่แล้วใน ubuntu ถ้ายังไม่มีกันก็ไปหาวิธีติดตั้งกันเองนะครับ

เข้าโปรแกรม xampp กด start ปุ่มใหญ่เลยครับ เราใช้ทั้งหมด...

เปิด web browser ขึ้นมา พิมพ์ localhost เข้าเมนู phpMyAdmin
จากนั้นเข้าไปสร้าง database ชื่อ racetrack_dev

สร้าง Database แล้ว ต่อไปสร้าง User , Password
คลิกที่ Database racetrack_devเรา เข้าเมนู Privileges > add New User
user : grails
host : localhost
password : grails
จากนั้น ที่ Global privileges เลือก check all เสร็จแล้ว กด GO ที่มุมขวาล่าง..

ต่อไป..โหลด Mysql Driver ไฟล์ชื่อ mysql-connector-java-5.1.xxx-bin.jar
copy มาวางที่ grail-app/lib ....

จากนั้นไปแก้ไขไฟล์ DataSource.groovy ที่ grails-app/conf/DataSource.groovy ดังนี้...

dataSource {
pooled = true
driverClassName = "com.mysql.jdbc.Driver"
username = "grails"
password = "grails"
}
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='net.sf.ehcache.hibernate.EhCacheProvider'
}
// environment specific settings
environments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop','update'
url = "jdbc:mysql://localhost:3306/racetrack_dev?autoreconnect=true"
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost:3306/racetrack_dev?autoreconnect=true"
}
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost:3306/racetrack_dev?autoreconnect=true"
}
}
}

อ่าห้า..ตอนนี้ก็สามารถใช้ Database ได้แล้ว...มาลองใส่ข้อมุลกัน Run-app ขึ้นมาเลย
ใส่ข้อมูลลงไปแล้วดูใน Database ...


มีข้อมูลเก็บใน racetrack_dev แล้ว
การทดลองนี้สอนให้รู้ว่า "ไม่รู้อย่าชี้" ....

22 March 2010

Grails-Relationships

Relationship คือ ความสัมพันธ์ ในทาง Database ความสัมพันธ์มีอยู่ด้วยกัน 3 แบบ คือ 1:1 , 1:N , M:N

Creating a One-to-Many Relationship
การสร้างความสัมพันธ์แบบ 1:N
ตัวอย่างนี้ จะสร้างความสัมพันธ์ระหว่าง Race กับ Registration โดย การแข่ง 1 รายการ สามารถมีผู้ลงทะเบียนแข่งขัน ได้หลายคน
ในไฟล์ Race.groovy เปิดไฟล์ และใส่ code เพิ่มไปจากเดิม 1 บรรทัด ตามนี้...

class Race {
//...............
static hasMany = [registrations:Registration]
String toString(){ return "${name},${startDate.format('MM/dd/yyyy')}" }
}
registrations คือ ชื่อ property ที่แสดงหน้าเว็บ
Registration คือ ชื่อ class
toString ใช้แสดงรายละเอียดของ class ในตัวอย่างนี้เราจะให้แสดง ชื่อการแข่งและวันที่แข่ง
สร้างที่ class Race แล้วทีนี้ก็ไปสร้างที่ class Registration บ้างดังนี้...
ใส่เพิ่มไปอีก 1 บรรทัดเช่นกัน

class Registration{
//........
static belongsTo = [race:Race]
}
race คือ ชื่อ property ที่แสดงหน้าเว็บส่วนของ Registration
Race คือ ชือ class Race ทีมีความสัมพันธ์ด้วยนั่นเอง

Run applications แล้ว กรอกข้อมูลในส่วน Race และ Registration

ตรงช่อง registrations ยังว่างอยู่...อย่าเพิ่งสนใจ ต่อไปกรอกข้อมูลส่วน Registration....


ในส่วน Registration มี Race ขึ้นมาให้เลือกแล้ว เราก็เลือก"แข่งวิ่งควาย"
จากนั้นไปกดดู race จะเห็นว่า มี Registration มา 1 คนแล้ว

---------------------------------------------------------------
Creating a Many-to-Many Relationship
การสร้างความสัมพันธ์แบบ M:N
ตัวอย่าง:
เพิ่ม class Runner พิมพ์ grails create-domain-class Runner เพิ่ม code ตามนี้เลย...
class Runner {

static constraints = {
firstName(blank:false)
lastName(blank:false)
dateOfBirth()
gender(inList:["M","F"])
address()
city()
stage()
zipcode()
email(email:true)
}
static hasMany=[registrations:Registration]
String firstName
String lastName
Date dateOfBirth
String gender
String address
String city
String Stage
String zipcode
String email

String toString(){"${lastName},$firstName (${email})"}
}
แก้ไขไฟล์ Registration ตามนี้...
class Registration {
static constraints = {
race()
runner()
paid()
dateCreate()
}
static belongsTo = [race:Race,runner:Runner]
boolean paid
Date dateCreate
}

สร้างไฟล์ controller ของ Runner พิมพ์ grails create-controller Runner
แก้ไขดังนี้...
class RunnerController {

def scaffold = true
}


เพิ่มข้อมูล....



ตอนนี้ก็คงพอจะเข้าใจกันแล้วนะครับ...
grails and groovy ทำให้ชีวิตง่ายขึ้นจริงๆ ^_^

21 March 2010

Grails-Validation


Validation คือ การตรวจสอบ
แล้วจะตรวจสอบไปทำไม ?
แน่นอนครับ web-app ที่เราสร้างขึ้นมา ต้องมีการป้องกัน user กรอกข้อมูลผิด หรือไม่ถูกต้องตามรูปแบบที่เรากำหนด หรือ กรอกข้อมูลยาวเกินไป ถ้าไม่มีการตรวจสอบ ข้อมูลก็จะถูกเก็บลงฐานข้อมูลแบบผิดๆ หรือเก็บไม่ได้เนื่องจาก ข้อมูลที่กรอกมีขนาดใหญ่เกินกว่าจะเก็บได้ ก็ทำให้ข้อมูลผิดพลาดอีก..
เมื่อผู้ใช้กรอกค่าเสร็จและกดตงลง ข้อมูลที่กรอกจะจะส่งไปที่ server แล้ว server จะทำการตรวจสอบ error หากพบ จะส่ง error message กลับมาบอกว่า ส่วนไหน error อย่างไร
เราก็ต้องกำหนดข้อจำกัดลงไปในไฟล์ application(.groovy) ของเราที่อยู่ใน folder domain ...

รู้จักกับข้อจำกัด ซึ่งมีดังนี้...
  1. blank,nullable
    การใช้ : blank:true,nullable:true
    อธิบาย : ใช้เพื่อตรวจสอบว่ามีการเว้นว่างช่องกรอกข้อมูลไว้หรือไม่ ถ้ามีจะแจ้ง error

  2. creditCard
    การใช้ : creditCard:true
    อธิบาย : ใช้เพื่อตรวจสอบรูปแบบของเลข creditCard

  3. display
    การใช้ : display:false
    อธิบาย : hide the field in create.gsp and edit.gsp.

  4. email
    การใช้ : email:true
    อธิบาย : ตรวจสอบรูปแบบของ email

  5. password
    การใช้ : password:true
    อธิบาย : เมื่อกรอกข้อมูล เวลาที่แสดงจะถูกแปลงเป็น ***** เพื่อป้องกันบุคคลอื่นเห็น

  6. inList
    การใช้ : inList:["A","B","C"]
    อธิบาย : สร้าง combo box มีข้อมูลใน list คือ A,B,C

  7. matches
    การใช้ : matches:"[a-zA-Z]+"
    อธิบาย : ตัวอักษรที่ให้ใช้ ถ้าไม่ตรงก็จะแจ้ง error ตัวอย่างนี้ ให้ใช้อักษรอังกฤษ a-z,A-Z เท่านั้น ถ้าเป็นอย่างอื่นจะแจ้ง error

  8. min,max
    การใช้ : min:0,max:100----min:0.0,max:100.0
    อธิบาย : ใช้กำหนดค่าต่ำสุด สูงสุด min,maxนี้ ใช้กับตัวเลข

  9. minSize,maxSize,size
    การใช้ : minSize:0,maxSize:30,size:0..30
    อธิบาย : ใช้กำหนดจำนวนของ ตัวอักษร

  10. notEqual
    การใช้ : notEqual:"FOO"
    อธิบาย : ใช้กำหนดไม่ให้ซ้ำกับคำที่เราต้องการ

  11. range
    การใช้ : range:0..100
    อธิบาย : สร้าง combo box ให้เลือก ตั้งแต่ 0 ถึง 100

  12. scale
    การใช้ : scale:2
    อธิบาย : กำหนดจุดทศนิยมของตัวเลข

  13. unique
    การใช้ : unique:true
    อธิบาย : ตรวจสอบว่าซ้ำกันใน Database ไหม เช่น ใช้ตรวจสอบ user ID ที่ใช้สมัคร

  14. url
    การใช้ : url:true
    อธิบาย : ทำให้แน่ในว่าค่าที่กรอกเป็น รูปแบบของ url

  15. validator
    การใช้ : validator:{return(it%2)==0}
    อธิบาย : ใ้ช้กำหนด validation ตามแบบของคุณเอง

วิธีการใช้ข้อจำกัด
ตอนนี้เราก็รู้จักแล้วว่าสามารถตรวจสอบ หรือ ใส่ข้อกำหนดแบบไหนได้บ้าง มาดู code ตัวอย่างกัน..
-------------------------------------------------
class Race {
//ส่วนที่เราจะเชคก็ให้เอามาใส่ไว้ใน constraints แบบนี้...
static constraints = {
name(blank:false,maxSize:20)
startDate(validator: {return(it > new Date())})
city()
stage(inList:["GA", "NC", "SC"])
distance(min:0.0)
cost(min:0.0,max:100.0)
maxRunners(min:0,max:100000)
}

String name
Date startDate
String city
String stage
BigDecimal distance
BigDecimal cost
Integer maxRunners = 100000

BigDecimal inMiles(){ return distance*0.6214 }
static hasMany = [registrations:Registration,locations:Location,sponsors:Company]

}
-------------------------------------------------

เราก็จะได้แล้วสิ่งที่เราได้ทำลงไป...
ทีนี้ลอง กรอกข้อมูลเล่นๆ ดูกันแบบนี้ แล้วกด create
จะเห็นว่า error message เป็น default..

Changing Error Messages การเปลี่ยนข้อความ error
จะอยู่ใน /...grails-app/i18n/messages.properties ใส่เพิ่มไปตามนี้เลย...
หรือ จะใส่ข้อความ error เป็นภาษาใดก็ได้นะครับ ใส่หลังเครื่องหมาย =

race.name.blank=plsese provide a Name for this Race
race.name.maxSize.exceeded=Sorry, but a Race Name can't be more than {3} letter
race.distance.min.notmet=A Distance of {2}? What are u trying to do, run backwards?
race.maxRunners.min.notmet=Max Runer must be more than {3}
race.maxRunners.max.exceeded=Max Runer must be less than {3}
race.cost.min.notmet=Cost must be more than {3}
race.cost.max.exceeded=Cost must be less than {3}
race.startDate.validator.invalid=sorry, but the past is the past.
-------------------------------------------------
{0} คือ ชื่อ property เช่น name
{1} คือ ชื่อ class เช่น Race
{2} คือ ค่าจากช่องกรอก
{3} to {4} คือ ช่วง เช่น 0 to 10

เราอยากจะให้แสดงตรงไหนก็ใส่ไป

เสร็จแล้ว save ลองแบบเดิมอีกครั้ง...
จะเห็นว่าข้อความได้เปลี่ยนไปตามที่เรากำหนดแล้ว...
A Haa! มันช่างง่ายดายจริงๆ ใช่ไหมหละครับ ถ้าต้องตรวจสอบแบบนี้ ถ้าไม้ใช่ Grails นี่ยากอยู่น้า...

20 March 2010

Installing & Creating a Grails in linux,ubuntu

สิ่งที่ต้องเตรียม มีดังนี้
- JDK 1.4 ขึ้นไปครับ สามารถ download ได้จาก http://java.sun.com
- Grails สามารถ download ได้ที่นี่ http://www.grails.org/Download หรือต้องการติดตั้งเป็น exe สำหรับ windows สามารถ download ได้จากที่นี่ http://72.249.85.178/files/grails-1.0.3-win_setup.exe
จากนั้น แตกไฟล์ ไว้ในส่วนที่คุณต้องการ

set path
ใน home คุณ เปิดไฟล์ชื่อ .bashrc เพิ่มลงไปในส่วนท้ายของไฟล์
  • export GRAILS_HOME=${HOME}/grails-1.2.1
  • export PATH=${GRAILS_HOME}/bin:${PATH}
  • export JAVA_HOME GRAILS_HOME PATH
เพียงเท่านี้ก็ติดตั้ง Grails เสร็จแล้ว(ง่ายจัง)

ทดลองสร้าง wep-app ของเราง่ายๆ
เข้าไป folder ของ grails ที่ได้แตกไฟล์ไว้ คลิกขวา Open in Terminal
  • สร้าง folder เป็นที่เก็บ web ของคุณ
    mkdir web
    cd web
  • สร้าง Application
    grails create-app (ชื่อapplication)
    grails create-app racetrack
    ตัวอย่างนี้จะสร้าง app ชื่อ racetrack
  • Run-app
    cd racetrack
    grails run-app
  • ทดสอบ
    เข้า web browser ของคุณ พิมพ์ localhost:8080/racetrack
ตอนนี้ก็จะได้หน้าเว็บแล้วแบบง่ายๆแล้ว