Java 我是否可以在同一RESTAPI响应中发送一个excel文件和JSON正文,其中包含文件的描述

Java 我是否可以在同一RESTAPI响应中发送一个excel文件和JSON正文,其中包含文件的描述,java,rest,web-services,jersey,Java,Rest,Web Services,Jersey,我有一个API,它返回应用程序作为媒体类型的八位字节流作为响应。我需要对其进行增强,以发送一个JSON正文,其中包含有关该文件的一些详细信息,例如文件中正确记录和错误记录的计数。所以基本上我需要在同一个API中有两种响应。这可行吗?这是可能的,但您需要使用多部分响应。请记住,有些客户端将无法处理这种类型的响应。您通常会在上传文件时看到此数据类型,但不经常用作响应数据类型 Response res = target("test").request().get(); FormDataMultiPar

我有一个API,它返回应用程序作为媒体类型的八位字节流作为响应。我需要对其进行增强,以发送一个JSON正文,其中包含有关该文件的一些详细信息,例如文件中正确记录和错误记录的计数。所以基本上我需要在同一个API中有两种响应。这可行吗?

这是可能的,但您需要使用多部分响应。请记住,有些客户端将无法处理这种类型的响应。您通常会在上传文件时看到此数据类型,但不经常用作响应数据类型

Response res = target("test").request().get();
FormDataMultiPart multiPart = res.readEntity(FormDataMultiPart.class);
FormDataBodyPart jsonPart = multiPart.getField("json-data");
FormDataBodyPart filePart = multiPart.getField("file-data");

Model jsonData = jsonPart.getValueAs(Model.class);
InputStream file = filePart.getValueAs(InputStream.class);
话虽如此,下面是一个使用的完整示例。在资源中,使用Jersey的
FormDataMultiPart

@Path("test")
public static class TestResource {
    @GET
    @Produces(MediaType.MULTIPART_FORM_DATA)
    public Response get() throws Exception {
        final MultiPart multiPart = new FormDataMultiPart()
                .field("json-data", new Model("Test Value"), MediaType.APPLICATION_JSON_TYPE)
                .bodyPart(new FileDataBodyPart("file-data", new File("test.txt")));
        return Response.ok(multiPart).build();
    }
}
要使测试成功,您应该在文件的第一行有一个名为
test.txt
的文件,其内容为“文件中的某些测试数据”(不带引号)。这个多部分响应有两部分,一部分是
json数据
部分,它使用
Model
类对json进行建模,另一部分是
文件数据
部分,它包含文件的内容

为了使多部分工作,我们需要在服务器和客户端注册
MultiPartFeature
(用于客户端反序列化),并且我们需要在项目中具有多部分依赖性

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
    <version>${jersey2.version}</version>
</dependency>
下面是完整的测试

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;

import static org.assertj.core.api.Assertions.assertThat;

public class MultipartResponseTest extends JerseyTest {

    public static class Model {
        private String value;
        public Model() {}
        public Model(String value) {
            this.value = value;
        }
        public String getValue() {
            return this.value;
        }
        public void setValue(String value) {
            this.value = value;
        }
    }

    @Path("test")
    public static class TestResource {
        @GET
        @Produces(MediaType.MULTIPART_FORM_DATA)
        public Response get() throws Exception {
            final MultiPart multiPart = new FormDataMultiPart()
                    .field("json-data", new Model("Test Value"), MediaType.APPLICATION_JSON_TYPE)
                    .bodyPart(new FileDataBodyPart("file-data", new File("test.txt")));
            return Response.ok(multiPart).build();
        }
    }

    @Override
    public ResourceConfig configure() {
        return new ResourceConfig()
                .register(TestResource.class)
                .register(MultiPartFeature.class);
    }

    @Override
    public void configureClient(ClientConfig config) {
        config.register(MultiPartFeature.class);
    }

    @Test
    public void testIt() throws Exception {
        final Response res = target("test")
                .request().get();
        FormDataMultiPart multiPart = res.readEntity(FormDataMultiPart.class);
        FormDataBodyPart jsonPart = multiPart.getField("json-data");
        FormDataBodyPart filePart = multiPart.getField("file-data");

        Model jsonData = jsonPart.getValueAs(Model.class);
        InputStream file = filePart.getValueAs(InputStream.class);

        BufferedReader fileReader = new BufferedReader(new InputStreamReader(file));
        String fileData = fileReader.readLine();

        file.close();
        fileReader.close();

        System.out.println(jsonData.getValue());
        System.out.println(fileData);

        assertThat(jsonData.getValue()).isEqualTo("Test Value");
        assertThat(fileData).isEqualTo("Some Test Data in File");
    }
}
要使用测试框架,您应该添加以下依赖项

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>${jersey2.version}</version>
</dependency>

org.glassfish.jersey.test-framework.providers
jersey-test-framework-provider-grizzly2
${jersey2.version}

