Introduction to Jooby – 乔比简介

最后修改: 2017年 7月 30日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Jooby is a scalable and fast micro web framework build on top of the most used NIO web servers. It’s very straightforward and modular, clearly designed for the modern day’s web architecture. It comes with support for Javascript and Kotlin too.

Jooby是一个可扩展和快速的微型网络框架,建立在最常用的NIO网络服务器之上。它是非常直接和模块化的,显然是为现代的网络架构设计的。它也支持JavascriptKotlin

By default, Jooby comes with great support for Netty, Jetty, and Undertow.

默认情况下,JoobyNetty、Jetty和Undertow提供了极大的支持。

In this article, we’ll learn about overall Jooby project structure and how to build a simple web application using Jooby.

在这篇文章中,我们将了解整体的Jooby项目结构,以及如何使用Jooby构建一个简单的Web应用程序。

2. Application Architecture

2.应用架构

A simple Jooby application structure will like below:

一个简单的Jooby应用结构如下。

├── public
|   └── welcome.html
├── conf
|   ├── application.conf
|   └── logback.xml
└── src
|   ├── main
|   |   └── java
|   |       └── com
|   |           └── baeldung
|   |               └── jooby
|   |                   └── App.java
|   └── test
|       └── java
|           └── com
|               └── baeldung
|                   └── jooby
|                       └── AppTest.java
├── pom.xml

Point to note here is that in public directory we can put static files like css/js/html etc. In the conf directory, we can put any configuration file that an application needs like logback.xml or application.conf etc.

这里需要注意的是,在public目录下,我们可以放置静态文件,如css/js/html等。在conf目录下,我们可以放任何应用程序需要的配置文件,如logback.xmlapplication.conf等。

3. Maven Dependency

3.Maven的依赖性

We can create a simple Jooby application by adding the following dependency into our pom.xml:

我们可以创建一个简单的Jooby应用程序,在我们的pom.xml中添加以下依赖关系:

<dependency>
    <groupId>org.jooby</groupId>
    <artifactId>jooby-netty</artifactId>
    <version>1.1.3</version>
</dependency>

If we want to choose Jetty or Undertow we can use the following dependency:

如果我们想选择JettyUndertow,我们可以使用以下依赖关系。

<dependency>
    <groupId>org.jooby</groupId>
    <artifactId>jooby-jetty</artifactId>
    <version>1.1.3</version>
</dependency>
<dependency>
    <groupId>org.jooby</groupId>
    <artifactId>jooby-undertow</artifactId>
    <version>1.1.3</version>
</dependency>

You can check the latest version of the Jooby project in the Central Maven Repository.

您可以在Central Maven Repository中查看Jooby项目的最新版本。

Jooby also has a dedicated Maven archetype. We can use it to create a sample project with all necessary dependencies pre-built.

Jooby也有一个专门的Maven原型。我们可以用它来创建一个预置了所有必要依赖项的样本项目。

We can use the following script to generate the sample project:

我们可以使用下面的脚本来生成示例项目。

mvn archetype:generate -B -DgroupId=com.baeldung.jooby -DartifactId=jooby 
-Dversion=1.0 -DarchetypeArtifactId=jooby-archetype 
-DarchetypeGroupId=org.jooby -DarchetypeVersion=1.1.3

4. Building an Application

4.建立一个应用程序

4.1. Initiating the Server

4.1.启动服务器

To start the embedded server, we need to use following code snippet:

要启动嵌入式服务器,我们需要使用以下代码段。

public class App extends Jooby {
    public static void main(String[] args) {
        run(App::new, args);
    }
}

Once started the server will be running on default port 8080.

一旦启动,服务器将运行在默认端口 8080

We can also configure the back-end server with custom port and custom HTTPS port:

我们还可以用自定义端口和自定义HTTPS端口配置后端服务器。

{
    port( 8081 );
    securePort( 8443 );
}

4.2. Implementing the Router

4.2.实施路由器

It’s very easy to create path based router in Jooby. For example, we can create a router for path ‘/login‘ in following way:

Jooby中创建基于路径的路由器非常容易。例如,我们可以通过以下方式为路径”/login“创建一个路由器。

{
    get( "/login", () -> "Hello from Baeldung");
}

In a similar way, if we want to handle other HTTP methods like POST, PUT, etc we can use below code snippet:

以类似的方式,如果我们想处理其他HTTP方法,如POST、PUT等,我们可以使用以下代码片段。

{
    post( "/save", req -> {
        Mutant token = req.param( "token" );
        return token.intValue();
    });
}

