| 時(shí)間:2006-12-26 作者:Harshad Oak 瀏覽次數: 本文關(guān)鍵字:groovy, grails, scripting language, Dev Toolbox, WebLogic Server, Harshad Oak, 腳本語(yǔ)言 |

Java Web應用程序框架是企業(yè)Java得以成功的重要原因之一。人們懷疑如果沒(méi)有Apache Struts框架JavaEE是否能夠如此成功。雖然底層編程語(yǔ)言很重要,但通常是框架使編程語(yǔ)言成為引人注目的中心的。如果您經(jīng)常訪(fǎng)問(wèn)討論論壇,就會(huì )注意到Ruby語(yǔ)言和Ruby On Rails框架之間也是這種情況。Ruby已經(jīng)出現十多年了,然而只是在Ruby OnRails框架流行之后,開(kāi)發(fā)人員才開(kāi)始注意到Ruby語(yǔ)言。
諸如Ruby、PHP和Python之類(lèi)的腳本語(yǔ)言最近幾年越來(lái)越流行,因此,需要開(kāi)發(fā)一個(gè)Java腳本備選語(yǔ)言和類(lèi)似Rails的針對Java環(huán)境的框架。Groovy就是這個(gè)腳本語(yǔ)言,而Grails就是這個(gè)框架。
在本文中我將討論Groovy的Web開(kāi)發(fā)功能,然后繼續討論Grails框架。我將開(kāi)發(fā)一個(gè)示例Grails Web應用程序,并討論此框架的各種特性。
Groovy是一種語(yǔ)言,其語(yǔ)法類(lèi)似于Java,但比Java更簡(jiǎn)單。它通常被視為腳本/靈活/動(dòng)態(tài)的語(yǔ)言,但是我不喜歡這類(lèi)形容詞,因為我認為它們只會(huì )令人困惑。如果說(shuō)Java是一位明智的中年男子,那么Groovy就是他十幾歲的兒子。Groovy具有父親的許多特點(diǎn),但是更為狂野且更為有趣。他們也可以很好地合作。
Groovy的規則比Java少得多。例如,要在Java中獲得標準的"HelloWorld"輸出,您需要編寫(xiě)一個(gè)類(lèi)、一個(gè)具有合適參數的主方法,等等。但是在Groovy中,如果不想編寫(xiě)所有樣板代碼,您可以?huà)侀_(kāi)類(lèi)定義和主方法,僅編寫(xiě)一行代碼即可打印出"Hello World"。
以下是打印Hello World的文件 Hello.groovy 的內容:
println "Hello World"
Java平臺僅關(guān)心使字節碼得到執行。同樣,此平臺不強迫您使用Java語(yǔ)言。只要提供了字節碼,工作就會(huì )進(jìn)行。Groovy代碼會(huì )被編譯為字節碼,而對于Java平臺來(lái)說(shuō),字節碼是從Java代碼還是Groovy代碼生成的并沒(méi)有任何區別。
以下是一個(gè)Groovy例子,它顯示了Groovy對清單、映射和范圍的內置支持,并證明了Groovy的簡(jiǎn)單性及其利用Java的強大功能的能力:
// Print Date
def mydate = new java.util.Date()
println mydate
//Iterate through a map
def numbersMAP = [‘1‘:‘ONE‘, ‘2‘:‘TWO‘]
for (entry in numbersMAP) {
println "${entry.key} = ${entry.value}"
}
//Introducing the range
def range = ‘a(chǎn)‘..‘d‘
//Lists
def numberlist = [1, 2, 3, 4, 5, 6, 7, 8]
println numberlist;
println "Maximum value: ${numberlist.max()}"
請注意以上代碼直接使用java.util.Date ,對收集的內置支持減少了使用清單、映射和范圍所需的代碼。還有許多其他有趣的Groovy特性,例如閉包和簡(jiǎn)化的XML處理。您可以在groovy.codehaus.org上找到詳細清單。
現在讓我們來(lái)討論如何將Groovy用于Web開(kāi)發(fā)。
大多數Java EE教程都從一個(gè)基本servlet例子開(kāi)始。對于GroovyWeb開(kāi)發(fā)來(lái)說(shuō),您將從groovlet(在groovy中servlet的對應概念)開(kāi)始。如果您在servlet中擺脫了類(lèi)和doXX()方法聲明,那么剩下的內容就與groovlet很像了。以下是一個(gè)名為 Login.groovy的groovlet例子,您需要將它置于Web應用程序的最高級目錄:
def username= request.getParameter("username")
def password= request.getParameter("password")
if (username == "java" && password == "developer") {
response.sendRedirect("home.jsp")
session = request.getSession(true);
session.setAttribute("name", username)
}
else {
println """
<h1>Login Invalid</h1>
<p>Your IP has been logged > ${request.remoteHost}</p>
"""
paramMap = request.getParameterMap()
println "<p>You Submitted:</p>"
for (entry in paramMap) {
println "${entry.key} = ${entry.value}<br/>"
}
}
您可以?xún)H創(chuàng )建一個(gè)簡(jiǎn)單的HTML表單,然后將此表單的行為屬性發(fā)送到 action="Login.groovy"。然后將以下標簽添加到web.xml:
<servlet>
<servlet-name>Groovy</servlet-name>
<servlet-class>groovy.servlet.GroovyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Groovy</servlet-name>
<url-pattern>*.groovy</url-pattern>
</servlet-mapping>
現在只需將要求的Groovy jar 文件添加到WEB-INF/lib 目錄,您的Groovy Web應用程序就準備好在任意Java EE應用服務(wù)器上運行了。
您應該已經(jīng)注意到代碼中沒(méi)有分號,而且使用了隱式變量如request和response。其他隱式變量有context、application、session、out、sout和 html。
GSP是JSP在groovy中的對應概念。您無(wú)需使用println生成HTML;只需將Groovy代碼嵌入HTML頁(yè)面。本文中的例子將在提到Grails時(shí)使用GSP。
請注意,因為所有代碼最終都要轉換為字節碼,所以groovlet和GSP能夠與servlet和JSP輕松協(xié)作。因此您無(wú)需區分groovlet和GSP或者servlet和JSP。
現在讓我們討論前途無(wú)量的Grails框架。如果成功的話(huà),Grails能夠極大地改變開(kāi)發(fā)Java Web應用程序的方式。Ruby on Rails對Ruby的影響,Grails也能夠對Groovy實(shí)現。
Grails試圖使用Ruby On Rails的“規約編程”(coding byconvention)范例來(lái)降低對配置文件和其他樣板代碼的需求。使用“規約編程”,如果文件的名稱(chēng)本身就能說(shuō)明此文件的用途,那么您就不需要在配置文件中再次聲明這些內容了。此框架會(huì )查看文件名,并自己弄清文件用途。通過(guò)使用“規約編程”,Grails還將自動(dòng)生成Web應用程序中需要的許多內容。通過(guò)使用Grails,您將能夠在很短的時(shí)間內、以最小的復雜性使Web應用程序就緒。請看以下例子。
Grails基于開(kāi)源技術(shù),例如Spring、Hibernate和SiteMesh。如果您已經(jīng)擅長(cháng)這些技術(shù),那么這是件好事;但是如果您由于某種原因不喜歡這些技術(shù),或者您認為不僅需要學(xué)習Grails,還需要學(xué)習其他三種框架,那么這就不是件好事了。雖然這些技術(shù)能夠幫助Grails執行得更好,但是學(xué)習四種框架對于大多數人來(lái)說(shuō)是一個(gè)很高的門(mén)檻。Grails文檔目前主要關(guān)注它與Spring、Hibernate和其他程序的集成,然而我認為它需要采用相反的方法,將Grails推行為一個(gè)簡(jiǎn)單快速的Web應用程序開(kāi)發(fā)框架。開(kāi)發(fā)人員無(wú)需擔心或考慮底層發(fā)生了什么。
幸運的是,一旦您開(kāi)始使用Grails,您將發(fā)現Grails隱藏了這些框架的大多數底層復雜性。如果您忘掉在底層運行的是Spring、Hibernate和其他程序,那么事情就會(huì )變得簡(jiǎn)單。
大多數框架都有數十種特性,其中只有很少幾種得到了廣泛使用。對于Grails來(lái)說(shuō),這種關(guān)鍵特性是指“規則編程”(coding by convention)范例和構件的自動(dòng)生成。
Grails的其他特性包括對Ajax、驗證、單元測試和功能測試的內置支持。它使用免費的開(kāi)源Canoo WebTest項目來(lái)實(shí)現Web應用程序的功能測試。Grails還提供與Quartz Scheduler的集成。
現在是時(shí)候安裝Grails框架并且編寫(xiě)您的第一個(gè)應用程序了。
安裝過(guò)程非常簡(jiǎn)單。以下是Grails下載頁(yè)面:http://grails.org/Download。您可以從http://dist.codehaus.org/grails/grails-bin-0.2.1.zip下載version 0.2.1。請注意Grails源代碼和文檔作為單獨的下載提供。下載zip文件之后,只需將其內容解壓縮到一個(gè)目錄即可,在我的案例中此目錄是 C:\groovy\grails-0.2.1\。
創(chuàng )建一個(gè)名為GRAILS_HOME 的新環(huán)境變量,并將其值設為C:\groovy\grails-0.2.1\。接下來(lái)將GRAILS_HOME\bin 添加到PATH環(huán)境變量。這樣安裝就完成了。通過(guò)在命令提示符界面中運行g(shù)rails 命令您可以檢查安裝是否成功。您應該獲得此命令的使用信息。
既然您有了一個(gè)運行中的Grails安裝,那么您已經(jīng)為創(chuàng )建Grails Web應用程序做好了準備。
多年來(lái)我一直計劃開(kāi)發(fā)一個(gè)可以幫助我管理衣服的應用程序——這個(gè)應用程序應該能夠告訴我我最喜歡的T恤衫放在哪里、是否洗過(guò)、是否熨過(guò),等等??傆幸惶煳視?huì )靠銷(xiāo)售這個(gè)應用程序掙上幾百萬(wàn),但是現在我將把它用作Grails例子。
第一步是創(chuàng )建一個(gè)Grails項目目錄結構。在這一步我將在C:\groovy\grailsapps創(chuàng )建一個(gè)新目錄,并在此級別打開(kāi)一個(gè)命令提示符窗口。在此窗口中,執行命令grails create-app。要求您輸入應用程序名稱(chēng)。輸入ClothesMgt。Grails將顯示它為您創(chuàng )建的全部目錄和文件。圖1顯示了最后得到的命令結構。

