程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 精通Grails: 構建您的第一個Grails應用程序

精通Grails: 構建您的第一個Grails應用程序

編輯:關於JAVA

請允許我借助另一種開源 Web 開發框架 —— Ruby on Rails —— 來介紹 Grails。Rails 一發布就 迷住了開發人員。Rails 的腳手架功能使您可以用以前所需時間的一小部分完成一個新的項目。支持 Rails 的約定優於配置(convention over configuration)思想意味著,應用程序可以根據常識性的命 名模式自動進行組裝(auto-wire),而不必借助繁雜的、容易出錯的 XML 配置文件。Ruby 的元編程功 能使對象可以神奇地在運行時繼承所需的方法和字段,而不會擾亂源代碼。

Rails 配得上它所受到的贊美和推崇(現在仍然如此),但是它使 Java 開發人員面臨困難的選擇。 您會因為一個新平台的承諾而放棄自己熟悉的 Java 平台嗎?如何處理已有的 Java 代碼、已有的生產服 務器和經驗豐富的 Java 開發人員?

Grails 為您提供 Rails 風格的開發體驗,同時以可靠的 Java 技術作為堅強後盾。但是 Grails 不 僅僅是 Rails 通往 Java 平台的簡單入口。Grails 吸取了 Rails 的經驗,並將它們與現代 Java 開發 的意識相結合。可以認為 Grails 是受 Rails 啟發,而不是由 Rails 轉化而來。

作為 Grails 入門 系列的開篇,本文介紹 Grails 框架,展示它的安裝方法,遍覽如何構建第一個 Grails 應用程序:介紹本系列後續文章的內容。

Groovy 的威力

就像 Rails 與 Ruby 編程語言聯系非常緊密一樣,Grails 也離不開 Groovy(請參閱 參考資料)。 Groovy 是一種動態語言,它在 JVM 上運行,並且與 Java 語言無縫集成。如果閱讀了 developerWorks 上的大型 實戰 Groovy 系列,那麼您已經了解了這種語言的威力。如果沒有,也不必擔心 — 在學習 Grails 的過程中,您將了解到很多關於 Groovy 的知識。Groovy 應該不難學,因為它是特意為 Java 開 發人員而設計的。

例如,Groovy 可以大大減少 Java 代碼的數量。在 Groovy 中,不再需要為字段編寫 getter 和 setter 方法,因為 Groovy 會自動提供它們。不再需要編寫 for Iterator i = list.iterator() 來循 環遍歷一系列的項;list.each 可以做相同的事情,而且看上去更簡潔,表達更清晰。簡言之,Groovy 就是 21 世紀的 Java 語言。

如果 Java 開發人員只有重新編寫整個應用程序才能利用 Groovy,那麼 Groovy 對他們就沒有多大的 吸引力了。令人高興的是,Groovy 可以無縫地與已有的代碼庫集成。Groovy 不會替代 Java 語言 — 它 只是提供了增強。您可以很快地掌握 Groovy,因為說到底,Groovy 代碼就是 Java 代碼。這兩種語言是 如此兼容,甚至可以將一個 .java 文件重命名為一個 .groovy 文件 — 例如,將 Person.java 改為 Person.groovy — 從而得到一個有效的(可執行的)Groovy 文件(雖然這個 Groovy 文件並沒有用到 Groovy 提供的任何語法)。

Groovy 與 Java 語言的深度兼容意味著 Grails 不需要重新創造內部使用的關鍵技術。相反,您可以 以 Groovy 的方式查看熟悉的 Java 庫。Groovy 封裝了 JUnit TestCase 並以 GroovyTestCase 形式提 供。Grails 通過 GANT 對 Ant 構建進行了調整,GANT 是 Ant 的一個純 Groovy 實現。Grails 將 Hibernate 包裝在一個小小的 Groovy facade 中,並稱之為 GORM — Grails Object/Relational Mapper。Grails 使您在利用已有的 Java 經驗的同時,還可以利用最新的 Web 開發實踐,以上只是其中 的三個例子。

