4.3. 从 Java 对象提取至和进行 marshalling

marshalling Java 对象用于通过 HTTP 传输

使用 REST 协议的一个最常见方式是在消息正文中传输 Java bean 的内容。要实现此目的,您需要提供一种机制来将 Java 对象聚合到合适的数据格式中。REST DSL 支持下列数据格式,适用于编码 Java 对象:

JSON

JSON (JavaScript 对象表示法)是一种轻量级数据格式,可轻松映射到 Java 对象或从 Java 对象映射。JSON 语法紧凑,更轻易输入,便于人类读取和写入。由于所有这些原因,JSON 已成为 REST 服务的消息格式。

例如,以下 JSON 代码可以代表一个 User bean,其中有两个属性字段 idname

{
    "id" : 1234,
    "name" : "Jane Doe"
}
JAXB

JAXB (用于 XML 绑定的 Java 架构)是一个基于 XML 的数据格式,可轻松映射到 Java 对象和 Java 对象。要将 XML 整理到 Java 对象,还必须注解您要使用的 Java 类。

例如,以下 JAXB 代码可以代表一个 User bean,其中有两个属性字段 idname

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<User>
  <Id>1234</Id>
  <Name>Jane Doe</Name>
</User>
注意

从 Camel 2.17.0,JAXB 数据格式和类型转换器支持从 XML 转换到 POJO,用于使用 ObjectFactory 而不是 XmlRootElement 的类。另外,camel 上下文应包含 CamelJaxbObjectFactory 属性,值为 true。但是,由于优化了默认值是 false。

将 JSON 和 JAXB 与 REST DSL 集成

当然,您可以编写必要的代码,以自己将消息正文转换为和从 Java 对象转换。但是 REST DSL 提供了自动执行此转换的便利。特别是,将 JSON 和 JAXB 与 REST DSL 集成提供以下优点:

  • 自动执行 Java 对象以及从 Java 对象进行 marshalling (指定适当的配置)。
  • REST DSL 可以自动检测数据格式(JSON 或 JAXB),并执行适当的转换。
  • REST DSL 提供了一个抽象层,因此您写入的代码不特定于特定的 JSON 或 JAXB 实施。因此,您可以稍后切换实施,对应用程序代码有最小影响。

支持的数据格式组件

Apache Camel 提供了很多不同的 JSON 和 JAXB 数据格式。REST DSL 目前支持以下数据格式:

  • JSON

    • Jackson 数据格式(camel-jackson) (默认)
    • GSon 数据格式(camel-gson)
    • XStream 数据格式(camel-xstream)
  • JAXB

    • JAXB 数据格式(camel-jaxb)

如何启用对象 marshalling

要在 REST DSL 中启用对象 marshalling,请观察以下几点:

  1. 启用绑定模式,通过设置 bindingMode 选项(有多个级别,您可以在其中设置绑定模式)确保详情请查看 “配置绑定模式”一节
  2. 指定要转换为(或从)传入消息的 Java 类型,使用 type 选项(必需),并在传出消息中带有 outType 选项(可选)。
  3. 如果要将 Java 对象转换为 JAXB 数据格式或从 JAXB 数据格式转换,您必须记得使用适当的 JAXB 注释给 Java 类添加注解。
  4. 使用 jsonDataFormat 选项和/或 xmlDataFormat 选项(可以在 restConfiguration 构建器中指定),指定底层数据格式实现(或实现)。
  5. 如果您的路由以 JAXB 格式提供返回值,您通常应当将交换正文的 Out 消息设置为含有 JAXB 注解的类实例(一个 JAXB 元素)。如果您希望直接以 XML 格式提供 JAXB 返回值,但是,使用键 xml.out.mustBeJAXBElement 设置为 false (可以在 restConfiguration 构建器上指定)的 dataFormatProperty。例如,在 XML DSL 语法中:

    <restConfiguration ...>
      <dataFormatProperty key="xml.out.mustBeJAXBElement"
                          value="false"/>
      ...
    </restConfiguration>
  6. 将所需的依赖项添加到项目构建文件。例如,如果您使用 Maven 构建系统,且您使用 Jackson 数据格式,您将在 Maven POM 文件中添加以下依赖项:

    <?xml version="1.0" encoding="UTF-8"?>
    <project ...>
      ...
      <dependencies>
        ...
        <!-- use for json binding --> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jackson</artifactId> </dependency>
        ...
      </dependencies>
    </project>
  7. 将应用程序部署到 OSGi 容器时,请记得为您的所选数据格式安装必要功能。例如,如果您使用的是 Jackson 数据格式(默认),则通过输入以下 Karaf 控制台来安装 camel-jackson 功能:

    JBossFuse:karaf@root> features:install camel-jackson

    或者,如果您要部署到 Fabric 环境中,您可以将该功能添加到 Fabric 配置集中。例如,如果您使用配置集 MyRestProfile,您可以输入以下命令添加这个功能:

    JBossFuse:karaf@root> fabric:profile-edit --features camel-jackson MyRestProfile

配置绑定模式

