讀古今文學網 > Spring Boot實戰 > 6.3 結合Spring Boot與Grails 3 >

6.3 結合Spring Boot與Grails 3

Grails一直都是構建於Spring、Groovy、Hibernate和其他巨人肩膀之上的高階框架。到了Grails 3,Grails已經基於Spring Boot,帶來了令人愉悅的開發體驗。Grails開發者和Spring Boot開發者都能駕輕就熟。

要使用Grails 3,首先要進行安裝。在Mac OS X和大部分Unix系統上,最簡單的安裝方法是在命令行裡使用SDKMAN:

$ sdk install grails

  

如果你用的是Windows,或者無法使用SDKMAN,就需要下載二進制發佈包。解壓後要將bin目錄添加到系統路徑裡去。

無論用哪種安裝方式,你都可以在命令行中查看Grails的版本,驗證安裝是否成功:

$ grails -version

  

如果安裝成功,現在就可以創建Grails項目了。

6.3.1 創建新的Grails項目

在Grails項目中,你會使用grails命令行工具執行很多任務,包括創建項目。要創建閱讀列表項目,可以這樣使用grails命令:

$ grails create-app readinglist

  

正如這個命令的名字所示,create-app創建了新的應用程序項目。這個例子裡的項目名為readinglist。

grails工具創建完應用程序,cd到了readinglist目錄裡,看看所創建的內容吧。圖6-2應該就是你看到的項目結構的概覽。

圖 6-2 Grails 3項目的目錄結構

在這個項目目錄結構裡,你應該認出了一些熟悉的東西。這裡有一個Gradle的構建說明文件和配置(build.gradle和gradle.properties)。src目錄裡還有一個標準的Gradle項目結構,但是grails-app應該是裡面最有趣的目錄。如果用過老版本的Grails,你就會知道這個目錄的作用。這裡面放的是你寫的控制器、領域類和其他構成Grails項目的代碼。

如果再深挖一下,打開build.gradle文件,會發現一些更熟悉的東西。首先,構建說明文件裡使用了Spring Boot的Gradle插件:

apply plugin: \"spring-boot\"

  

這意味著你能像使用其他Spring Boot應用程序那樣構建並運行這個Grails應用程序。

你還應該注意到,依賴裡有不少有用的Spring Boot庫:

dependencies {
  compile \'org.springframework.boot:spring-boot-starter-logging\'
  compile(\"org.springframework.boot:spring-boot-starter-actuator\")
  compile \"org.springframework.boot:spring-boot-autoconfigure\"
  compile \"org.springframework.boot:spring-boot-starter-tomcat\"
  ...
}

  

這些庫為Grails應用程序提供了Spring Boot的自動配置、日誌,還有Actuator及嵌入式Tomcat。把應用當作可執行JAR運行時,這個Tomcat可以提供服務。

實際上,這是一個Spring Boot項目,同時也是Grails項目,因為Grails 3就是構建在Spring Boot的基礎上的。

運行應用程序

運行Grails應用程序最直接的方式是在命令行裡使用grails工具的run-app命令:

$ grails run-app

  

就算一行代碼都還沒寫,我們也能運行應用程序,在瀏覽器裡進行訪問。一旦應用程序啟動,就可以在瀏覽器裡訪問http://localhost:8080。你應該能看到類似圖6-3的頁面。

圖 6-3 全新的Grails應用程序

在Grails裡運行應用程序要使用run-app命令,這種方式已經用了很多年,上個版本的Grails也是這樣。Grails 3項目的Gradle說明裡使用了Spring Boot的Gradle插件,你還可以用各種運行Spring Boot項目的方式來運行這個應用程序。此處通過Gradle引入了bootRun任務:

$ gradle bootRun

  

你還可以構建項目,運行生成的可執行JAR文件:

$ gradle build
...
$ java -jar build/lib/readingList-0.1.jar

  

當然,構建產生的WAR文件可以部署到你喜歡的各種Servlet 3.0容器裡。

在開發早期就能運行應用程序,這一點十分方便,能幫你確認應用程序已正確初始化。但是這時應用程序還沒做什麼有意思的事情,在初始化後的項目上做什麼完全取決於我們。接下來,開始定義領域模型吧。

6.3.2 定義領域模型

閱讀列表應用程序裡的核心領域模型是Book類。雖然我們可以手工創建Book.groovy文件,但通常還是用grails工具來創建領域模型類比較好。因為它知道該把文件放到哪裡,並且能在同一時間生成各種相關內容。

要創建Book類,我們會使用grails工具的create-domain-class命令:

$ grails create-domain-class Book

  

這條命令會生成兩個源文件:一個Book.groovy文件和一個BookSpec.groovy文件。後者是一個Spock說明,用來測試Book類。一開始這個文件是空的,你可以填入各種測試內容來驗證Book的各種功能。

Book.groovy文件裡定義了Book類,你可以在grails-app/domain/readingList裡找到這個文件。它一開始基本沒什麼內容:

package readinglist
class Book {

  static constraints = {
  }
}

  

我們需要添加一些字段來定義一本書,比如書名、作者和ISBN。在添加了這些字段後,Book.groovy看起來是這樣的:

package readinglist
class Book {

  static constraints = {
  }

  String reader
  String isbn
  String title
  String author
  String description

}

  

靜態的constraints變量裡可以定義各種附加在Book實例上的驗證約束。本章中,我們主要關注閱讀列表應用程序的構建,看看如何基於Spring Boot構建應用程序,不會太關注驗證的問題。因此,這裡的constraints內容為空。當然,如果有需要的話,你可以隨意添加約束。可以參考一下Grails in Action\'Second Edition,作者是Glen Smith和Peter Ledbrook。1

1這本書雖然主講Grails 2,但你在Grails 2里瞭解到的大部分內容都適用於Grails 3。

為了使用Grails,我們要保持閱讀列表應用程序的簡潔,要和第2章的程序一致。因此,接下來我們要創建Reader領域模型,還有控制器。

6.3.3 開發Grails控制器

有了領域模型,通過grails工具創建出控制器就很容易了。關於控制器,有幾個命令可供選擇。

  • create-controller:創建空控制器,讓開發者來編寫控制器的功能。

  • generate-controller:生成一個控制器,其中包含特定領域模型類的基本CRUD操作。

  • generate-all:生成針對特定領域模型類的基本CRUD控制器,及其視圖。

腳手架控制器很好用,也是Grails中比較知名的特性,但我們仍然會保持簡潔,寫一個僅包含必要功能的控制器,能匹配第2章裡的應用程序功能就好。因此,我們用create-controller命令來創建原始的控制器,然後填入所需的方法。

$ grails create-controller ReadingList

  

這個命令會在grails-app/controllers/readingList裡創建一個名為ReadingListController的控制器:

package readinglist
class ReadingListController {

  def index { }
}

  

一行代碼都不用改,這個控制器就能運行了,雖然它幹不成什麼事。此時,它能處理發往/readingList的請求,將請求轉給grails-app/views/readingList/index.gsp裡定義的視圖(現在還沒有,我們稍後會創建的)。

我們需要控制器來顯示圖書列表,還有添加新書的表單。我們還需要提交表單,將新書保存到數據庫裡的功能。下面的代碼就是我們所需要的ReadingListController

代碼清單6-6 改寫ReadingListController

package readinglist

import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional

class ReadingListController {

  def index {
    respond Book.list(params), model:[book: new Book]    ←---獲取圖書填充到模型裡
  }

  @Transactional
  def save(Book book) {
    book.reader = \'Craig\'
    book.save flush:true     ←---保存圖書
    redirect(action: \"index\")
  }

}

  

雖然相比等效的Java控制器,代碼長度大幅縮短,但這個版本的ReadingListController功能已經基本完整。它可以處理發往/readingList的GET請求,獲取並展示圖書列表。在表單提交後,它還會處理POST請求,保存圖書,隨後重定向回index動作(由index方法來處理)。

太不可思議了,我們已經基本完成了Grails版本的閱讀列表應用程序。剩下的就是創建一個視圖,顯示圖書列表和表單。

6.3.4 創建視圖

Grails應用程序通常都用GSP模板來做視圖。你已經看到過如何在Spring Boot應用程序裡使用GSP了,因此,此處的模板並不會和6.2節裡的模板有太多不同。

我們要做的是,利用Grails提供的佈局設施,將公共的設計風格運用到整個應用程序裡。如代碼清單6-7所示,這就是個很簡單的修改。

代碼清單6-7 一個適用於Grails的GSP模板,包含佈局

<!DOCTYPE html>
<html>
  <head>
    <meta name=\"layout\" content=\"main\"/>     ←---使用了main佈局
    <title>Reading List</title>
    <link rel=\"stylesheet\"
          href=\"/assets/main.css?compile=false\"  />
    <link rel=\"stylesheet\"
          href=\"/assets/mobile.css?compile=false\"  />
    <link rel=\"stylesheet\"
          href=\"/assets/application.css?compile=false\"  />
  </head>

  <body>
    <h2>Your Reading List</h2>

    <g:if test=\"${bookList && !bookList.isEmpty}\">     ←---列出圖書
      <g:each in=\"${bookList}\" var=\"book\">
      <dl>
        <dt>
          ${book.title}</span> by ${book.author}
          (ISBN: ${book.isbn}\")
        </dt>
        <dd>
          <g:if test=\"${book.description}\">
          ${book.description}
          </g:if>
          <g:else>
          No description available
          </g:else>
        </dd>
      </dl>
      </g:each>
    </g:if>
    <g:else>
      <p>You have no books in your book list</p>
    </g:else>

    <hr/>

    <h3>Add a book</h3>

    <g:form action=\"save\">     ←---圖書表單
    <fieldset>
      <label for=\"title\">Title:</label>
      <g:field type=\"text\" name=\"title\" /><br/>
      <label for=\"author\">Author:</label>
      <g:field type=\"text\" name=\"author\"
                          /><br/>
      <label for=\"isbn\">ISBN:</label>
      <g:field type=\"text\" name=\"isbn\" /><br/>
      <label for=\"description\">Description:</label><br/>
      <g:textArea name=\"description\" 
                                     rows=\"5\" cols=\"80\"/>
    </fieldset>
    <fieldset>
      <g:submitButton name=\"create\"
         />
    </fieldset>
    </g:form>

  </body>
</html>

 

<head>元素裡移除了引用樣式表的<link>標籤。這裡放了一個<meta>標籤,引入了Grails應用程序的main佈局。這樣一來,應用程序就能用上Grails的外觀了,運行效果如圖6-4所示。

圖 6-4 應用通用Grails風格的閱讀列表應用程序

雖然Grails風格比之前用的簡單的樣式表更吸引眼球。但很顯然的是,要讓閱讀列表應用程序更好看,還有一些工作要做。首先要讓應用程序和Grails不那麼像,和我們的想像更接近一點。修改應用程序的樣式表在本書的討論範圍之外,但如果你對樣式微調感興趣,可以在grails-app/ assets/stylesheets目錄裡找到樣式表文件。