不過,要想全面地鑒賞 Grails,還需要親身體驗一下。現在,讓我們來安裝 Grails,並創建第一個 Web 應用程序。

安裝 Grails

運行 Grails 應用程序所需的一切都在一個 ZIP 文件中。所有的依賴庫 — 例如 Groovy、 Spring 和 Hibernate — 都已經在那裡,隨時可以使用。要安裝 Grails:

從 Grails 站 點(見 參考資料)下載並解壓 grails.zip。

創建一個 GRAILS_HOME 環境變量。

將 $GRAILS_HOME/bin 添加到 PATH 中。

您的確 需要安裝一個 JDK(Grails 是不錯,但是還沒有 好到 那種程度)。Grails 1.0 可在 Java 1.4、1.5 和 1.6 上運行。如果不知道已經安裝了哪個版本, 可以在命令行提示符下輸入 java -version。必要時,下載並安裝一個與 Grails 兼容的 JDK(見 參考 資料)。

完成安裝步驟後,輸入 grails -version 以進行檢查。如果看到以下友好信息,則說 明一切都得到正確配置:

Welcome to Grails 1.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /opt/grails

附帶 的 Web 服務器和數據庫

有趣的是,不需要單獨安裝 Web 服務器就可以運行 Grails 應用程序。 Grails 內置了 Jetty servlet 容器。只需輸入 grails run-app,就可以使應用程序在 Jetty 容器(見 參考資料)中運行,而不必執行常見的部署過程。在已有的生產服務器上運行 Grails 應用程序也沒有問 題。通過輸入 grails war 創建一個標准文件,然後可以將其部署到 Tomcat、JBoss、Geronimo、 WebSphere®,或者任何其他遵從 Java EE 2.4 的 servlet 容器。

您也不需要單獨安裝數據 庫。Grails 附帶了 HSQLDB(見 參考資料),它是一個純 Java 數據庫。通過提供一個隨時可用的數據 庫可以立即提高生產率。由於有了 Hibernate 和 GORM,使用其他數據庫(例如 MySQL、PostgreSQL、 Oracle Database 或 DB2)也很簡單。如果有一個 JDBC driver JAR 再加上通常的連接設置,只需改變 一下 DataSource.groovy,就可以立即使用您自己的數據庫。

編寫第一個 Grails 應用程序

我經常旅行 — 一年至少 40 趟。我發現,日程表可以很好地告訴我何時 需要達到某個地方,但是不 能顯示那個地方在哪裡。而在線地圖剛好相反:它們可以解決地點問題,但不能解決時間問題。所以,在 本文和本系列接下來的兩篇文章中,您將構建一個定制的 Grails 應用程序,在計劃旅程時,這個應用程 序既可以用於解決時間問題,又可以用於解決地點問題。

首先,在一個空白目錄下,輸入 grails create-app trip-planner。稍後,可以看到一個名為 trip -planner 的目錄。同 Maven、Rails 和 AppFuse 一樣,Grails 會建立一個標准的目錄結構。如果您覺 得這個目錄結構限制了您,並且只有精心設計自己的定制目錄樹才能使用一個框架,那麼這樣使用 Grails 不會有多大的樂趣。約定優於配置中的約定 部分使您可以擁有任何 Grails 應用程序,並立即知 道各個部分之間的聯系。

進入 trip-planner 目錄,並輸入 grails create-domain-class Trip。如果一切順利,將得到兩個 新的文件:grails-app/domain/Trip.groovy 和 grails-app/test/integration/TripTests.groovy。在 後面的文章中,我將談到測試。目前,我們主要關注域類。一開始,域類看上去如清單 1 所示:

清單 1. Grails 生成的域類

class Trip{
}

看上去沒什麼內容,對嗎?接下來讓我們來完善它。為 Trip 添加一些字段,如清單 2 所示:

清單 2. 添加字段後的 Trip 類

class Trip {
  String name
  String city
  Date startDate
  Date endDate
  String purpose
  String notes
}

如前所述,這裡不需要創建 getter 和 setter 方法:Groovy 會動態地生成它們。Trip 還有很多新 的、有用的動態方法,這些方法的名稱非常易用理解:

