精通 Grails: 構(gòu)建您的第一個 Grails 應(yīng)用程序(轉(zhuǎn)自developmentwork 中國)

          Java™ 程序員不需要放棄自己喜愛的語言和已有的開發(fā)基礎(chǔ)設(shè)施就可以采納一種新型的 Web 開發(fā)框架。在這個新推出的每月一期的 精通 Grails 系列的第一期中,Java 專家 Scott Davis 介紹了 Grails,并演示了如何構(gòu)建您的第一個 Grails 應(yīng)用程序。

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

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

          關(guān)于本系列

          Grails 是一種新型 Web 開發(fā)框架,它將常見的 Spring 和 Hibernate 等 Java 技術(shù)與當(dāng)前流行的約定優(yōu)于配置等實踐相結(jié)合。Grails 是用 Groovy 編寫的,它可以提供與遺留 Java 代碼的無縫集成,同時還可以加入腳本編制語言的靈活性和動態(tài)性。學(xué)習(xí)完 Grails 之后,您將徹底改變看待 Web 開發(fā)的方式。

          Grails 為您提供 Rails 風(fēng)格的開發(fā)體驗,同時以可靠的 Java 技術(shù)作為堅強(qiáng)后盾。但是 Grails 不僅僅是 Rails 通往 Java 平臺的簡單入口。Grails 吸取了 Rails 的經(jīng)驗,并將它們與現(xiàn)代 Java 開發(fā)的意識相結(jié)合。可以認(rèn)為 Grails 是受 Rails 啟發(fā),而不是由 Rails 轉(zhuǎn)化而來

          作為 Grails 入門 系列的開篇,本文介紹 Grails 框架,展示它的安裝方法,遍覽如何構(gòu)建第一個 Grails 應(yīng)用程序:介紹本系列后續(xù)文章的內(nèi)容。

          Groovy 的威力

          就像 Rails 與 Ruby 編程語言聯(lián)系非常緊密一樣,Grails 也離不開 Groovy(請參閱 參考資料)。Groovy 是一種動態(tài)語言,它在 JVM 上運(yùn)行,并且與 Java 語言無縫集成。如果閱讀了 developerWorks 上的大型 實戰(zhàn) Groovy 系列,那么您已經(jīng)了解了這種語言的威力。如果沒有,也不必?fù)?dān)心 — 在學(xué)習(xí) Grails 的過程中,您將了解到很多關(guān)于 Groovy 的知識。Groovy 應(yīng)該不難學(xué),因為它是特意為 Java 開發(fā)人員而設(shè)計的。

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

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

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

          不過,要想全面地鑒賞 Grails,還需要親身體驗一下。現(xiàn)在,讓我們來安裝 Grails,并創(chuàng)建第一個 Web 應(yīng)用程序。





          回頁首


          安裝 Grails

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

          1. 從 Grails 站點(diǎn)(見 參考資料)下載并解壓 grails.zip。
          2. 創(chuàng)建一個 GRAILS_HOME 環(huán)境變量。
          3. 將 $GRAILS_HOME/bin 添加到 PATH 中。

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

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

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

          附帶的 Web 服務(wù)器和數(shù)據(jù)庫

          使用免費(fèi)附帶品

          對于本文的應(yīng)用程序,您將使用 Grails 免費(fèi)提供的 Web 服務(wù)器和數(shù)據(jù)庫。在將來的文章中,我將詳細(xì)說明如何在您自己的服務(wù)器上運(yùn)行 Grails。在此期間,請經(jīng)常訪問 grails.org 并瀏覽優(yōu)秀的在線文檔(見 參考資料)。

          有趣的是,不需要單獨(dú)安裝 Web 服務(wù)器就可以運(yùn)行 Grails 應(yīng)用程序。 Grails 內(nèi)置了 Jetty servlet 容器。只需輸入 grails run-app,就可以使應(yīng)用程序在 Jetty 容器(見 參考資料)中運(yùn)行,而不必執(zhí)行常見的部署過程。在已有的生產(chǎn)服務(wù)器上運(yùn)行 Grails 應(yīng)用程序也沒有問題。通過輸入 grails war 創(chuàng)建一個標(biāo)準(zhǔn)文件,然后可以將其部署到 Tomcat、JBoss、Geronimo、WebSphere®,或者任何其他遵從 Java EE 2.4 的 servlet 容器。

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





          回頁首


          編寫第一個 Grails 應(yīng)用程序

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

          后續(xù)介紹

          本系列后面的文章將討論如何將 Google Calendar 和 Google Maps 與 Grails 相結(jié)合。

          首先,在一個空白目錄下,輸入 grails create-app trip-planner。稍后,可以看到一個名為 trip-planner 的目錄。同 Maven、Rails 和 AppFuse 一樣,Grails 會建立一個標(biāo)準(zhǔn)的目錄結(jié)構(gòu)。如果您覺得這個目錄結(jié)構(gòu)限制了您,并且只有精心設(shè)計自己的定制目錄樹才能使用一個框架,那么這樣使用 Grails 不會有多大的樂趣。約定優(yōu)于配置中的約定 部分使您可以擁有任何 Grails 應(yīng)用程序,并立即知道各個部分之間的聯(lián)系。

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


          清單 1. Grails 生成的域類
                      class Trip{
                      }
                      

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


          清單 2. 添加字段后的 Trip 類
                      class Trip {
                      String name
                      String city
                      Date startDate
                      Date endDate
                      String purpose
                      String notes
                      }
                      

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

          • Trip.save() 將數(shù)據(jù)保存 到 HSQLDB 數(shù)據(jù)庫中的 Trip 表中。
          • Trip.delete() 從 Trip 表中刪除 數(shù)據(jù)。
          • Trip.list() 返回一個 Trip 列表。
          • Trip.get() 返回一個 Trip

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

          構(gòu)建控制器和視圖

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

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


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

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

          那么,如何使用這個 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,并構(gòu)建一個格式良好的 HTML 表格。

          對控制器的理解可以歸結(jié)為三個 Rreturnredirect 和 render。有些動作利用隱式的 return 語句將數(shù)據(jù)返回到具有相同名稱的 GSP 頁面。有些動作進(jìn)行重定向。例如,如果 URL 中未指定動作,則將調(diào)用 index

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

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

          最后,save 動作(見清單 5)并沒有相應(yīng)的 save.gsp 頁面。如果記錄被成功地保存到數(shù)據(jù)庫中,那么該動作會重定向到 show 動作頁面。否則,它呈現(xiàn) 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])
                      }
                      }
                      

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





          回頁首


          應(yīng)用程序的實際效果

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

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

          如果端口 8080 上已經(jīng)有一個服務(wù)器在運(yùn)行,那么將顯示一條核心轉(zhuǎn)儲信息:

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

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

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

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


          圖 1. Grails 應(yīng)用程序的歡迎屏幕
          Grails 應(yīng)用程序的歡迎屏幕 

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

          使用圖 2 所示的頁面創(chuàng)建新的 trip:


          圖 2. Create Trip 頁面
          創(chuàng)建 Trip 

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


          圖 3. Trip List 頁面
          編輯 Trip 

          準(zhǔn)備和運(yùn)行這個應(yīng)用程序要花多長時間?需要多少代碼?下面就是答案:

          1. 按下 Ctrl-C,關(guān)閉 Grails。
          2. 輸入 grails stats

          屏幕上將顯示輸出:

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

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

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

            class TripController{
                      def scaffold = Trip
                      }
                      

          這行代碼告訴 Grails 像對待前一個控制器一樣,在運(yùn)行時在內(nèi)存中動態(tài)地生成所有那些 listsave 和 edit 動作。僅僅 3 行代碼就可以產(chǎn)生和 66 行代碼一樣的行為。

          再次輸入 grails run-app。是的 — 所有數(shù)據(jù)都沒有了。不必?fù)?dān)心。按下 Ctrl-C 關(guān)閉 Grails。這一次,輸入 grails prod run-app。現(xiàn)在處于生產(chǎn)模式下,這意味著在服務(wù)器重新啟動之前,數(shù)據(jù)已被保存。通過一連串的單擊進(jìn)入 TripController,保存一些記錄。應(yīng)用程序的行為應(yīng)該沒有什么不同。您已經(jīng)知道,在瀏覽器中看到的一切,是由 15 行代碼驅(qū)動的,可知 Grails 的威力有多大。





          回頁首


          結(jié)束語

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

          在下個月的文章中,您將專門花一些時間來關(guān)注 GORM。您將把日期保存到一個 MySQL 數(shù)據(jù)庫中,進(jìn)行某些數(shù)據(jù)驗證,并設(shè)置一個一對多的關(guān)系。不必添加很多代碼,就可以明顯增強(qiáng) trip-planner 應(yīng)用程序的功能。

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



          關(guān)于作者

          Scott Davis

          Scott Davis 是國際知名作家、演講家、軟件開發(fā)人員。他出版的書籍有 Groovy Recipes: Greasing the Wheels of JavaGIS for Web Developers: Adding Where to Your ApplicationThe Google Maps API 和 JBoss At Work


          posted on 2008-10-01 16:27 OVER 閱讀(203) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           
          <2008年10月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(1)

          隨筆檔案

          Links

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 永泰县| 象山县| 元谋县| 梁河县| 紫阳县| 龙里县| 时尚| 小金县| 古田县| 怀集县| 清苑县| 黔江区| 南乐县| 汉源县| 芒康县| 淳安县| 南安市| 图木舒克市| 阿克苏市| 海南省| 澄江县| 唐山市| 五寨县| 峨山| 饶阳县| 镇康县| 天长市| 淳安县| 墨脱县| 高唐县| 象山县| 天柱县| 舞钢市| 太白县| 兰溪市| 修文县| 门源| 邵武市| 诸城市| 勐海县| 清涧县|