这是可能的,但您需要使用多部分响应。请记住,有些客户端将无法处理这种类型的响应。您通常会在上传文件时看到此数据类型,但不经常用作响应数据类型

Response res = target("test").request().get();
FormDataMultiPart multiPart = res.readEntity(FormDataMultiPart.class);
FormDataBodyPart jsonPart = multiPart.getField("json-data");
FormDataBodyPart filePart = multiPart.getField("file-data");

Model jsonData = jsonPart.getValueAs(Model.class);
InputStream file = filePart.getValueAs(InputStream.class);
话虽如此,下面是一个使用的完整示例。在资源中,使用Jersey的
FormDataMultiPart

@Path("test")
public static class TestResource {
    @GET
    @Produces(MediaType.MULTIPART_FORM_DATA)
    public Response get() throws Exception {
        final MultiPart multiPart = new FormDataMultiPart()
                .field("json-data", new Model("Test Value"), MediaType.APPLICATION_JSON_TYPE)
                .bodyPart(new FileDataBodyPart("file-data", new File("test.txt")));
        return Response.ok(multiPart).build();
    }
}
要使测试成功,您应该在文件的第一行有一个名为
test.txt
的文件,其内容为“文件中的某些测试数据”(不带引号)。这个多部分响应有两部分,一部分是
json数据
部分,它使用
Model
类对json进行建模,另一部分是
文件数据
部分,它包含文件的内容

为了使多部分工作,我们需要在服务器和客户端注册
MultiPartFeature
(用于客户端反序列化),并且我们需要在项目中具有多部分依赖性

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
    <version>${jersey2.version}</version>
</dependency>
下面是完整的测试

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;

import static org.assertj.core.api.Assertions.assertThat;

public class MultipartResponseTest extends JerseyTest {

    public static class Model {
        private String value;
        public Model() {}
        public Model(String value) {
            this.value = value;
        }
        public String getValue() {
            return this.value;
        }
        public void setValue(String value) {
            this.value = value;
        }
    }

    @Path("test")
    public static class TestResource {
        @GET
        @Produces(MediaType.MULTIPART_FORM_DATA)
        public Response get() throws Exception {
            final MultiPart multiPart = new FormDataMultiPart()
                    .field("json-data", new Model("Test Value"), MediaType.APPLICATION_JSON_TYPE)
                    .bodyPart(new FileDataBodyPart("file-data", new File("test.txt")));
            return Response.ok(multiPart).build();
        }
    }

    @Override
    public ResourceConfig configure() {
        return new ResourceConfig()
                .register(TestResource.class)
                .register(MultiPartFeature.class);
    }

    @Override
    public void configureClient(ClientConfig config) {
        config.register(MultiPartFeature.class);
    }

    @Test
    public void testIt() throws Exception {
        final Response res = target("test")
                .request().get();
        FormDataMultiPart multiPart = res.readEntity(FormDataMultiPart.class);
        FormDataBodyPart jsonPart = multiPart.getField("json-data");
        FormDataBodyPart filePart = multiPart.getField("file-data");

        Model jsonData = jsonPart.getValueAs(Model.class);
        InputStream file = filePart.getValueAs(InputStream.class);

        BufferedReader fileReader = new BufferedReader(new InputStreamReader(file));
        String fileData = fileReader.readLine();

        file.close();
        fileReader.close();

        System.out.println(jsonData.getValue());
        System.out.println(fileData);

        assertThat(jsonData.getValue()).isEqualTo("Test Value");
        assertThat(fileData).isEqualTo("Some Test Data in File");
    }
}
要使用测试框架,您应该添加以下依赖项

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>${jersey2.version}</version>
</dependency>

org.glassfish.jersey.test-framework.providers
jersey-test-framework-provider-grizzly2
${jersey2.version}

您的意思是希望API方法在不同的情况下返回不同的内容吗?如果是这样的话,您的客户端可以根据需要文件还是JSON元数据设置不同的
Accept
头。如果您希望同一个请求在同一个响应中同时返回JSON和Excel文件,我认为您会遇到困难。如果JSON不是很大,您可以使用自定义头返回JSON数据,并在请求正文中返回文件。您的意思是希望您的API方法在不同的情况下返回不同的内容吗?如果是这样的话,您的客户端可以根据需要文件还是JSON元数据设置不同的
Accept
头。如果您希望同一个请求在同一个响应中同时返回JSON和Excel文件,我认为您会遇到困难。如果JSON不是很大,您可以使用自定义头返回JSON数据,并在请求正文中返回文件。感谢您的详细响应。谢谢。我还考虑将文件转换为64进制编码数据,并将其返回到对象中的UI。以及JSON。感谢您的详细回复。谢谢。我还考虑将文件转换为64进制编码数据,并将其返回到对象中的UI。以及JSON。