為什麼 Java 開發人員應該給 Grails 一個機會?

已發表: 2022-03-11

Java 擁有一個經過多年發展成熟的生態系統,將其確立為最可靠的平台之一。 然而,它缺乏快速完成工作所必需的手段,尤其是對於 Web 應用程序之類的事情。 為了避免對這些類型的問題感到沮喪,開發人員通常選擇實現語言及其現代 Web 框架,例如 Ruby 與 Ruby on Rails、Python 與 Django 等。 與 Java 不同,它們提供了一種更加簡化的方式來構建 Web 應用程序。

為什麼 Java 開發人員應該給 Grails 一個機會?

Java Web 開發人員:認識 Grails 並找出您錯過的內容。
鳴叫

幸運的是,對於想要構建 Web 應用程序的 Java 開發人員來說,一個更好的方法,它涉及到 Grails。 在本文中,我們將看到帶有 Groovy 的 Grails 如何成為 JVM 領域的可行替代方案。 我們將看一些例子,說明 Grails 對我們作為 Java 開發人員具有吸引力,並且可能會誘使其他人也嘗試一下。

故事

在我工作的一家初創公司中,我們遇到了這個確切的問題。 我們有一個 Spring 應用程序,使用它變得很痛苦。 隨著它變得越來越大,我們很快發現重構和添加功能花費的時間比預期的要長。 結合其他一些動機,我們決定重寫我們的核心應用程序。 我們也願意改變或替換現有的技術堆棧。 Grails 看起來是一個可行的選擇,因為它在 JVM 中運行並且構建在我們已經知道的技術之上。 它使用 Groovy 編程語言,但同時允許您將其與 Java 混合使用。 所以我們冒險了。

全速前進

Grails 真正擅長的一件事是讓開始一個新項目變得容易。 它就像運行一個命令一樣簡單,該命令創建項目結構,其中包含您稍後將添加的類所需的所有文件夾。 添加模型類、控制器、服務和網頁同樣需要最少的工作量。 您唯一需要注意的是正確命名和放置東西。 與 Java 不同,幾乎沒有樣板代碼需要存在,因為它需要存在。 這部分是通過使用作為 Grails 的兩個支柱的 Spring 和 Hibernate 以及按約定編碼的概念來實現的。 為了運行該項目,Grails 與 Apache Tomcat 捆綁在一起作為開發服務器。 我們所要做的就是在我們的 IDE 中運行該項目,然後服務器將被我們部署的代碼啟動。 此外,帶有 Hibernate 的 Grails 對象關係映射 (GORM) 將負責為我們創建數據庫。 要使用現有數據庫,我們需要配置 JDBC 連接屬性,或者默認使用內存實例。 一旦帶有 Grails 的服務器開始運行(比 Spring MVC 應用程序需要更多的時間),我們可以修改代碼,熱部署功能將使我們的調試會話配備最新版本。 唯一不能以這種方式重新加載的類是實體類。

可以使用 SQL 腳本來填充數據庫,但這可能會變得乏味。 所有 Grails 項目都包含一個 Bootstrap 類,它將在我們的應用程序運行時運行。 在這個類中,我們可以存儲或修改數據,從而初始化我們的應用程序狀態。 事實證明這對我們非常有用,所以我們馬上就有了一些開發版本的測試用例。

在 Bootstrap 類中,我們還可以使用“if”條件來檢查環境類型(開發、測試、生產等)並相應地修改數據。

操作數據

Grails 立即引起我們注意的一件事是處理數據的便利性。 從數據庫中讀取是一項需要反复完成的任務。 很多時候它很簡單。 就像獲取一個或多個滿足特定條件的實體然後聚合它們一樣。 為什麼不使用動態查找器呢? 這是一種查詢數據的方式,其中方法是在運行時動態創建的。 您所要做的就是遵循命名約定。

 def users = User.findAllByLastNameLikeOrAgeGreaterThan('Doe%', 30)