圖1:Grails項目目錄結構
此命令將創(chuàng )建約800KB大小的文件和目錄。這里的想法是此框架遵循已經(jīng)建立的Web應用程序開(kāi)發(fā)慣例,因此它創(chuàng )建的文件和目錄在大多數Web應用程序中是有用的。雖然有些人可能不喜歡這種強制使用某種結構的想法,但是這種基于慣例的自動(dòng)生成正是Grails的RAD特性的基礎。
如果更仔細地看一下這些目錄,您就會(huì )發(fā)現存在用于諸如控制器、視圖、測試、配置文件和標簽庫之類(lèi)東西的目錄。您還會(huì )發(fā)現存在一些基本JavaScript和CSS文件。那么現在應用程序的基本結構已經(jīng)有了。您只需做些填空,應用程序即可就緒。
請注意自動(dòng)生成目錄和文件的命令是可選的。您可以手動(dòng)創(chuàng )建全部文件和目錄。如果熟悉Apache Ant,那么您甚至可以打開(kāi)GRAILS_HOME 目錄中的\src\grails\build.xml 文件,來(lái)仔細查看每個(gè)Grails命令的用途。
在此例中我將使用一個(gè)運行于localhost的名為Clothes_Grails的MySQL數據庫。Grails內置一個(gè)HSQL數據庫,這對測試簡(jiǎn)單的應用程序或僅試用Grails非常有用。如果您使用HSQL DB,那么無(wú)需執行以下幾步。我將使用MySQL來(lái)證明您能夠非常輕松地使用HSQL之外的數據庫。
從http://www.mysql.com/products/connector/j/下載MySQL驅動(dòng)器,并將mysql-connector-java-<version number>-stable-bin.jar文件放置在ClothesMgt\lib 目錄中。接下來(lái)您需要編輯ClothesMgt\grails-app\conf\ApplicationDataSource.groovy文件。
現在此文件的內容應該類(lèi)似以下內容:
class ApplicationDataSource {
boolean pooling = true
String dbCreate = "create-drop"
String url = "jdbc:mysql://localhost/Clothes_Grails"
String driverClassName = "com.mysql.jdbc.Driver"
String username = "grails"
String password = "groovy"
}
現在讓我們看一下如何使用此數據庫和對象關(guān)系映射。
Grails的對象關(guān)系映射(GORM)功能在內部使用Hibernate3,但是您無(wú)需了解或更改任何Hibernate設置。Grails具有稱(chēng)為“域類(lèi)”的東西,這些域類(lèi)的對象被映射到數據庫。您可以使用關(guān)系來(lái)鏈接域類(lèi),它們也提供用于CRUD(創(chuàng )建/讀取/更新/刪除)操作的功能非常強大的動(dòng)態(tài)方法。
在此例中,我們將創(chuàng )建三個(gè)域類(lèi),其名稱(chēng)分別是Shirt、Trouser和Cabinet。要創(chuàng )建域類(lèi),只需運行命令 grailscreate-domain-class。請記住在您的項目目錄(而不是它的上級目錄)內運行此命令。這是一個(gè)常見(jiàn)錯誤,雖然我已經(jīng)提醒了您,您還是會(huì )犯至少一次這樣的錯誤。
您必須提供給create-domain-class命令的唯一輸入是類(lèi)的名稱(chēng)。運行此命令三次,將Shirt、Trouser和Cabinet作為三個(gè)域類(lèi)的名稱(chēng)。Grails現在將在目錄grails-app/domain/中創(chuàng )建這些域類(lèi)。它們將僅具有兩個(gè)屬性id 和version。我將為這些類(lèi)添加屬性,以便使它們更能代表襯衫、褲子和衣櫥。
清單1:Cabinet.groovy
class Cabinet {
Long id
Long version
String name
String location
def relatesToMany = [ shirts : Shirt, trousers : Trouser ]
Set shirts = new HashSet()
Set trousers = new HashSet()
String toString() { "${this.class.name} : $id" }
boolean equals(other) {
if(other?.is(this))return true
if(!(other instanceof Cabinet)) return false
if(!id || !other?.id || id!=other?.id) return false
return true
}
int hashCode() {
int hashCode = 0
hashCode = 29 * (hashCode + ( !id ? 0 : id ^ (id >>> 32)) )
}
}
清單2: Trouser.groovy
class Trouser {
Long id
Long version
String name
String color
Cabinet cabinet
def belongsTo = Cabinet
String toString() { "${this.class.name} : $id" }
boolean equals(other) {
if(other?.is(this))return true
if(!(other instanceof Trouser)) return false
if(!id || !other?.id || id!=other?.id) return false
return true
}
int hashCode() {
int hashCode = 0
hashCode = 29 * (hashCode + ( !id ? 0 : id ^ (id >>> 32) ) )
}
}
清單3: Shirt.groovy
class Shirt {
Long id
Long version
String name
String color
Cabinet cabinet
def belongsTo = Cabinet
String toString() { "${this.class.name} : $id" }
boolean equals(other) {
if(other?.is(this))return true
if(!(other instanceof Shirt)) return false
if(!id || !other?.id || id!=other?.id) return false
return true
}
int hashCode() {
int hashCode = 0
hashCode = 29 * (hashCode + ( !id ? 0 : id ^ (id >>> 32)))
}
}
我添加的僅有的幾行聲明了字段名稱(chēng)和顏色,然后聲明了Cabinet、Shirt和Trouser之間的關(guān)系。每個(gè)Shirt和Trouser都屬于Cabinet,而Cabinet具有shirt和trouser的集合。belongsTo屬性在此案例中是可選的,因為在一對多關(guān)系中,Grails會(huì )將“一”這一方視為所有者。因此您就無(wú)需顯式聲明了。在這里我進(jìn)行顯式聲明只是為了使這種關(guān)系更明顯。
接下來(lái)我們將討論Grails應用程序的控制器和視圖部分。
既然域類(lèi)已經(jīng)就緒,讓我們使用generate-all命令自動(dòng)生成基本CRUD Web應用程序。運行g(shù)rails generate-all 命令三次,當被詢(xún)問(wèn)時(shí)提供域類(lèi)名稱(chēng)。generate-all 命令的目的是生成每個(gè)域類(lèi)的控制器和視圖,但是由于bug-245,Grails 0.2.1不能生成控制器。您必須手動(dòng)生成控制器,其方法是對每個(gè)域類(lèi)使用generate-controller 命令。
現在您應該在grails-app\controllers 目錄中看到三個(gè)控制器。這些控制器負責處理Web應用程序中針對特定域類(lèi)的請求。因此ShirtController.groovy 將處理Web應用程序中與Shirt域類(lèi)相關(guān)的CRUD請求,等等?,F在控制器具有多個(gè)閉包,每個(gè)閉包映射到一個(gè)URI。閉包是Groovy語(yǔ)言很好的一個(gè)特性,然而要習慣它還是需要一些時(shí)間的。清單4顯示了Shirtcontroller.groovy的一段摘錄。
清單4:ShirtController.groovy 摘錄
class ShirtController {
def index = { redirect(action:list,params:params) }
def list = {
[ shirtList: Shirt.list( params ) ]
}
def show = {
[ shirt : Shirt.get( params.id ) ]
}
def delete = {
def shirt = Shirt.get( params.id )
if(shirt) {
shirt.delete()
flash.message = "Shirt ${params.id} deleted."
redirect(action:list)
}
else {
flash.message = "Shirt not found with id ${params.id}"
redirect(action:list)
}
}
// ...
}
在此例中,ShirtController 中的list閉包將處理URI是/shirt/list的請求,等等。您可在控制器中使用您習慣在Java Web應用程序中使用的東西,例如請求、會(huì )話(huà)和servletContext。
請注意:閉包也將值作為顯式返回語(yǔ)句返回,或者作為閉包體中的最后一個(gè)語(yǔ)句的值返回。不要因為Grails生成的代碼中沒(méi)有return 而困惑。
一旦控制器完成了對請求的處理,它必須委托給合適的視圖。Grails使用慣例機制實(shí)現此操作。因此ShirtController中的list閉包將委托給視圖 /grails-app/views/shirt/list.gsp 或/grails-app/views/shirt/list.jsp。盡管您在使用Grails,全部視圖可以是JSP文件而不是GSP。我幾乎沒(méi)有編寫(xiě)任何代碼,但是我已經(jīng)準備好了一個(gè)Web應用程序。
讓我們嘗試部署和運行我們的應用程序。
Grails具有一個(gè)內置Resin服務(wù)器,您可使用grails run-app 命令運行應用程序。此命令會(huì )將應用程序部署到Resin服務(wù)器并啟動(dòng)服務(wù)器。因此您現在可以在http://localhost:8080/ClothesMgt 訪(fǎng)問(wèn)此應用程序。您還可以同樣輕松地將應用程序部署到任意JavaEE服務(wù)器。我嘗試將它部署到Tomcat。要實(shí)現此操作,我所需要做的是運行g(shù)rails war 命令,將生成的war文件復制到Tomcat中的webapps目錄!
在此案例中生成的war文件的名稱(chēng)為 ClothesMgt.war。一旦部署到Tomcat,您就應該能夠在http://localhost:8080/ClothesMgt/ 上訪(fǎng)問(wèn)它,并看到如圖2所示的屏幕。