Trip.save() 將數據保存 到 HSQLDB 數據庫中的 Trip 表中。

Trip.delete() 從 Trip 表中刪除 數據。

Trip.list() 返回一個 Trip 列表。

Trip.get() 返回一個 Trip。

所有這些方法都已經存在,您在需要的時候就可以使用它們。注意,Trip 並沒有擴展某個父類或者實 現某個接口。由於 Groovy 的元編程功能,那些方法只是出現在適當類中的適當位置(只有 grails- app/domain 目錄中的類才擁有這些與持久性相關的方法)。

構建控制器和視圖

創建域類只是成功的一半。每個模型都還需要一個良好的控制器和一些視圖(我假設您熟悉 Model- View-Controller 模式;請參閱 參考資料)。輸入 grails generate-all Trip,以構建一個 grails- app/controllers/TripController.groovy 類,並在 grails-app/views/Trip 中生成一組匹配的 Groovy Server Page(GSP)。對於控制器中的每個 list 動作,都有一個相應的 list.gsp 文件。create 動作 則對應於一個 create.gsp 文件。從這裡可以看出約定優於配置的優點:無需 XML 文件就可以匹配這些 元素。每個域類根據名稱與一個控制器配對。控制器中的每個動作也是根據名稱與一個視圖配對。如果您 願意,也可以繞開這種基於名稱的配置,但是大多數時候只需遵循約定,應用程序自然就可以運行。

看看清單 3 所示的 grails-app/controller/TripController.groovy:

清單 3. TripController

class TripController {
   ...
   def list = {
     if(!params.max) params.max = 10
     [ tripList: Trip.list( params ) ]
   }
   ...
}

Java 開發人員首先會注意到的是,這麼少的代碼可以實現多少功能。以 list 動作為例。起重要作用 的是最後一行。Grails 將返回一個 hashmap,其中只有一個名為 tripList 的元素。(Groovy 方法的最 後一行是一個隱式的 return 語句。如果您願意,也可以手動地輸入單詞 return)。tripList 元素是 Trip 對象的一個 ArrayList,Trip 對象是通過 Trip.list() 方法從數據庫中拉出的。通常該方法將返 回表中的全部記錄。它上面的一行代碼表示 “如果 URL 中提供了一個 max 參數,那麼使用它來限制返 回的 Trip 的數量。否則,將 Trip 的數量限制為 10”。URL http://localhost:8080/trip- planner/trip/list 將調用這個動作。例如,http://localhost:8080/trip-planner/trip/list?max=3 顯示 3 個 trip,而不是通常的 10 個。如果有更多的 trip 要顯示,Grails 會自動創建上一頁和下一 頁的分頁鏈接。

那麼,如何使用這個 hashmap?看看 grails-app/views/list.gsp,如清單 4 所示:

清單 4. list.gsp

<g:each in="${tripList}" status="i" var="trip">
  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
   <td>
    <g:link action="show" id="${trip.id}">${trip.id?.encodeAsHTML()}</g:link>
   </td>
  </tr>
</g:each>

list.gsp 主要是一些老式 HTML 加上少量 GroovyTagLib。以 g: 為前綴的就是 GroovyTag。在清單 4 中,g:each 遍歷 tripList ArrayList 中的每個 Trip,並構建一個格式良好的 HTML 表格。

對控制器的理解可以歸結為三個 R:return、redirect 和 render。有些動作利用隱式的 return 語 句將數據返回到具有相同名稱的 GSP 頁面。有些動作進行重定向。例如,如果 URL 中未指定動作,則將 調用 index:

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

在此,TripController 重定向到 list 動作,同時傳遞 params hashmap 中的所有的參數(或 QueryString)。

最後,save 動作(見清單 5)並沒有相應的 save.gsp 頁面。如果記錄被成功地保存到數據庫中,那 麼該動作會重定向到 show 動作頁面。否則,它呈現 create.gsp 頁面,以便顯示錯誤,並讓您重試。

清單 5. save 動作

