为什么 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