圖2:Grails 應用程序
通過(guò)此應用程序,能夠獲得Shirt、Trouser和Cabinet的全部CRUD功能??梢燥@示衣櫥的全部數據、向衣櫥添加新襯衫和褲子、編輯它們的值和刪除記錄——實(shí)現這些操作都無(wú)需編寫(xiě)任何業(yè)務(wù)邏輯、視圖或數據訪(fǎng)問(wèn)代碼。僅在幾分鐘內您就在JavaEE服務(wù)器上部署好了一個(gè)合適的Web應用程序。很酷吧?!
讓我們更進(jìn)一步來(lái)定制Grails。
我現在將把新功能和頁(yè)面添加到Web應用程序,同時(shí)重用已經(jīng)存在的域類(lèi)。shirt/list 和 trouser/list 會(huì )分別顯示襯衫和褲子的清單,現在讓我們添加一個(gè)新的顯示,來(lái)同時(shí)顯示襯衫和褲子的清單。要創(chuàng )建一個(gè)新的顯示,您需要一個(gè)新的控制器和視圖。
使用 generate-controller 和 generate-views命令,可以輕松實(shí)現使用域類(lèi)自動(dòng)生成視圖和控制器。然而,在此案例中我希望創(chuàng )建一個(gè)與域類(lèi)不直接關(guān)聯(lián)的控制器。因此我將使用grailscreate-controller命令。當被提示輸入控制器名稱(chēng)時(shí),聲明Display。Grails將在grails-app/controllers/ 目錄創(chuàng )建一個(gè)名為DisplayController.groovy 的控制器,在grails-tests目錄創(chuàng )建一個(gè)測試套件。如清單5所示編輯控制器。
清單5:DisplayController.groovy
class DisplayController {
def index = {redirect(action:list,params:params)}
def list = {
params[‘max‘] = 10
return [ shirtList: Shirt.list( params ),
trouserList: Trouser.list( params )]
}
}
index 閉包將請求重定向到清單。在list 閉包中我將最大參數設為10,然后使用動(dòng)態(tài)方法Shirt.list 和 Trouser.list。然后返回Groovy Map,它有兩個(gè)清單——襯衫清單和褲子清單。
作為Java開(kāi)發(fā)人員,當看到Shirt.list()時(shí)會(huì )自然認為是在Shirt域類(lèi)中的list方法。然而,如果打開(kāi)Shirt.groovy,會(huì )發(fā)現并沒(méi)有此方法。對于Java開(kāi)發(fā)人員來(lái)說(shuō),不了解Groovy的特性就使用Grails不僅是令人困惑的,而且是死胡同。動(dòng)態(tài)方法是Grails的特殊特性,它是構建于Groovy語(yǔ)言的一個(gè)非常特殊的特性元對象協(xié)議 (MOP)之上的。如此證明可以使用動(dòng)態(tài)方法查詢(xún)域類(lèi)。因此,在控制器中,您將注意到在域類(lèi)上調用的方法似乎在域類(lèi)中不存在。您可以在這里閱讀關(guān)于使用動(dòng)態(tài)方法查詢(xún)的更多信息??梢栽?a >這里找到對Grails控制器和域類(lèi)中可用的動(dòng)態(tài)方法的參考資料。
既然控制器能夠處理請求、獲取清單并轉發(fā)到視圖,我需要創(chuàng )建相應視圖。
當創(chuàng )建控制器時(shí),Grails還在grails-app\views 目錄創(chuàng )建了一個(gè)新的顯示目錄,并將以下映射添加到web.xml 文件中。
<servlet-mapping>
<servlet-name>grails</servlet-name>
<url-pattern>/display/*</url-pattern>
</servlet-mapping>
目前Grails有一個(gè)generate-views 命令,此命令能夠生成基于域類(lèi)的視圖,然而沒(méi)有能夠自動(dòng)生成視圖的create-view 命令。請看圖3中的例子。

圖3:一個(gè)顯示Trousers的默認視圖
因為我希望創(chuàng )建一個(gè)獨立于域類(lèi)的視圖,所以讓我們手動(dòng)創(chuàng )建視圖文件。在目錄grails-app\views\display\中,創(chuàng )建一個(gè)名為 list.gsp的文件,如清單6所示。
清單6:list.gsp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Display Shirt And Trouser List</title>
<link rel="stylesheet" href="${createLinkTo(dir:‘css‘,file:‘main.css‘)}"></link>
</head>
<body>
<div class="nav">
<span class="menuButton"><a href="${createLinkTo(dir:‘‘)}">Home</a></span>
</div>
<div class="body">
<h1>Shirt List</h1>
<table>
<tr>
<th>Id</th><th>Cabinet</th> <th>Color</th><th>Name</th>
</tr>
<g:each in="${shirtList}">
<tr>
<td>${it.id}</td> <td>${it.cabinet.name}</td>
<td>${it.color}</td> <td>${it.name}</td>
</tr>
</g:each>
</table>
<h1>Trouser List</h1>
<table>
<tr>
<th>Id</th> <th>Cabinet</th>
<th>Color</th> <th>Name</th>
</tr>
<g:each in="${trouserList}">
<tr>
<td>${it.id}</td> <td>${it.cabinet.name}</td>
<td>${it.color}</td> <td>${it.name}</td>
</tr>
</g:each>
</table>
</div>
</body>
</html>
與我之前使用的方式類(lèi)似,您現在也可以使用run-app 命令運行應用程序,或者創(chuàng )建一個(gè)war文件并將其部署到Tomcat。您應該在http://localhost:8080/ClothesMgt/display/下看到新的視圖,如圖4所示。

圖4:新創(chuàng )建的列出襯衫和褲子清單的視圖
現在讓我們快速討論一下Grails服務(wù)。
如果您想知道如何分開(kāi)業(yè)務(wù)邏輯以及放置業(yè)務(wù)邏輯的位置,答案在Grails 服務(wù)中。服務(wù)以SomeNameService.groovy 格式命名,且被置于 /grails-app/services/目錄。服務(wù)可利用依賴(lài)注入特性,您能夠輕松地從控制器內部調用這些服務(wù)。
讓我們來(lái)看一個(gè)使用服務(wù)的例子。首先,使用create-service命令創(chuàng )建新服務(wù)。運行此命令并命名服務(wù)Order。Grails將創(chuàng )建兩個(gè)文件——grails-app/services/OrderService.groovy 和 grails-tests/OrderTests.groovy。
現在編輯OrderService.groovy,如清單7所示。當引入新的orderGoods() 方法時(shí)會(huì )自動(dòng)生成serviceMethod() 。
清單7:OrderService.groovy
class OrderService {
boolean transactional = true
def serviceMethod() {
// TODO
}
def orderGoods() {
return "Order Placed - New shirts and trousers \
will be sent shortly."
}
}
現在編輯DisplayController,如清單8所示。引入使用OrderService的重排閉包。請注意服務(wù)將由Groovy注入。
清單8:DisplayController.groovy
class DisplayController {
OrderService orderService
def index = {redirect(action:list,params:params)}
def list = {
params[‘max‘] = 10
return [ shirtList: Shirt.list( params )
, trouserList: Trouser.list( params )]
}
def reorder = {
render(orderService.orderGoods())
}
}
現在當您訪(fǎng)問(wèn)URLhttp://localhost:8080/ClothesMgt/display/reorder時(shí),重排閉包將調用OrderService,響應會(huì )被發(fā)回到瀏覽器。您能夠以類(lèi)似方式將全部業(yè)務(wù)邏輯移入服務(wù),然后使用Grails的注入功能非常輕松地使用它們。
正如之前提到的,域類(lèi)沒(méi)有能夠從數據庫獲取數據或更新/刪除現有數據的任何方法,例如find()、 findAll() 或 save()。在控制器中您也沒(méi)有編寫(xiě)諸如 redirect() 或 render()之類(lèi)的方法。但是域類(lèi)和控制器有它們的計劃目的,且允許所有要求的操作。原因是Grails中動(dòng)態(tài)方法和屬性的存在。動(dòng)態(tài)方法被動(dòng)態(tài)添加到類(lèi),就好像功能是在程序中編譯的一樣。
這些是可用的方法和屬性,無(wú)需編寫(xiě)。這些動(dòng)態(tài)方法涵蓋了大多數Web應用程序開(kāi)發(fā)中會(huì )碰到的常見(jiàn)情況。對于域類(lèi)來(lái)說(shuō),存在諸如find()、findAll()、list()、executeQuery()、save()和delete()之類(lèi)的動(dòng)態(tài)方法??刂破骶哂兄T如session、request和response之類(lèi)的動(dòng)態(tài)屬性,以及諸如chain()、render()和 redirect()之類(lèi)的方法。要真正利用Grails的強大功能,您需要了解所有這些動(dòng)態(tài)方法和屬性的功能。
Grails的一個(gè)重要特性是能夠在開(kāi)發(fā)過(guò)程中進(jìn)行了更改時(shí)自動(dòng)重載文件。因此只需編輯和保存gsp文件,就會(huì )自動(dòng)重載新文件。然而這里創(chuàng )建的類(lèi)似OrderService 的事務(wù)服務(wù)不會(huì )被重載。您會(huì )在服務(wù)器控制臺看到以下消息"[groovy]Cannot reload class [class OrderService] reloading of transactionalservice classes is not currently possible. Set class tonon-transactional first. "。
Grails的自動(dòng)重載功能會(huì )為您節省許多時(shí)間,您就無(wú)需浪費時(shí)間來(lái)重啟服務(wù)器了。我碰到過(guò)一些Grails不能自動(dòng)重載的案例,例如將一個(gè)jsp文件重命名到gsp。然而,Grails的這項功能有望在未來(lái)版本中得到進(jìn)一步改進(jìn)。
在Groovy JSR 06 的之前版本中,您必須使用@Property來(lái)定義Groovy中的新屬性。因此您會(huì )在線(xiàn)看到許多使用@Property的舊的Groovy例子。然而請注意,@Property已經(jīng)從GroovyJSR 06中移除,在Grails 0.2和之后的版本中也不會(huì )再需要它。請參閱@Property 建議來(lái)獲得更多細節。
在本文中,我介紹了Grails框架的基本特性,并使用Grails創(chuàng )建了一個(gè)應用程序。Groovy和Grails最大的好處是一切都運行在優(yōu)秀的舊Java和Java EE上——因此您能夠使用Groovy和Grails的RAD特性快速開(kāi)發(fā)應用程序,然后將應用程序部署到可靠的JavaEE服務(wù)器上??紤]到關(guān)于Ruby和Rails的宣傳噪音,顯然需要一個(gè)Java備選方案。Groovy和Grails看起來(lái)非常適合這個(gè)角色。
下載本文中的代碼:
聯(lián)系客服