编辑此页面

使用带有 Multipart 的旧版 REST 客户端

本指南介绍了与RESTEasy Classic兼容的REST客户端的Multipart支持,该客户端曾是Quarkus 2.8之前的默认Jakarta REST(以前称为JAX-RS)实现。

现在建议使用Quarkus REST(以前称为RESTEasy Reactive),它同样很好地支持传统的阻塞式工作负载和响应式工作负载。有关Quarkus REST的更多信息,请参阅REST客户端指南,有关服务器端,请参阅REST JSON入门指南或更详细的Quarkus REST指南

RESTEasy对multipart/*multipart/form-data MIME类型具有丰富的支持。Multipart MIME格式用于传递内容体列表。多个内容体嵌入在一个消息中。multipart/form-data经常出现在Web应用程序HTML表单文档中,通常用于上传文件。form-data格式与其他multipart格式相同,不同之处在于每个内嵌的内容部分都与其关联了一个名称。

本指南将介绍如何使用RESTEasy REST客户端与Multipart配合,以非常轻松地与需要multipart/form-data内容类型的REST API进行交互。

先决条件

要完成本指南,您需要

  • 大约 15 分钟

  • 一个 IDE

  • 已安装 JDK 17+ 并正确配置了 JAVA_HOME

  • Apache Maven 3.9.9

  • 如果您想使用它,可以选择 Quarkus CLI

  • 如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置

解决方案

我们建议您按照以下章节中的说明,逐步创建应用程序。但是,您可以直接转到完整的示例。

克隆Git仓库:git clone https://github.com/quarkusio/quarkus-quickstarts.git,或下载一个存档

解决方案位于resteasy-client-multipart-quickstart 目录中。

创建 Maven 项目

首先,我们需要一个新项目。使用以下命令创建一个新项目

CLI
quarkus create app org.acme:resteasy-client-multipart-quickstart \
    --extension='resteasy-client,resteasy,resteasy-multipart' \
    --no-code
cd resteasy-client-multipart-quickstart

要创建 Gradle 项目,请添加 --gradle--gradle-kotlin-dsl 选项。

有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.24.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=resteasy-client-multipart-quickstart \
    -Dextensions='resteasy-client,resteasy,resteasy-multipart' \
    -DnoCode
cd resteasy-client-multipart-quickstart

要创建 Gradle 项目,请添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

对于 Windows 用户

  • 如果使用 cmd,(不要使用反斜杠 \ 并将所有内容放在同一行上)

  • 如果使用Powershell,请将-D参数括在双引号中,例如"-DprojectArtifactId=resteasy-client-multipart-quickstart"

此命令会生成一个包含REST端点的Maven项目,并导入resteasy-clientresteasy扩展。它还添加了resteasy-multipart扩展以支持multipart/form-data请求。

如果您已经配置了Quarkus项目,可以通过在项目根目录下运行以下命令将resteasy-multipart扩展添加到您的项目中

CLI
quarkus extension add resteasy-multipart
Maven
./mvnw quarkus:add-extension -Dextensions='resteasy-multipart'
Gradle
./gradlew addExtension --extensions='resteasy-multipart'

这会将以下内容添加到您的构建文件中

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy-multipart</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-resteasy-multipart")

设置模型

在本指南中,我们将演示如何调用接受multipart/form-data输入的REST服务。我们假设在发送请求之前载荷是已知的,因此我们可以将其建模为POJO。

如果载荷未知,您也可以使用RESTEasy自定义API。在这种情况下,请参阅指南末尾的RESTEasy Multipart Providers链接。

我们的首要任务是设置我们将用于定义MultipartBody POJO的multipart/form-data载荷的模型。

创建一个src/main/java/org/acme/rest/client/multipart/MultipartBody.java文件并包含以下内容

package org.acme.rest.client.multipart;

import java.io.InputStream;

import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.core.MediaType;

import org.jboss.resteasy.annotations.providers.multipart.PartType;

public class MultipartBody {

    @FormParam("file")
    @PartType(MediaType.APPLICATION_OCTET_STREAM)
    public InputStream file;

    @FormParam("fileName")
    @PartType(MediaType.TEXT_PLAIN)
    public String fileName;
}

上面代码中注解的目的是以下几点

  • @FormParam是一个标准的Jakarta REST注解,用于定义包含在请求实体体中的表单参数

  • @PartType是RESTEasy特定的注解,当客户端执行Multipart请求时需要,并定义部分的content type。

创建接口

使用RESTEasy REST客户端就像创建使用适当的Jakarta REST和MicroProfile注解的接口一样简单。在本例中,接口应在src/main/java/org/acme/rest/client/multipart/MultipartService.java中创建,并包含以下内容

package org.acme.rest.client.multipart;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;

@Path("/echo")
@RegisterRestClient
public interface MultipartService {

    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.TEXT_PLAIN)
    String sendMultipartData(@MultipartForm MultipartBody data);

}

sendMultipartData方法使我们的代码能够将multipart/form-data请求POST到我们的Echo服务(为演示目的,该服务运行在同一服务器上)。由于在本演示中我们确切地知道multipart/form-data数据包,我们可以使用@org.jboss.resteasy.annotations.providers.multipart.MultipartForm注解将其映射到上一节创建的模型类。

客户端将处理所有网络和编组,使我们的代码免于这些技术细节。

上面代码中注解的目的是以下几点

  • @RegisterRestClient 允许 Quarkus 知道此接口旨在作为 REST 客户端用于 CDI 注入

  • @Path@POST是用于定义如何访问服务的标准Jakarta REST注解

  • @MultipartForm将参数定义为multipart/form-data MIME类型的入站/出站请求/响应的值对象。

  • @Consumes定义此请求(参数)消耗的预期content-type

  • @Produces定义此请求(返回类型)产生的预期content-type

虽然@Consumes@Produces是可选的,因为支持自动协商,但强烈建议使用它们来注解您的端点,以精确定义预期的content-types。

这将允许缩小包含在原生可执行文件中的Jakarta REST提供商(可视为转换器)的数量。

创建配置

为了确定将进行 REST 调用的基本 URL,REST 客户端使用 application.properties 中的配置。属性的名称需要遵循一定的约定,最好在以下代码中显示

# Your configuration properties
quarkus.rest-client."org.acme.rest.client.multipart.MultipartService".url=https://:8080/

此配置意味着使用org.acme.rest.client.multipart.MultipartService执行的所有请求都将使用https://:8080/作为基础URL。

请注意,org.acme.rest.client.multipart.MultipartService必须与我们在上一节中创建的MultipartService接口的完全限定名称匹配。

创建 Jakarta REST 资源

创建src/main/java/org/acme/rest/client/multipart/MultipartClientResource.java文件,并包含以下内容

package org.acme.rest.client.multipart;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;

import jakarta.inject.Inject;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import org.eclipse.microprofile.rest.client.inject.RestClient;

@Path("/client")
public class MultipartClientResource {

    @Inject
    @RestClient
    MultipartService service;

    @POST
    @Path("/multipart")
    @Produces(MediaType.TEXT_PLAIN)
    public String sendFile() throws Exception {
        MultipartBody body = new MultipartBody();
        body.fileName = "greeting.txt";
        body.file = new ByteArrayInputStream("HELLO WORLD".getBytes(StandardCharsets.UTF_8));
        return service.sendMultipartData(body);
    }
}

请注意,除了标准的CDI @Inject注解外,我们还需要使用MicroProfile @RestClient注解来注入MultipartService

创建服务器

出于演示目的,让我们创建一个简单的Echo端点,它将作为服务器部分。

创建目录src/main/java/org/acme/rest/client/multipart/server并包含一个EchoService.java文件,其内容如下

package org.acme.rest.client.multipart.server;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/echo")
public class EchoService {

    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.TEXT_PLAIN)
    public String echo(String requestBody) throws Exception {
        return requestBody;
    }
}

这只会返回请求体,对于测试很有用。

更新测试

我们还需要更新功能测试以反映对端点所做的更改。编辑src/test/java/org/acme/rest/client/multipart/MultipartClientResourceTest.java文件以

package org.acme.rest.client.multipart;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;

@QuarkusTest
public class MultipartClientResourceTest {

    @Test
    public void testMultipartDataIsSent() {
        given()
                .when().post("/client/multipart")
                .then()
                .statusCode(200)
                .body( containsString("Content-Disposition: form-data; name=\"file\""),
                        containsString("HELLO WORLD"),
                        containsString("Content-Disposition: form-data; name=\"fileName\""),
                        containsString("greeting.txt"));
    }

}

上面的代码使用REST Assured来断言Echo服务返回的内容包含Multipart元素

由于测试运行在不同的端口,我们还需要在src/test/resources中包含一个application.properties文件,其内容如下

# Your configuration properties
quarkus.rest-client."org.acme.rest.client.multipart.MultipartService".url=https://:8081/

打包并运行应用程序

使用以下命令运行应用程序

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

在终端中,运行curl -X POST https://:8080/client/multipart

您应该看到类似以下的输出

--89d288bd-960f-460c-b266-64c5b4d170fa
Content-Disposition: form-data; name="fileName"
Content-Type: text/plain

greeting.txt
--89d288bd-960f-460c-b266-64c5b4d170fa
Content-Disposition: form-data; name="file"
Content-Type: application/octet-stream

HELLO WORLD
--89d288bd-960f-460c-b266-64c5b4d170fa--

与往常一样,可以使用以下命令打包应用程序

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

并使用 java -jar target/quarkus-app/quarkus-run.jar 执行。

您还可以使用以下命令生成原生可执行文件

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true

相关内容