1. Overview
1.概述
Ratpack is a set of lightweight Java libraries for building scalable HTTP applications with reactive, asynchronous, and non-blocking features.
Ratpack是一套轻量级的Java库,用于构建具有反应式、异步和非阻塞功能的可扩展HTTP应用程序。
Additionally, Ratpack also provides integration with technologies and frameworks like Google Guice, Spring Boot, RxJava and Hystrix.
此外,Ratpack还提供了与技术和框架的集成,如Google Guice, Spring Boot, RxJava和Hystrix。
In this tutorial, we’ll explore how to use Ratpack with Groovy.
在本教程中,我们将探讨如何用Groovy使用Ratpack。
2. Why Groovy?
2.为什么是Groovy?
Groovy is a powerful, dynamic language that runs in the JVM.
Groovy是一种强大的动态语言,在JVM中运行。
Therefore, Groovy makes scripting and Domain Specific Languages really easy. With Ratpack, this provides for rapid web application development.
因此,Groovy使脚本和特定领域语言变得非常容易。有了Ratpack,这就提供了快速的网络应用程序开发。
Ratpack provides easy integration with Groovy through the ratpack-groovy and ratpack-groovy-test libraries.
Ratpack通过ratpack-groovy和ratpack-groovy-test库提供了与Groovy的轻松集成。
3. Ratpack Application Using Groovy Script
3.使用Groovy脚本的Ratpack应用程序
The Ratpack Groovy APIs are built in Java so they can easily integrate with both Java and Groovy applications. They’re available in the ratpack.groovy package.
Ratpack Groovy APIs是用 Java 构建的,因此它们可以轻松地与 Java 和 Groovy 应用程序集成。它们可以在ratpack.groovy包中获得。
Actually, in combination with Groovy’s scripting abilities and Grape dependency management, we can quickly create a Ratpack-powered web application in just a few lines:
实际上,结合Groovy的脚本能力和Grape的依赖性管理,我们只需几行就能快速创建一个由Ratpack驱动的Web应用。
@Grab('io.ratpack:ratpack-groovy:1.6.1')
import static ratpack.groovy.Groovy.ratpack
ratpack {
handlers {
get {
render 'Hello World from Ratpack with Groovy!!'
}
}
}
This is our first handler, handling a GET request. All we had to do was to add some basic DSL to enable the Ratpack server.
这是我们的第一个处理程序,处理一个GET请求。我们所要做的就是添加一些基本的DSL来启用Ratpack服务器。
Let’s now run this as a Groovy script to start the application. By default, the application will be available on http://localhost:5050:
现在让我们以Groovy脚本的形式运行这个脚本来启动应用程序。默认情况下,该应用程序将在http://localhost:5050上可用。
$ curl -s localhost:5050
Hello World from Ratpack with Groovy!!
We can also configure the port using ServerConfig:
我们还可以使用ServerConfig来配置端口。
ratpack {
serverConfig {
port(5056)
}
}
Ratpack also provides a hot reloading feature, which means we can change Ratpack.groovy, and then see the changes the moment the application serves our next HTTP request.
Ratpack还提供了热重载功能,这意味着我们可以改变Ratpack.groovy,然后在应用程序为我们的下一个HTTP请求提供服务时看到这些变化。
4. Ratpack-Groovy Dependency Management
4.Ratpack-Groovy依赖性管理
There are several ways to enable ratpack-groovy support.
有几种方法来启用ratpack-groovy支持。
4.1. Grape
4.1 葡萄
We can use Groovy’s embedded dependency manager Grape.
我们可以使用Groovy的嵌入式依赖管理器Grape。
It’s as simple as adding an annotation to our Ratpack.groovy script:
这就像在我们的Ratpack.groovy脚本中添加一个注释一样简单。
@Grab('io.ratpack:ratpack-groovy:1.6.1')
import static ratpack.groovy.Groovy.ratpack
4.2. Maven Dependency
4.2.Maven的依赖性
For building in Maven, all we need is to add the dependency for the ratpack-groovy library:
在Maven中构建时,我们只需添加ratpack-groovy库的依赖性。
<dependency>
<groupId>io.ratpack</groupId>
<artifactId>ratpack-groovy</artifactId>
<version>${ratpack.version}</version>
</dependency>
4.3. Gradle
4.3. Gradle
We can enable ratpack-groovy integration, by adding Ratpack’s Gradle plugin for Groovy in build.gradle:
我们可以通过在build.gradle中添加Ratpack的Groovy Gradle插件来实现ratpack-groovy集成。
plugins {
id 'io.ratpack.ratpack-groovy' version '1.6.1'
}
5. Ratpack Handlers in Groovy
5 Groovy中的Ratpack处理程序
Handlers provide a way to handle web requests and responses. The request and response objects can be accessed in this closure.
处理程序提供了一种处理Web请求和响应的方法。请求和响应对象可以在这个闭包中被访问。
We can handle web requests using HTTP methods like GET and POST:
我们可以使用HTTP方法处理网络请求,如GET和POST:。
handlers {
get("greet/:name") { ctx ->
render "Hello " + ctx.getPathTokens().get("name") + " !!!"
}
}
We can test this web request through http://localhost:5050/greet/<name>:
我们可以通过http://localhost:5050/greet/<name>测试这个网络请求。
$ curl -s localhost:5050/greet/Norman
Hello Norman!!!
In the code of the handler, ctx is the Context registry object which grants access to path variables, request and response objects.
在处理程序的代码中,ctx是Context注册表对象,允许访问路径变量、请求和响应对象。
Handlers also have support for dealing with JSON through Jackson.
处理程序也支持通过Jackson处理JSON。
Let’s return JSON, converted from a Groovy map:
让我们返回JSON,由Groovy地图转换而成。
get("data") {
render Jackson.json([title: "Mr", name: "Norman", country: "USA"])
}
$ curl -s localhost:5050/data
{"title":"Mr","name":"Norman","country":"USA"}
Here, Jackson.json is used to make the conversion.
这里,Jackson.json被用来进行转换。
6. Ratpack Promises in Groovy
6.Groovy中的Ratpack Promises
As we know, Ratpack enables the asynchronous and non-blocking features in the application. This is implemented with Ratpack Promises.
正如我们所知,Ratpack在应用程序中实现了异步和非阻塞的功能。这是用Ratpack Promises实现的。
Promises are similar to those used in JavaScript and are a bit like a Java Future. We can think of a Promise as the representation of a value which will be available in the future:
承诺与JavaScript中使用的承诺类似,有点像Java的Future。我们可以把Promise看作是未来可用的值的表示。
post("user") {
Promise<User> user = parse(Jackson.fromJson(User))
user.then { u -> render u.name }
}
The last action here is the then action, which determines what to do with the final value. In this case, we return it as a response to the POST.
这里的最后一个动作是then动作,它决定如何处理最后的值。在这种情况下,我们把它作为POST的一个响应返回。
Let’s understand this code in more detail. Here, Jackson.fromJson parses the JSON of the request body using the ObjectMapper User. Then, the inbuilt Context.parse method binds it to the Promise object.
让我们更详细地了解这段代码。在这里,Jackson.fromJson使用ObjectMapper User解析了请求主体的JSON。然后,内置的Context.parse方法将其绑定到Promise对象。
The promise operates asynchronously. When the then operation is eventually performed, the response is returned:
承诺的操作是异步的。当then操作最终被执行时,会返回响应。
curl -X POST -H 'Content-type: application/json' --data \
'{"id":3,"title":"Mrs","name":"Jiney Weiber","country":"UK"}' \
http://localhost:5050/employee
Jiney Weiber
We should note that the Promise library is quite rich, allowing us to chain actions using functions like map and flatMap.
我们应该注意到,Promise库相当丰富,允许我们使用map和flatMap等函数进行连锁操作。
7. Integration with a Database
7.与数据库整合
Having asynchronous handlers is of most benefit when our handlers have to wait for services. Let’s demonstrate this by integrating our Ratpack application with an H2 database.
当我们的处理程序需要等待服务时,拥有异步处理程序是最有好处的。让我们通过将我们的Ratpack应用程序与H2数据库集成来证明这一点。
We can either use the Ratpack’s HikariModule class which is an extension of HikariCP JDBC connection pool, or Groovy Sql for database integration.
我们可以使用Ratpack的HikariModule类,它是HikariCP JDBC连接池的扩展,或者使用GroovySql进行数据库集成。
7.1. HikariModule
7.1 HikariModule
To add HikariCP support, let’s first add the following Hikari and H2 maven dependencies in our pom.xml:
要添加HikariCP支持,首先让我们在pom.xml中添加以下Hikari和H2>的maven依赖项。
<dependency>
<groupId>io.ratpack</groupId>
<artifactId>ratpack-hikari</artifactId>
<version>${ratpack.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
Or, we can add the following dependencies to our build.gradle:
或者,我们可以在我们的build.gradle中添加以下依赖项。
dependencies {
compile ratpack.dependency('hikari')
compile "com.h2database:h2:$h2.version"
}
Now, we’ll declare HikariModule under the bindings closure for the connection pool:
现在,我们将在连接池的bindings闭包下声明HikariModule。
import ratpack.hikari.HikariModule
ratpack {
bindings {
module(HikariModule) { config ->
config.dataSourceClassName = 'org.h2.jdbcx.JdbcDataSource'
config.addDataSourceProperty('URL',
"jdbc:h2:mem:devDB;INIT=RUNSCRIPT FROM 'classpath:/User.sql'")
}
}
}
Finally, we’re all set to use it for simple database operations using Java’s Connection and PreparedStatement:
最后,我们就可以使用Java的Connection和PreparedStatement进行简单的数据库操作了。
get('fetchUserName/:id') { Context ctx ->
Connection connection = ctx.get(DataSource.class).getConnection()
PreparedStatement queryStatement =
connection.prepareStatement("SELECT NAME FROM USER WHERE ID=?")
queryStatement.setInt(1, Integer.parseInt(ctx.getPathTokens().get("id")))
ResultSet resultSet = queryStatement.executeQuery()
resultSet.next()
render resultSet.getString(1)
}
Let’s check that the handler works as expected:
让我们检查一下处理程序是否按预期工作。
$ curl -s localhost:5050/fetchUserName/1
Norman Potter
7.2. Groovy Sql Class
7.2 Groovy Sql Class
We can use Groovy Sql for quick database operations, through methods like rows and executeInsert:
我们可以通过rows和executeInsert等方法,使用Groovy Sql进行快速数据库操作。
get('fetchUsers') {
def db = [url:'jdbc:h2:mem:devDB']
def sql = Sql.newInstance(db.url, db.user, db.password)
def users = sql.rows("SELECT * FROM USER");
render(Jackson.json(users))
}
$ curl -s localhost:5050/fetchUsers
[{"ID":1,"TITLE":"Mr","NAME":"Norman Potter","COUNTRY":"USA"},
{"ID":2,"TITLE":"Miss","NAME":"Ketty Smith","COUNTRY":"FRANCE"}]
Let’s write an HTTP POST example with Sql:
让我们写一个带有Sql的HTTP POST例子。
post('addUser') {
parse(Jackson.fromJson(User))
.then { u ->
def db = [url:'jdbc:h2:mem:devDB']
Sql sql = Sql.newInstance(db.url, db.user, db.password)
sql.executeInsert("INSERT INTO USER VALUES (?,?,?,?)",
[u.id, u.title, u.name, u.country])
render "User $u.name inserted"
}
}
$ curl -X POST -H 'Content-type: application/json' --data \
'{"id":3,"title":"Mrs","name":"Jiney Weiber","country":"UK"}' \
http://localhost:5050/addUser
User Jiney Weiber inserted
8. Unit Testing
8.单元测试
8.1. Setting up the Tests
8.1.设置测试
As discussed, Ratpack also provides the ratpack-groovy-test library for testing a ratpack-groovy application.
如前所述,Ratpack还提供了ratpack-groovy-test库,用于测试ratpack-groovy应用。。
To use it, we can add it as Maven dependency in our pom.xml:
要使用它,我们可以在pom.xml中把它作为Maven依赖项加入。
<dependency>
<groupId>io.ratpack</groupId>
<artifactId>ratpack-groovy-test</artifactId>
<version>1.6.1</version>
</dependency>
Alternatively, we can add the Gradle dependency in our build.gradle:
另外,我们可以在我们的build.gradle中添加Gradle依赖。
testCompile ratpack.dependency('groovy-test')
Then we need to create a Groovy main class RatpackGroovyApp.groovy to let us test the Ratpack.groovy script.
然后我们需要创建一个Groovy主类RatpackGroovyApp.groovy来让我们测试Ratpack.groovy脚本。
public class RatpackGroovyApp {
public static void main(String[] args) {
File file = new File("src/main/groovy/com/baeldung/Ratpack.groovy");
def shell = new GroovyShell()
shell.evaluate(file)
}
}
When running Groovy tests as JUnit tests, the class will invoke the Ratpack.groovy script using GroovyShell. In turn, it will start the Ratpack server for testing.
当作为JUnit测试运行Groovy测试时,该类将使用GroovyShell调用Ratpack.groovy脚本。反过来,它将启动Ratpack服务器进行测试。
Now, let’s write our Groovy Test class RatpackGroovySpec.groovy along with the code to start the Ratpack server through the RatpackGroovyApp:
现在,让我们编写我们的Groovy测试类RatpackGroovySpec.groovy,以及通过RatpackGroovyApp启动Ratpack服务器的代码。
class RatpackGroovySpec {
ServerBackedApplicationUnderTest ratpackGroovyApp =
new MainClassApplicationUnderTest(RatpackGroovyApp.class)
@Delegate TestHttpClient client =
TestHttpClient.testHttpClient(ratpackGroovyApp)
}
Ratpack provides MainClassApplicationUnderTest to mock the application class for starting the server.
Ratpack提供MainClassApplicationUnderTest来模拟启动服务器的应用类。
8.2. Writing Our Tests
8.2.编写我们的测试
Let’s write our tests, starting with a very basic test to check if the application can start:
让我们来编写我们的测试,从一个非常基本的测试开始,检查应用程序是否能够启动。
@Test
void "test if app is started"() {
when:
get("")
then:
assert response.statusCode == 200
assert response.body.text ==
"Hello World from Ratpack with Groovy!!"
}
Let’s now write another test to verify the response of the fetchUsers get handler:
现在让我们再写一个测试来验证fetchUsers get handler的响应。
@Test
void "test fetchUsers"() {
when:
get("fetchUsers")
then:
assert response.statusCode == 200
assert response.body.text ==
'[{"ID":1,"TITLE":"Mr","NAME":"Norman Potter","COUNTRY":"USA"},{"ID":2,"TITLE":"Miss","NAME":"Ketty Smith","COUNTRY":"FRANCE"}]'
}
The Ratpack test framework takes care of starting and stopping the server for us.
Ratpack测试框架为我们处理了启动和停止服务器的问题。
9. Conclusion
9.结语
In this article, we’ve seen a few ways to write HTTP handlers for Ratpack using Groovy. We also explored Promises and Database integration.
在这篇文章中,我们已经看到了一些使用Groovy为Ratpack编写HTTP处理程序的方法。我们还探讨了Promises和数据库集成。
We’ve seen how Groovy closures, DSLs, and Groovy’s Sql make our code concise, efficient and readable. At the same time, Groovy’s test support makes unit and integration testing straightforward.
我们已经看到Groovy闭包、DSL和Groovy的Sql是如何使我们的代码简洁、高效和可读的。同时,Groovy的测试支持使单元和集成测试变得简单明了。
With these techniques, we can use Groovy’s dynamic language features, and expressive APIs, to rapidly develop high-performance, scalable HTTP applications with Ratpack.
通过这些技术,我们可以利用Groovy的动态语言特性,以及富有表现力的API,用Ratpack快速开发高性能、可扩展的HTTP应用。
As usual, the example code can be found over on GitHub.
像往常一样,可以在GitHub上找到示例代码。