Here, we’re fetching the request param name token from the request. By default, all request params are type-casted into Jooby‘s Mutant data type. Based on the expectation, we can convert it into any supported primitive data type.

在这里,我们要从请求中获取请求参数名称令牌。默认情况下,所有请求参数都被类型化为Joobya href=”https://javadoc.io/static/org.jooby/jooby/1.2.3/org/jooby/Mutant.html”>Mutant数据类型。根据期望值,我们可以将其转换为任何支持的原始数据类型。

We can check any url param in following way:

我们可以通过以下方式检查任何URL参数。

{
    get( "/user/{id}", req -> "Hello user : " + req.param("id").value() );
    get( "/user/:id", req -> "Hello user: " + req.param("id").value() );
}

We can use any of the above. It’s also possible to find params starting with a fixed content. For example, we can find a URL parameter starting with ‘uid:’ in following way:

我们可以使用上述的任何一种方式。也可以找到以固定内容开头的参数。例如,我们可以通过以下方式找到一个以’uid:’ 开头的URL参数。

{
    get( "/uid:{id}", req -> "Hello User with id : uid" + 
        req.param("id").value());
}

4.3. Implementing MVC Pattern Controller

4.3.实现MVC模式的控制器

For an enterprise application, Jooby comes with an MVC API much like any other MVC frameworks like Spring MVC.

对于企业应用程序来说,Jooby带有一个MVC API,与Spring MVC等其他MVC框架一样。

For example, we can handle a path called ‘/hello‘ :

例如,我们可以处理一个名为’/hello‘的路径。

@Path("/hello")
public class GetController {
    @GET
    public String hello() {
        return "Hello Baeldung";
    }
}

Very similarly we can create a handler to handle other HTTP methods with @POST, @PUT, @DELETE, etc. annotation.

非常类似地,我们可以创建一个处理程序来处理其他的HTTP方法,使用@POST, @PUT, @DELETE, 等注释。

4.4. Handling Static Content

4.4.处理静态内容

To serve any static content like HTML, Javascript, CSS, image, etc., we need to place those file in the public directory.

要提供任何静态内容,如HTML、Javascript、CSS、图像等,我们需要将这些文件放在public目录中。

Once placed, from the router we can map any url to these resources:

一旦放置好,我们可以从路由器上将任何网址映射到这些资源。

{
    assets( "/employee" , "form.html" );
}

4.5. Handling Form

4.5.处理表格

Jooby’s Request interface by default handles any form object without using any manual type casting.

Jooby的Request接口默认处理任何表单对象,无需使用任何手动类型转换。

Let’s assume we need to submit employee details through a form. At first step, we need to create an Employee bean object that we will use to hold the data:

让我们假设我们需要通过一个表单来提交雇员的详细信息。第一步,我们需要创建一个Employee bean对象,我们将用它来保存数据。

public class Employee {
    String id;
    String name;
    String email;

    // standard constructors, getters and setters
}

Now, we need to create a page to create the form:

现在,我们需要创建一个页面来创建表单。

<form enctype="application/x-www-form-urlencoded" action="/submitForm" 
    method="post">
    <input name="id" />
    <input name="name" />
    <input name="email" />
    <input type="submit" value="Submit"/>
</form>

Next, we’ll create a post handler to address this form and fetch the submitted data:

接下来,我们将创建一个帖子处理程序来处理这个表单并获取提交的数据。

post( "/submitForm", req -> {
    Employee employee = req.params(Employee.class);
    // ...
    return "empoyee data saved successfullly";
});

Point to note here is that we must need to declare form enctype as application/x-www-form-urlencoded to support the dynamic form binding.

这里需要注意的是,我们必须将表单enctype声明为application/x-www-form-urlencoded以支持动态表单绑定。

By Request.file(String filename) we can retrieve the uploaded file:

通过Request.file(String filename)我们可以检索到上传的文件。

post( "/upload", req -> {
    Upload upload = req.file("file");
    // ...
    upload.close();
});

4.6. Implementing a Filter

4.6.实现一个过滤器

Out of the box, Jooby provides the flexibility to define global filters as well as the path-based filters.

开箱即用,Jooby提供了定义全局过滤器和基于路径的过滤器的灵活性。

Implementing filter in Jooby is a little bit tricky since we need to configure the URL path twice, once for the filter and once again for the handler.

Jooby中实现过滤器有点棘手,因为我们需要配置两次URL路径,一次用于过滤器,另一次用于处理器。

For example, if we have to implement a filter for a URL path called ‘/filter’, we need to implement the filter in this path explicitly:

例如,如果我们要为一个名为’/filter’的URL路径实现一个过滤器,我们需要在这个路径中明确实现过滤器。

get( "/filter", ( req, resp, chain ) -> {
    // ...
    chain.next( req, resp );
});

The syntax is very similar to Servlet filter. It’s possible to restrict the request and send back the response in the filter itself by calling Response.send(Result result) method.

其语法与Servlet过滤器非常相似。通过调用 Response.send(Result result)方法,可以在过滤器本身中限制请求并送回响应。

Once the filter is implemented, we need to implement the request handler:

一旦实现了过滤器,我们就需要实现请求处理程序。

get("/filter", (req, resp) -> {
    resp.send("filter response");
});

4.7. Session

4.7.会议

Jooby comes with two types of session implementation; in-memory and cookie-based.

Jooby带有两种类型的会话实现;内存中和基于cookie。

Implementing in-memory session management is quite simple. We have the options to choose any of the high-throughput session stores available with Jooby like EhCache, Guava, HazleCast, Cassandra, Couchbase, Redis, MongoDB, and Memcached.

实施内存会话管理是非常简单的。我们可以选择Jooby提供的任何高吞吐量会话存储,如EhCache、Guava、HazleCast、Cassandra、Couchbase、Redis、MongoDBMemcached。

For example, to implement a Redis-based session storage, we need to add following Maven dependency:

例如,为了实现基于Redis的会话存储,我们需要添加以下Maven依赖。

<dependency>
    <groupId>org.jooby</groupId>
    <artifactId>jooby-jedis</artifactId>
    <version>1.1.3</version>
</dependency>

Now we can use below code snippet to enable session management:

现在我们可以使用下面的代码片断来启用会话管理。

{
    use(new Redis());
    session(RedisSessionStore.class);

    get( "/session" , req -> {
        Session session = req.session();
        session.set("token", "value");
        return session.get("token").value();
    });
}

Point to note here is that we can configure Redis url as the ‘db’ property in the application.conf.

这里需要注意的是,我们可以在application.conf中配置Redis网址作为‘db’属性。

To enable cookie based session management, we need to declare cookieSession(). If cookie based approach is selected, we must need to declare application.secret property in the application.conf file. Since each cookie will be signed will be signed with this secret key, it’s always advisable to use long random string fragment as a secret key.

为了启用基于cookie的会话管理,我们需要声明cookieSession()如果选择基于cookie的方法,我们必须需要在application.conf文件中声明application.secret属性。由于每个cookie都将用这个秘密密钥进行签名,因此建议使用长的随机字符串片段作为秘密密钥。

In both in-memory and cookie based approach, we must have to declare the necessary configuration parameter in the application.conf file, else the application will throw an IllegalStateException at start up.

在基于内存和cookie的方法中,我们必须在application.conf文件中声明必要的配置参数,否则应用程序在启动时将抛出IllegalStateException

5. Testing

5.测试

Testing MVC route is indeed easy since a route is bound to a strategy for some class. This makes it easy to run unit tests against all routes.

测试MVC路由确实很容易,因为一个路由被绑定到某个类的策略上。这使得针对所有路由运行单元测试变得很容易。

For example, we can quickly create a test-case for default URL:

例如,我们可以快速创建一个默认URL的测试案例。

public class AppTest {
 
    @ClassRule
    public static JoobyRule app = new JoobyRule(new App());

    @Test
    public void given_defaultUrl_expect_fixedString() {
 
        get("/").then().assertThat().body(equalTo("Hello World!"))
          .statusCode(200).contentType("text/html;charset=UTF-8");
    }
}

Point to note here is that using @ClassRule annotation will create only one instance of the server for all test-cases. If we need to build separate instances of the servers for every test-cases we have to use the @Rule annotation without the static modifier.

这里需要注意的是,使用@ClassRule注解将为所有测试用例创建一个服务器实例。如果我们需要为每个测试案例建立单独的服务器实例,我们必须使用@Rule注解,而不使用静态修改器。

We can also use Jooby’s MockRouter to test the path in the same way:

我们也可以使用Jooby的MockRouter,以同样的方式测试路径。

@Test
public void given_defaultUrl_with_mockrouter_expect_fixedString() 
  throws Throwable {
 
    String result = new MockRouter(new App()).get("/");
 
    assertEquals("Hello World!", result);
}

6. Conclusion

6.结论

In this tutorial, we explored the Jooby project and its essential functionality.

在本教程中,我们探讨了Jooby项目及其基本功能。

Like always, the full source code is available over on GitHub.

像往常一样,完整的源代码可以在GitHub上找到