使用 Apache Camel 创建 REST 服务

使用 Apache Camel 创建 REST 服务

让我们使用 Camel 的 REST DSL 创建一个 REST 服务!请参阅使用 Apache Camel 和 Spring Boot 实现 REST API 的示例。

使用 Apache Camel 创建 REST 服务

您已经了解了Apache Camel 的一些基础知识。您现在知道如何处理消息。伟大的!下一个是什么?

您可能想要开始使用 Web 服务。

因此,在本教程中,我将展示如何使用 Camel从应用程序公开 REST 端点

我将介绍您开始所需的依赖项和配置。最后,有一个示例供您参考,以便您了解如何使用 Apache Camel 和 Spring Boot 创建自己的 RESTful 服务。

如果您不熟悉 Apache Camel,那么我鼓励您阅读我的Apache Camel 教程的第一部分。

基础知识

如何使用 Camel 创建 REST 服务?

您现在可能已经知道 Camel 是一个用于在不同系统之间进行集成的框架。它通常不会自己做一些事情,而是创建和配置一些实际完成工作的东西(例如一个组件)。

在 Camel 中创建 REST 服务遵循几乎相同的模式。为 Camel 编写一些说明,它将使用一堆其他组件为您公开您的 REST 服务。您只需要准确选择您希望服务实现的方式,Camel 将负责配置。

这意味着使用 Camel 创建 REST 服务有无数种不同的方式。因此,我不会涵盖每一种不同的方法,而只是简要提及您可以在 Apache Camel 中使用 REST 服务的主要方法。你可以:

  • 使用 Camel 支持的组件之一公开一个 REST 服务:您使用 Camel 的 REST DSL 或 REST 组件定义您的 REST 服务操作,并选择一个将被配置为实现您的服务的组件。然后,Camel 将使用该信息来引导组件、创建您的服务及其操作、将其部署到 Web 服务器(如 Jetty 或 Undertow)中,并为您生成 Swagger/OpenAPI 文档。(这非常简单,这就是我将在本教程中介绍的方式。)

  • 使用 Camel 来引导使用 JAX-RS 的服务: Camel 与 Apache CXF 紧密集成,这是 Java 的Web 服务JAX-RS 规范的一种实现。因此,如果您正在考虑使用 JAX-RS 标准来定义您的 REST 服务,那么您可以使用 Camel 使用 CXF 为您引导您的服务。查看CXFRS 组件以获取更多信息。

  • 使用 Camel 为现有的 REST 服务提供业务逻辑:如果您已经在应用程序的其他地方公开了 REST 服务——例如使用JAX-RS或 Spring Rest——那么您可以使用 Camel 来实现实际的业务逻辑,如果你喜欢。

    例如,您可能已经编写了一个包含使用javax.ws.rs注释(@Path@GET@POST等)注释的方法的服务类,并且已经配置了您的实现(例如 CXF、Jersey 或 Resteasy)。如果是这样,那么在您的服务方法中,您可以使用 Camel 的 Java API(ProducerTemplate等)将消息发送到 Camel 路由,然后使用来自 Camel 的响应传递回您的使用者。

那么有没有“最好的方法”呢?

嗯,不。:)

但在本教程中,我将向您展示我的首选方法。我们将使用 Camel 的 REST DSL 来配置服务并将其部署到嵌入式 Web 服务器中,该服务器在 Spring Boot 中运行。

使用 REST DSL 创建 REST 服务

那么如何在 Camel 中定义 REST 服务呢?最好的方法是使用 REST DSL。

REST DSL 是 Camel 现有路由构建语法的扩展,但专门用于描述 REST 服务。编写和配置很容易。

在幕后,Camel 使用您的 REST DSL 代码来配置实际提供REST 服务的底层组件。您现在不需要担心这些细节,因为 Camel 会为您设置大部分默认值。

REST DSL 可以轻松定义 REST 服务,而无需了解太多底层细节或任何复杂的布线。

在非常高的层次上,当使用 Camel 创建 REST 服务时,我们需要做以下事情:

  1. 声明我们的 RESTful 服务的端点和操作

  2. 选择哪个组件将实现该服务(有关支持的组件列表,请参见下文)

  3. 添加代码以使用参数

  4. 添加配置以获取 Camel 以帮助我们处理 JSON 或 XML。

定义endpoints端点和操作

为了定义我们服务的操作,我们可以使用 REST DSL 语法。Camel在 Camel 2.14 中引入了REST DSL。REST DSL 基本上是用于定义 REST 服务的 Camel 语法。

看起来有点像普通的Camel route…… 除了它以rest(). 定义您使用的服务,rest(...)然后是您的操作,其采用 HTTP 动词的形式,例如.get().post()等。