bindingMode 选项默认为 off,因此您必须显式配置它,以便启用 Java 对象的 marshalling。TABLE 显示支持的绑定模式列表。

注意

从 Camel 2.16.3 开始,仅当 content-type 标头包含 jsonxml 时,从 POJO 到 JSon/JAXB 的绑定才会发生。这可让您在消息正文没有使用绑定时指定自定义 content-type。这很有用,例如,消息正文是一个自定义二进制有效负载。

表 4.2. REST DSL BInding Modes

绑定模式描述

off

关闭 (默认)绑定

auto

为 JSON 和/或 XML 启用绑定。在这个模式中,Camel auto-selects JSON 或 XML (JAXB)基于传入消息的格式。您不需要 同时启用多种数据格式,但:JSON 实施、XML 实施或两者都可以在类路径上提供。

json

仅针对 JSON 启用绑定。必须在 类路径上提供 JSON 实施(默认情况下,Camel 会尝试启用 camel-jackson 实施)。

xml

仅为 XML 启用绑定。必须在 类路径上提供 XML 实施(默认情况下,Camel 会尝试启用 camel-jaxb 实施)。

json_xml

为 JSON 和 XML 启用绑定。在这个模式中,Camel auto-selects JSON 或 XML (JAXB)基于传入消息的格式。您需要在类路径上提供两种数据格式。

在 Java 中,这些绑定模式值表示为以下枚举的实例:

org.apache.camel.model.rest.RestBindingMode

您可以在其中设置 绑定Mode 有几个不同级别,如下所示:

REST DSL 配置

您可以从 restConfiguration 构建器设置 bindingMode 选项,如下所示:

restConfiguration().component("servlet").port(8181).bindingMode(RestBindingMode.json);
服务定义基础部分

您可以在 rest () 关键字后立即设置 bindingMode 选项(在 verb 子句的前面),如下所示:

rest("/user").bindingMode(RestBindingMode.json).get("/{id}").VerbClause
verb 子句

您可以在 verb 子句中设置 bindingMode 选项,如下所示:

rest("/user")
    .get("/{id}").bindingMode(RestBindingMode.json).to("...");

Example

如需完整的代码示例,显示如何使用 REST DSL,将 Servlet 组件用作 REST 实施,请查看 Apache Camel camel-example-servlet-rest-blueprint 示例。您可以通过安装独立的 Apache Camel 分发版本 apache-camel-2.23.2.fuse-7_10_0-00018-redhat-00001.zip 可以找到此示例,该文件在 Fuse 安装的 extras/ 子目录中提供。

安装独立 Apache Camel 发布后,您可以在以下目录下找到示例代码:

ApacheCamelInstallDir/examples/camel-example-servlet-rest-blueprint

将 Servlet 组件配置为 REST 实施

camel-example-servlet-rest-blueprint 示例中,REST DSL 的底层实施由 Servlet 组件提供。Servlet 组件在 Blueprint XML 文件中配置,如 例 4.1 “为 REST DSL 配置 Servlet 组件” 所示。

例 4.1. 为 REST DSL 配置 Servlet 组件

<?xml version="1.0" encoding="UTF-8"?>
<blueprint ...>

  <!-- to setup camel servlet with OSGi HttpService -->
  <reference id="httpService" interface="org.osgi.service.http.HttpService"/>

  <bean class="org.apache.camel.component.servlet.osgi.OsgiServletRegisterer"
        init-method="register"
        destroy-method="unregister">
    <property name="alias" value="/camel-example-servlet-rest-blueprint/rest"/>
    <property name="httpService" ref="httpService"/>
    <property name="servlet" ref="camelServlet"/>
  </bean>

  <bean id="camelServlet" class="org.apache.camel.component.servlet.CamelHttpTransportServlet"/>
  ...
  <camelContext xmlns="http://camel.apache.org/schema/blueprint">

    <restConfiguration component="servlet"
                       bindingMode="json"
                       contextPath="/camel-example-servlet-rest-blueprint/rest"
                       port="8181">
      <dataFormatProperty key="prettyPrint" value="true"/>
    </restConfiguration>
    ...
  </camelContext>

</blueprint>

要使用 REST DSL 配置 Servlet 组件,您需要配置由以下三个层组成的堆栈:

REST DSL 层
REST DSL 层由 restConfiguration 元素配置,它通过将 component 属性设置为 servlet,从而与 Servlet 组件集成。
Servlet 组件层
Servlet 组件层作为类的实例实施,CamelHttpTransportServlet,其中示例实例具有 bean ID camelServlet
HTTP 容器层

Servlet 组件必须部署到 HTTP 容器中。Karaf 容器通常使用默认的 HTTP 容器(a Jetty HTTP 容器)配置,该容器监听端口 8181 上的 HTTP 请求。要将 Servlet 组件部署到默认的 Jetty 容器,您需要执行以下操作:

  1. 获取 OSGi 参考 org.osgi.service.http.HttpService OSGi 服务,其中该服务是标准的 OSGi 接口,提供对 OSGi 中默认 HTTP 服务器的访问。
  2. 创建 utility 类 OsgiServletRegister 的实例,以在 HTTP 容器中注册 Servlet 组件。OsgiServletRegister 类是一个实用程序,可以简化 Servlet 组件的生命周期。创建此类的实例时,它会自动调用 HttpService OSGi 服务的 registerServlet 方法;当实例销毁时,它会自动调用 unregister 方法。