上面的行將獲取姓氏以“Doe”開頭或年齡大於 30 的所有用戶對象。是的,這不是一個非常複雜的案例,但你明白了要點。

如果我們想針對“failedLogins”屬性大於 10 的列表額外過濾該列表怎麼辦? 如果我們想按創建日期對它們進行排序怎麼辦? 如果我們想要連接他們的名字或找到返回用戶的最大年齡怎麼辦?

 users = users.findAll() { it.failedLogins > 10 } users = users.sort { it.dateCreated } def firstNamesString = users.firstName.join(', ') def maximumAge = users.age.max()

上面的例子可能看起來很簡單,但它們展示了 Grails 在查詢、過濾和操作數據方面的強大功能。 在 Java 8 中,您可以在其中一些情況下獲得類似的結果,但它仍然需要比 Grails 更多的代碼。

有時我想創造不同的東西

動態構造函數或命名參數構造函數是我們許多人希望在 Java 中擁有的特性。 定義某個類允許哪些構造函數很好,但在許多情況下,您只想設置一些屬性並獲取該死的實例。 Groovy 為每個實體添加了一個特殊的構造函數,它基本上將地圖的優雅作為輸入,並使用地圖條目設置屬性。

 def Person = new Person(name: 'Batman', age: 57)

這種方法導致代碼更具表現力,並且避免了對所有構造函數樣板代碼的需要。

順便說一句,這裡有一些 Groovy 地圖令人敬畏和優雅的例子:

 def emptyMap = [:] def map = [bread:3, milk:5, butter:2] map['bread'] = 4 map.milk = 6

這是代碼如何簡短而強大的另一個示例。 它展示瞭如何使用內聯初始化以及如何以類似於對象屬性的方式操作映射值。 無需調用傳統的 Java 方法進行基本操作,除非您真的想這樣做。

我們需要更多的力量!

當然,沒有什麼框架可以做所有事情,但是當我們填補空白時,我們應該在嘗試實現我們自己的解決方案之前看看還有什麼可用的。 為了擴展我們基於 Grails 的功能庫,我們可以使用 Grails 插件。 只需在每個 Grails 項目中存在的BuildConfig類中添加另一行即可安裝插件(代碼約定再次出現!)。

 compile ':spring-security-core:2.0-RC4'

上面的行將 Spring 安全核心添加到我們的應用程序中,實際上不需要更多配置來合併此功能。

它類似於使用 Maven 依賴項(您也可以在同一配置類中引用),但插件通常是包含整個功能的較大塊。

話雖如此,讓我告訴你一個我們必須處理的案例。 我們需要實現跨越多個數據實體的搜索。 Grails 有一個 Elasticsearch 插件,使用起來很輕鬆。 如前所述,我們只需要在配置文件中引用插件就可以了。 如果我們想搜索某個類的實體,我們只需要為該類添加一個靜態的“可搜索”屬性。 如果我們願意,我們甚至可以限制允許搜索的屬性。

 class User { static searchable = { only = name } String name Double salary }

它的代碼非常少,但在底層,Grails 和 Elasticsearch 插件會自動按名稱索引所有用戶,並使我們能夠按名稱搜索。 實際的搜索調用也很簡潔:

 User.search("${params.query}")

如果我們不想,我們將永遠不必接觸 Lucene 索引。 一切都會自動為我們完成。 該插件甚至有一個用於顯示搜索結果的 API——它可以突出顯示在搜索文本中找到的匹配項。 這只是一個插件如何提供大量功能的示例,這些功能可以通過避免我們自己實現它來提高我們的效率。

我們仍然需要更多的力量

插件很棒,但有時我們不需要一個完整的插件,我們只是想要一些額外的東西。 您還記得上次您想在現有 Java 類上添加一個附加方法但您不想(或不能)擴展/覆蓋它們嗎? 在 Groovy 中,您可以將方法和屬性添加到現有類,甚至只是它們的某些實例。 例如,您可以向java.util.Date類添加一個formatting方法,當您想要一致地格式化日期並且不想編寫靜態 util 類或定義各種過濾器時,這非常棒。

 Date.metaClass.formatDate = { delegate.format("dd.MM.yyyy") }

如果您想按計算值對用戶列表進行排序並且只在一種情況下需要它(即在 User 類中添加新方法會造成污染)怎麼辦? 您可以在每個實例上添加一個屬性,然後按該屬性對集合進行排序或過濾:

 user.metaClass.computedProp = 312 * 32 * 3

Groovy 作者已經為一些核心 Java 類添加了很多增強功能,所以我們不必這樣做。 下面是一些例子。

使用“減號”從一個集合中刪除另一個集合中存在的所有元素。

 assert [1, 2, 3, 4, 4, 5] - [2, 4] == [1, 3, 5]

用於操作java.util.Date對象的其他方法可以派上用場很多次,例如從日期中添加/減去天數或獲取/設置日期的某個字段而不將其轉換為Calendar或使用其他庫。

 def yesterdayAllMyTroublesSeemedSoFarAway = new Date() - 1 def myAwesomeAnniversaryYear = myAwesomeDate[Calendar.YEAR] + 1 myAwesomeDate.set(year: myAwesomeAnniversaryYear, second: 0)

當您想真正了解日期操作時,您可以簡單地使用 Groovy 添加的TimeCategory類:

 use (TimeCategory) { println 1.minute.from.now println 10.hours.ago def someDate = new Date() println someDate - 3.months }

錘子和釘子

然後是IDE。 基於 Eclipse 的 GGTS 和 IntelliJ IDEA 設置為與 Grails 一起使用。 他們了解項目結構(並將幫助您瀏覽文件夾和資源)並為您最常使用的命令提供快捷方式(例如,添加控制器、添加頁面、運行項目等)。 使用 Grails,您將執行命令(運行項目或設置新的插件功能),並且您將需要不同的配置,這也包含在 IDE 中。 代碼完成在 Grails Web 模板頁面中工作得很好,您經常會在其中引用控制器和操作。還有其他可以與 Grails 一起使用的 IDE,例如 Netbeans、TextMate、Emacs 等。

黑暗面呢?

就像生活中的一切一樣,Grails 也有一些注意事項。 引擎蓋下有很多魔術,這通常是一件好事,但有時結果不會是你所期望的。 錯誤的發生只是因為不使用類型(是的,類型在 Groovy 中是可選的)並且不夠小心。 也許你不會注意到錯誤,直到為時已晚。 此外,寫單行字來給你的同事留下深刻印像是非常誘人的。 和你自己。 但是這些強大的代碼行可能對您的同事來說並不那麼容易解釋。 甚至在幾個月內對你自己。 這就是為什麼我認為 Grails 比一些更傳統的框架需要更多的編程紀律。

時間就是金錢

編碼不應該僅僅因為您當前的框架需要它而花費更多時間。 尤其是如今初創公司數量越來越多,重要的是要專注於真正重要的任務並儘可能提高效率。 時間確實是金錢,上市時間至關重要。 您需要能夠在時間用完之前迅速採取行動並實施解決方案,並且您的競爭對手會擊敗您。

長期以來,我使用 Ruby on Rails 或 Python/Django 的朋友一直在告訴我這些技術有多酷。 想想我在 Java 中花費了多少時間來編寫將某些內容存儲在數據庫中並將其顯示在網頁中的代碼,真的感覺很愚蠢。 Grails 可能確實是一個有用的答案。 並不是說你不能用純 Java、Spring MVC 和 Hibernate 來做到這一點。 你可以。 您的應用程序甚至可能運行得更快一些。 但是使用 Grails 可以更快地完成工作。

相關:為什麼需要升級到 Java 8