在 Java DSL 中,它看起来像这样:

rest("/api/customers")
    .get()
        .route()
        .to("direct:getCustomers")
    .post()
        .route()
        .to("file:output/customers");

在 Camel 的 XML DSL 中:

<rest path="/api/customers">
    <get>
        <route>
            <to uri="direct:getCustomers"/>
        </route>
    </get>
    <post>
        <route>
            <to uri="file:output/customers"/>
        </route>
    </post>
</rest>

REST 消费者还是 REST 生产者?当 Camel 公开或提供 REST 服务时,Camel 使用术语consumer,因为 Camel 正在通过 REST 消费提供给它的数据。另一方面,REST生产者是 Camel 消费或调用外部 REST 服务的地方。

配置实现

现在我们需要设置一些关于服务本身的信息。我们需要选择哪个组件将实现服务,并设置任何属性,如主机名端口

第一件事是选择 Camel 应该引导哪个组件来实现您的 REST 服务。在这里,您可以选择:

  • servlet

  • spark-rest

  • netty-http

  • jetty

选择哪个组件完全取决于您,但是对于 Spring Boot 应用程序,我会选择servlet,因为您已经拥有一个 Camel 可以用于 servlet (Tomcat) 的嵌入式 Web 服务器。

然后您可以在restConfiguration()块中设置此配置,如下所示:

// 定义实现组件 - 并接受默认主机和端口
restConfiguration().component("servlet");
​
// 定义组件和主机名和端口
restConfiguration().component("servlet")
    .host("localhost").port(8080);

使用参数

您的 REST API 可能需要接受来自使用者的参数。无论您是在正文、URL 还是在查询字符串中使用参数,都可以轻松做到这一点。

POST 正文

像POST这样的操作很容易。请求的正文将存储在 Camel Exchange Body 中。所以你可以像这样访问它:

rest("/customers")
    .post().log("The body is ${body}!");

网址参数

当您需要从 URL 中读取参数(例如客户 ID 或产品 ID)时,您需要:

  • 在您的操作的 URI 中定义一个占位符,例如/customers/{id}

  • 稍后获取您的输入,使用同名的Header - 例如${header.id}

这是一个示例 - 一个采用客户 ID 的 REST 删除操作。该参数{id}在声明uri-如/customers/12345。然后可以使用${header.id}以下方法检索它:

Java DSL

rest("/api/apartments")
    .get("/search?country={country}")
    .to("bean:searchBean?method=byCountry(${header.country})");

XML DSL

<rest path="/api/apartments">
    <get uri="/search?country={country}">
        <to uri="bean:searchBean?method=byCountry(${header.country})"/>
    </get>
</rest>

设置 JSON 到 POJO 转换

最后,我们需要弄清楚我们想要对我们的请求和响应消息做什么。如果您正在接收或发送 JSON,那么 Camel 如何提供帮助?

您可以手动编写自己的 JSON 字符串,但它非常麻烦,而且编写一大堆字符串连接也没什么乐趣!

答案是对您的请求和响应类型使用 POJO。是的,Java 对象。当您将 POJO 用于输入和输出消息时,Camel 可以为您的 REST 服务使用者轻松地将这些消息与 JSON 进行相互转换。如果 Jackson 在类路径上,Camel 能够做到这一点。

这是一个示例供您查看。首先,这是我编写的一个名为ResponseType的类,它对来自我的 RESTful API 的响应进行建模。它包含一个字段,message

public class ResponseType {
​
    private String message;
​
    public ResponseType(String message) {
        this.message = message;
    }
​
    public String getMessage() { }
        return message;
    }
​
    public void setMessage(String message) {
        this.message = message;
    }
}

为了让 Camel 自动将其从我的 REST 服务编组为 JSON,我确保.outType()设置了它,并且它引用了我的自定义ResponseType类。这告诉 Camel 它应该期望将类型为ResponseType的消息返回给消费者:

rest().path("/my-api").....
    .get()
        .outType(ResponseType.class)
        .to("bean:helloBean"); // this sends the Body to the bean

由于我的 REST 操作的业务逻辑是在 Java bean 中实现的,我只需要确保我的业务逻辑方法返回一个类型为ResponseType的对象:

public class HelloBean {
    public ResponseType sayHello() {
        return new ResponseType("Hello, world!");
    }
}

最后,我需要给 Camel 一个提示,将 JSON 绑定到 Java 对象。这是使用bindingMode配置完成的,我添加到restConfiguration块中:

restConfiguration()
    .component("servlet")
    .bindingMode(RestBindingMode.auto);

或者,如果您愿意,可以在 XML DSL 中:

<restConfiguration component="servlet" bindingMode="auto"/>