def save = {
  def trip = new Trip(params)
  if(!trip.hasErrors() && trip.save()) {
   flash.message = "Trip ${trip.id} created"
   redirect(action:show,id:trip.id)
  }
  else {
   render(view:'create',model:[trip:trip])
  }
}

在此,我們不詳細討論 Grails 是如何工作的,而是看看它的實際效果。

應用程序的實際效果

在命令行輸入 grails run-app。控制台在快速顯示一批 Log4j 消息之後,將顯示如下所示的消息:

Server running. Browse to http://localhost:8080/trip-planner

如果端口 8080 上已經有一個服務器在運行,那麼將顯示一條核心轉儲信息:

Server failed to start: java.net.BindException: Address already in use

可以通過兩種方法輕松更改 Jetty 所使用的端口。可以通過輸入 grails -Dserver.port=9090 run- app 臨時進行更改。如果要使更改持久,可以從 $GRAILS_HOME/scripts/Init.groovy 中找出以 serverPort 開頭的那一行,並更改值:

serverPort = System.getProperty('server.port') ?
       System.getProperty('server.port').toInteger() : 9090

使 Grails 在您選擇的端口上運行之後,在 Web 浏覽器中輸入 URL。應該可以看到一個歡迎屏幕,其 中列出所有的控制器,如圖 1 所示:

圖 1. Grails 應用程序的歡迎屏幕

單擊 TripController 鏈接。您有一個完整的 CRUD(創建、讀取、更新、刪除)應用程序可以使用。

使用圖 2 所示的頁面創建新的 trip:

圖 2. Create Trip 頁面

使用圖 3 所示的頁面編輯 trip:

圖 3. Trip List 頁面

准備和運行這個應用程序要花多長時間?需要多少代碼?下面就是答案:

按下 Ctrl-C,關閉 Grails。

輸入 grails stats。

屏幕上將顯示輸出:

+----------------------+-------+-------+
  | Name         | Files | LOC |
  +----------------------+-------+-------+
  | Controllers     |   1 |  66 |
  | Domain Classes    |   1 |   8 |
  | Integration Tests  |   1 |   4 |
  +----------------------+-------+-------+
  | Totals        |   3 |  78 |
  +----------------------+-------+-------+

只需不到 100 行代碼,就可以實現應用程序的所有功能。看起來還不錯。不過,最後我還要再展示一 個竅門。

生成控制器和視圖是一項很好的學習體驗,而磁盤上的物理文件則有助於說明各個部分是如何連接在 一起的。不過在此需要做一件事:刪除 TripController 類中的內容,並用下面的內容替代:

class TripController{
   def scaffold = Trip
  }

這行代碼告訴 Grails 像對待前一個控制器一樣,在運行時在內存中動態地生成所有那些 list、save 和 edit 動作。僅僅 3 行代碼就可以產生和 66 行代碼一樣的行為。

再次輸入 grails run-app。是的 — 所有數據都沒有了。不必擔心。按下 Ctrl-C 關閉 Grails。這 一次,輸入 grails prod run-app。現在處於生產模式下,這意味著在服務器重新啟動之前,數據已被保 存。通過一連串的單擊進入 TripController,保存一些記錄。應用程序的行為應該沒有什麼不同。您已 經知道,在浏覽器中看到的一切,是由 15 行代碼驅動的,可知 Grails 的威力有多大。

結束語

希望您對 Grails 的初次體驗感到滿意。小小一個包中,竟包含了令人驚訝的威力,而您只是看到冰 山一角。這個框架的安裝非常簡單,只需解壓一個文件。通過輸入幾行命令,就可以從頭創建一個應用程 序。希望這次簡單的介紹能勾起您對 Grails 的更大興趣。當然,本文也為您打好了一個基礎,您可以擴 展這個例子,嘗試各種新的、有趣的方面。

在下個月的文章中,您將專門花一些時間來關注 GORM。您將把日期保存到一個 MySQL 數據庫中,進 行某些數據驗證,並設置一個一對多的關系。不必添加很多代碼,就可以明顯增強 trip-planner 應用程 序的功能。

到那時,好好享受使用 Groovy 和 Grails 的樂趣吧。您對 Web 開發的看法將徹底改變。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved