作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Gregor Ambrozic
Verified Expert in Engineering

Gregor是一名拥有超过12年工作经验的全栈软件工程师, 主要是用Java开发和使用数据库.

Read More

PREVIOUSLY AT

Fieldoo
Share

Java有一个经过多年开发而成熟的生态系统, 把它打造成最可靠的平台之一. 然而,它缺乏迅速完成这项工作所需的手段, 尤其是对于web应用程序. 为了避免这类问题带来的挫折, 开发人员通常会选择实现语言及其现代web框架, 比如Ruby with Ruby on Rails, Python with Django, and so on. 与Java不同,它们为构建web应用程序提供了更加精简的路径.

为什么Java开发者应该给Grails一个机会?

Java web开发人员:认识一下Grails,看看你错过了什么.

幸运的是,对于想要构建web应用程序的Java开发人员来说,有 is 一个更好的方法,它涉及到Grails. 在本文中,我们将看到Grails与Groovy如何成为JVM领域中一个可行的替代方案. 我们将看到一些例子,在这些例子中,Grails对Java开发人员很有吸引力,也可能会吸引其他人尝试一下.

The Story

在我工作的一家初创公司,我们就遇到了同样的问题. 我们有一个Spring应用程序,使用起来很麻烦. 随着它越来越大, 我们很快发现,重构和添加功能所花费的时间远远超出了预期. 结合其他动机,我们决定重写我们的核心应用程序. 我们也愿意改变或替换现有的技术堆栈. Grails看起来是一个可行的选择,因为它运行在JVM中,并且构建在我们已经知道的技术之上. 它使用Groovy编程语言,但同时允许您将其与Java混合使用. 所以我们决定冒险一试.

Full Speed Ahead

Grails真正擅长的一件事是使启动一个新项目变得容易. 它就像运行一个命令一样简单,该命令创建项目结构,其中包含稍后要添加的类所需的所有文件夹. 添加模型类、控制器、服务和网页也只需要最少的工作量. 你唯一需要注意的是正确地命名和放置物品. Unlike Java, 实际上,不存在仅仅因为需要而需要存在的样板代码. 这部分是通过使用Spring和Hibernate实现的,这是Grails的两大支柱, 以及按约定编码的概念. 为了运行这个项目,Grails作为开发服务器与Apache Tomcat捆绑在一起. 我们所要做的就是在IDE中运行这个项目,然后服务器就会被我们部署的代码启动. Also, the Grails对象关系映射(GORM) Hibernate会帮我们创建数据库. 使用现有数据库, 我们需要配置JDBC连接属性,或者将其默认设置为使用内存中的实例. 一旦使用Grails的服务器开始运行(比Spring MVC应用程序稍微多一点), 我们可以修改代码,热部署功能将使我们的调试会话配备最新版本. 唯一不能以这种方式重新加载的类是实体类.

可以通过使用SQL脚本来填充数据库,但这可能会很繁琐. 所有Grails项目都包含一个Bootstrap类,它将在我们的应用程序运行时运行. 在这个类中,我们可以存储或修改数据,从而初始化应用程序状态. 事实证明,这对我们非常有用,因此我们在开发版本中立即有了一些测试用例.

在Bootstrap类中, 我们还可以使用“if”条件检查环境类型(开发), test, production, etc.),并对数据进行相应的修改.

Manipulating Data

Grails立即引起我们注意的一件事是处理数据的便利性. 从数据库中读取数据是一项需要反复执行的任务. 很多时候都很简单. 比如获取一个或多个满足特定条件的实体,然后将它们聚合起来. 为什么不使用动态查找器呢? 它是在运行时动态创建方法的情况下查询数据的一种方式. 您所要做的就是遵循命名约定.

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

上面一行将获取姓氏以“Doe”开头或年龄大于30岁的所有User对象. 是的,不是很复杂的案子,但你懂的.

如果我们想要过滤这个列表中“failedLogins”属性大于10的那些呢? 如果我们想按照它们的创建日期来排序呢? 如果我们想把他们的名字连接起来或者找到返回用户的最大年龄呢?

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

上面的例子可能看起来很简单, 但它们显示了Grails在查询方面的强大功能, filtering, 操纵数据. In Java 8, 对于其中一些情况,您可以获得类似的结果, 但它仍然需要比Grails更多的代码.

有时候我想做些不一样的创作

动态构造函数或命名参数构造函数是我们许多人希望在Java中拥有的特性. 定义某个类允许使用哪些构造函数是件好事, 但在很多情况下,你只是想设置一些属性,然后获得那个该死的实例. Groovy为每个实体添加了一个特殊的构造函数,它基本上将map的优雅性作为输入,并使用map条目设置属性.

def Person = new Person(名字:'Batman',年龄:57)

这种方法使代码更具表现力,并且避免了对所有构造函数样板代码的需要.

顺便说一句,这里有一些Groovy地图的优秀和优雅的例子:

def emptyMap = [:]
Def map =[面包:3,牛奶:5,黄油:2]
map[‘bread’] = 4
map.milk = 6

这是另一个例子,说明代码可以简短而简单,但功能强大. 它展示了如何使用内联初始化,以及如何以类似于对象属性的方式操作映射值. 不需要调用传统的Java方法进行基本操作,除非您真的想这样做.