所需的依赖项

这个示例有两个与 REST DSL 至关重要的依赖关系,如下所示:

Servlet 组件

提供 REST DSL 的底层实施。这在 Maven POM 文件中指定,如下所示:

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-servlet</artifactId>
  <version>${camel-version}</version>
</dependency>

在将应用程序捆绑包部署到 OSGi 容器前,您必须安装 Servlet 组件功能,如下所示:

JBossFuse:karaf@root> features:install camel-servlet
jackson 数据格式

提供 JSON 数据格式实施。这在 Maven POM 文件中指定,如下所示:

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-jackson</artifactId>
  <version>${camel-version}</version>
</dependency>

在将应用程序捆绑包部署到 OSGi 容器前,您必须安装 Jackson 数据格式功能,如下所示:

JBossFuse:karaf@root> features:install camel-jackson

用于响应的 Java 类型

示例应用重新传递 用户类型 对象,并在 HTTP 请求和响应消息中返回。User Java 类定义如 例 4.2 “JSON 响应的用户类” 所示。

例 4.2. JSON 响应的用户类

// Java
package org.apache.camel.example.rest;

public class User {

    private int id;
    private String name;

    public User() {
    }

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

User 类采用 JSON 数据格式相对简单的表示。例如,以 JSON 格式表示此类的典型实例是:

{
    "id" : 1234,
    "name" : "Jane Doe"
}

使用 JSON 绑定的 REST DSL 路由示例

本例中的 REST DSL 配置和 REST 服务定义在 例 4.3 “使用 JSON 绑定的 REST DSL 路由” 中显示。

例 4.3. 使用 JSON 绑定的 REST DSL 路由

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           ...>
  ...
  <!-- a bean for user services -->
  <bean id="userService" class="org.apache.camel.example.rest.UserService"/>

  <camelContext xmlns="http://camel.apache.org/schema/blueprint">

    <restConfiguration component="servlet"
                       bindingMode="json"
                       contextPath="/camel-example-servlet-rest-blueprint/rest"
                       port="8181">
      <dataFormatProperty key="prettyPrint" value="true"/>
    </restConfiguration>

    <!-- defines the REST services using the  base path, /user -->
    <rest path="/user" consumes="application/json" produces="application/json">
      <description>User rest service</description>

      <!-- this is a rest GET to view a user with the given id -->
      <get uri="/{id}" outType="org.apache.camel.example.rest.User">
        <description>Find user by id</description>
        <to uri="bean:userService?method=getUser(${header.id})"/>
      </get>

      <!-- this is a rest PUT to create/update a user -->
      <put type="org.apache.camel.example.rest.User">
        <description>Updates or create a user</description>
        <to uri="bean:userService?method=updateUser"/>
      </put>

      <!-- this is a rest GET to find all users -->
      <get uri="/findAll" outType="org.apache.camel.example.rest.User[]">
        <description>Find all users</description>
        <to uri="bean:userService?method=listUsers"/>
      </get>

    </rest>

  </camelContext>

</blueprint>

REST 操作

来自 例 4.3 “使用 JSON 绑定的 REST DSL 路由” 的 REST 服务定义以下 REST 操作:

GET /camel-example-servlet-rest-blueprint/rest/user/{id}
获取由 {id} 标识的用户的详细信息,其中以 JSON 格式返回 HTTP 响应。
PUT /camel-example-servlet-rest-blueprint/rest/user
创建一个新用户,其中用户详情包含在 PUT 消息的正文中,采用 JSON 格式进行编码(与 User 对象类型匹配)。
GET /camel-example-servlet-rest-blueprint/rest/user/findAll
获取所有用户的详细信息,其中 HTTP 响应作为用户数组返回,采用 JSON 格式。

调用 REST 服务的 URL

通过从 例 4.3 “使用 JSON 绑定的 REST DSL 路由” 检查 REST DSL 定义,您可以将所需的 URL 组合在一起,以调用每个 REST 操作。例如,要调用第一个 REST 操作,它会返回具有给定 ID 的用户的详细信息,其 URL 构建如下:

http://localhost:8181
restConfiguration 中,协议默认为 http,端口被明确设置为 8181
/camel-example-servlet-rest-blueprint/rest
restConfiguration 元素的 contextPath 属性指定。
/user
rest 元素的 path 属性指定。
/{id}
get verb 元素的 uri 属性指定。

因此,可以在命令行中输入以下命令来使用 curl 程序调用这个 REST 操作:

curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/123

同样,可以通过 curl 命令调用剩余的 REST 操作,方法是输入以下示例命令:

curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/findAll

curl -X PUT -d "{ \"id\": 666, \"name\": \"The devil\"}" -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user