现在,当我使用curl测试服务时,HelloBean将返回一个ResponseType对象。Camel 将使用 Jackson 为我自动将其编组为 JSON - 请注意我如何获得包含一个字段 的 JSON 对象message,这就像我上面的示例 POJO:

$ curl http://localhost:8080/services/my-api
{"message":"Hello, world!"}

示例 - 使用 REST DSL 在 Camel 中创建RESTful 服务

现在我们知道使用 Camel 创建 RESTful 服务需要什么——一个将实现服务的组件,以及一些 REST DSL 糖来配置它。这个例子将:

  • 使用servlet组件托管 RESTful 服务

  • 在默认的 Spring Boot Web 端口上运行,即 8080

  • 在 JSON 和 Java 对象之间自动转换,这样我们就不必自己搞砸了

要创建服务,请按照下列步骤操作:

  1. 创建一个新的 Camel Spring Boot 项目

  2. 在您的 Maven POM 中,添加camel-servlet-starter为依赖项。这将允许 Camel 将我们的服务部署到嵌入式 Tomcat 容器中:

     <dependency>
     <groupId>org.apache.camel.springboot</groupId>
     <artifactId>camel-servlet-starter</artifactId>
     </dependency>
  3. 添加camel-jackson-starter为依赖项。这将允许 Camel 编组到/从 JSON:

     <dependency>
     <groupId>org.apache.camel.springboot</groupId>
     <artifactId>camel-jackson-starter</artifactId>
     </dependency>
  4. RouteBuilder新项目的 中,添加一个restConfiguration()元素。

    这将初始化将提供REST 服务的组件。在这个例子中,我们为此使用了Servlet组件。

    在为服务定义任何操作之前,我们首先执行此操作:

     public void configure() throws Exception {
     restConfiguration()
           .component("servlet")
           .bindingMode(RestBindingMode.auto);
     }
  5. 定义一个 REST 端点,并为您的每个操作(GET、POST 等)添加框架。

    首先,使用服务的路径 (URI)定义 REST 端点rest。然后附加您的每个操作- 这些是您的 HTTP 动词。

    REST 动词/操作的语法看起来就像熟悉的 Camel 路由。但是,from我们使用您要使用的HTTP 动词(例如getpost和 )开始每个操作,而不是delete

    像这样做:

    语言语言

     rest("/api/customers")
         .get().route().to("...")
         .post().route().to("...")
         .delete().route().to("...");

    XML DSL

    <rest path="/api/customers">
       <get>
         <route>
             <to uri="..."/>
         </route>
       </get>
       <post>
         <route>
             <to uri="..."/>
         </route>
       </post>
     </rest>

    该在什么时候使用哪个 HTTP 动词上?看到这篇文章的结尾,我写了一个厚颜无耻的小备忘单。

  6. 现在为您的 REST 操作构建您的骆驼路线!以下是已填写的 REST 服务示例:

    Java DSL

     rest("/customers")
     .get().route().to("bean:customerService?method=listCustomers")
     .post().route().to("jms:queue:CUSTOMERS");

    XML DSL

     <rest path="/customers">
     <get>
       <route>
           <to uri="bean:customerService?method=listCustomers"/>
       </route>
     </get>
     <post>
       <route>
           <to uri="direct:post"/>
       </route>
     </post>
     </rest>

    正如你所看到的,GET操作通过一个beancustomerService传递服务的请求。但是POST操作将请求传递给一个直接分量direct:post

  7. 要添加对自动将请求和响应转换为 JSON 的支持,请定义代表您的请求和响应消息的 POJO,例如:

     public class CreateCustomerResponse {
     private String result;
     // Add some getters and setters here...
     }

    现在,声明您的请求和响应类型,以便 Camel 知道如何将它们编组到 JSON 或从 JSON 编组:

     rest()
       .post()
         .route()
         .type(Customer.class)
         .outType(CreateCustomerResponse.class)
         .to("direct:post");

    并确保您已在REST 配置中设置绑定模式

     restConfiguration()
         .component("servlet")
         .bindingMode(RestBindingMode.auto);
    就是这样!现在继续使用您需要的尽可能多的端点和操作来构建您的 REST API。

只是想看看完整的、有效的例子?单击下面的按钮查看完整示例:

获取示例代码 在 GitHub 上

HTTP 动词何时使用例子
GET 获取/检索实体 GET /customers/:id
POST 创建一个新实体 POST /customers
PUT 更新现有实体 PUT /customers/:id/tags
DELETE 删除现有实体 DELETE /customers/:id
posted @ 2021-09-26 15:45  yiwenzhang  阅读(4686)  评论(0编辑  收藏  举报