We Need More Power!

Of course, 没有一个框架可以做所有的事情, 但当我们填补空白的时候, 在尝试实现我们自己的解决方案之前,我们应该看看其他可能已经可用的东西. 为了扩展基于Grails的功能库,我们可以使用Grails插件. 插件的安装只需要在 BuildConfig 在每个Grails项目中都存在的类(代码约定再次出现)!).

编译:spring-security-core: 2.0-RC4'

上面这行代码将Spring安全核心添加到我们的应用程序中,实际上不需要更多的配置来合并此功能.

它类似于使用Maven依赖项(您也可以在相同的配置类中引用它)。, 但是插件通常是包含全部功能的更大的块.

话虽如此,让我告诉你一个我们必须处理的案子. 我们需要实现跨多个数据实体的搜索. Grails有一个Elasticsearch插件,使用起来很简单. 如前所述,我们只需要在配置文件中引用插件,就可以开始了. 如果我们想搜索某个类的实体, 我们只需要向该类添加一个静态的“searchable”属性. 如果我们愿意,我们甚至可以限制允许搜索的属性.

class User { 
    静态可搜索={仅= name} 
    String name 
    Double salary 
}

代码这么少, but under the hood, Grails和Elasticsearch插件会自动按名字为所有用户建立索引,并允许我们按名字进行搜索. 实际的搜索调用也非常简洁:

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

如果我们不想这样做,我们将永远不必碰Lucene索引. 一切都会自动为我们完成. 这个插件甚至有一个显示搜索结果的API——它可以突出显示在搜索文本中找到的匹配项. 这只是一个插件如何提供大量功能的例子,这些功能可以通过避免我们自己实现来提高我们的效率.

我们还需要更多的能源

插件很好,但有时我们不需要整个插件,我们只是想要一些额外的东西. 还记得上次您想要在现有Java类上添加一个额外的方法,但又不想(或不能)扩展/覆盖它们的情况吗? In Groovy, 可以向现有类添加方法和属性, 或者只是其中的一些例子. 例如,您可以添加a formatting method to the java.util.Date 类,当你想要一致地格式化日期,而不想编写静态util类或定义各种过滤器时,这是非常棒的.

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

如果您希望根据计算值对用户列表进行排序,并且只在一种情况下需要这样做(i.e. 在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昨天allmytroubleshooting seemedsofaraway =新的日期()- 1
myAwesomeAnniversaryYear = myawesomeedate[日历].YEAR] + 1
myAwesomeDate.set(年份:myAwesomeAnniversaryYear,秒:0)

当您想要真正获得描述性的日期操作时,您可以简单地使用添加的Groovy TimeCategory class:

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

A Hammer and a Nail

然后是ide. 基于eclipse的GGTS和IntelliJ IDEA是为使用Grails而设置的. 他们了解项目结构(并将帮助您浏览文件夹和资源),并为您最常用的命令提供快捷方式(例如.g.,添加控制器,添加页面,运行项目等.). 使用Grails,您将执行命令(运行一个项目或设置一个新的插件功能),您将需要不同的配置, ide也涵盖了哪些方面. 代码补全在Grails web模板页面中工作得很好,因为您经常会引用控制器和操作.还有其他可以与Grails一起使用的ide,如Netbeans、TextMate、Emacs等.

那黑暗面呢?

就像生活中的所有事情一样,使用Grails也有一些注意事项. 在幕后有很多神奇的事情发生,这往往是一件好事, 但有时结果并不如你所愿. bug会因为不使用打字而发生(是的, 类型在Groovy中是可选的),而且不够小心. 也许当你发现错误的时候已经太晚了. 此外,写一句俏皮话给同事留下深刻印象也是很诱人的. And yourself. 但是这些功能强大的代码行对您的同事来说可能不那么容易理解. 或者几个月后对自己说. 这就是为什么我认为Grails比一些更传统的框架需要更多的编程原则.

Time is Money

编码不应该因为当前框架的要求而花费更多的时间. 尤其是现在创业公司的数量越来越多, 把注意力集中在真正重要的任务上,尽可能提高效率是很重要的. 时间就是金钱,进入市场的时间至关重要. 你需要能够在时间耗尽和你的竞争对手抢在你之前迅速行动并实施解决方案.

我的朋友们 Ruby on Rails 或者Python/Django一直在告诉我这些技术有多酷. 想想我用Java写代码,把东西存储到数据库中,然后显示在网页上,花了多少时间,我真的觉得很傻. Grails可能确实是一个有用的答案. 这并不是说使用纯Java、Spring MVC和Hibernate就不能做到这一点. You could. 您的应用程序甚至可能运行得更快一些. 但是使用Grails可以更快地完成这项工作.

聘请Toptal这方面的专家.
Hire Now
Gregor Ambrozic

Gregor Ambrozic

Verified Expert in Engineering

Ljubljana, Slovenia

2015年11月30日成为会员

About the author

Gregor是一名拥有超过12年工作经验的全栈软件工程师, 主要是用Java开发和使用数据库.

Read More
作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

PREVIOUSLY AT

Fieldoo

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

Toptal Developers

Join the Toptal® community.