使用 Jersey 发送多个文件:找不到用于 multipart/form-data 的 MessageBodyWriter [英] Sending multiple files with Jersey: MessageBodyWriter not found for multipart/form-data

查看:35
本文介绍了使用 Jersey 发送多个文件:找不到用于 multipart/form-data 的 MessageBodyWriter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Java REST 应用程序的新手.我正在尝试运行一个应用程序,但我遇到了这个异常

I'm new in java rest application. I'm trying to run an application, but i have this exception

message com.sun.jersey.api.client.ClientHandlerException: A message body writer for Java type, class java.util.ArrayList, and MIME media type, multipart/form-data, was not found

exception
com.sun.jersey.api.client.ClientHandlerException: com.sun.jersey.api.client.ClientHandlerException: A message body writer for Java type, class java.util.ArrayList, and MIME media type, multipart/form-data, was not found
com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:155)
com.sun.jersey.api.client.Client.handle(Client.java:652)
com.sun.jersey.api.client.WebResource.handle(WebResource.java:682)
com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:570)
org.eu.paas.client.APIClient.doPost(APIClient.java:265)
javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)

APIClient.java:265 我有一些类似的东西:

In APIClient.java:265 I have some thing like:

cr = service.path(path)
    .type(MediaType.MULTIPART_FORM_DATA)
    .post(ClientResponse.class, listForm);

其中 listForm 是一个 ArrayList

在其余的应用程序中我有:

and in the rest application I have:

@POST
@Path("{appId-appId}/action/Multideploy/env/{envId-envId}")
@Consumes(MediaType.MULTIPART_FORM_DATA)    
@Produces(MediaType.APPLICATION_XML)
Response MultideployApplication(
        @PathParam("appId-appId") String appid, @PathParam("envId-envId") String envid,
        @FormDataParam("file") List<InputStream> uploadedInputStream);

在我的 pom.xml 中我也有这些依赖项:

Also in my pom.xml I have these dependencies:

<dependencies>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-server</artifactId>
        <version>1.8</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey.contribs</groupId>
        <artifactId>jersey-multipart</artifactId>
        <version>1.18</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.19</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>1.4</version>
    </dependency>
</dependencies>

推荐答案

Jersey 使用 MessageBodyWriter 处理 Java 对象到请求流(或服务器端的响应流)的序列化,以及 MessageBodyReaders 用于处理 de-将响应流(或服务器端的请求流)序列化为 Java 对象.您可以在 JAX-RS 实体提供者.

Jersey uses MessageBodyWriters to handle serialization of Java objects to the request stream (or response stream on server side, and MessageBodyReaders to handle de-serialization of the response stream (or request stream on server side) into Java objects. You can read more at JAX-RS Entity Providers.

话虽如此,每当你看到类似No MessageBodyReader(Writer) found for type so and so and java type so and"这样的错误时,这意味着没有序列化程序可以处理转换.在您的特定情况下,它是说没有编写器可以处理 ArrayList 到 multipart/form-data 的转换.这是有道理的,因为作者将如何知道如何进行这种转换.

That being said, whenever you see an error like "No MessageBodyReader(Writer) found for type so and so and java type so and so", it means that there is no serializer to handle the conversion. In you particular case, it is saying that there is not writer that can handle the conversion of an ArrayList to multipart/form-data. This makes sense, as how will the writer know how to make this conversion.

对于多部分,您需要在客户端实际使用多部分 API.作者知道如何将这些 API 对象转换为所需的多部分.有关 API 的完整列表,您可以查看包 com.sun.jersey.multipart .

For multipart, you need to actually use the multipart APIs on the client client side. The writer knows how to convert these API object into the required multipart parts. For the complete list of APIs, you can look at the package com.sun.jersey.multipart .

这是一个发送文件的例子

Here is an example of sending a file

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public String getTest(@FormDataParam("file") InputStream in,
                      @FormDataParam("file") FormDataContentDisposition fdc) {
    try (FileOutputStream out = new FileOutputStream(fdc.getFileName())) {
        ReaderWriter.writeTo(in, out);
    } catch (IOException ex) {
        ex.printStackTrace(System.out);
        return "Bad $#!t happended";
    }
    return "Upload OK";
}

@Test
public void doit() {
    File file = new File("...");
    FileDataBodyPart filePart = new FileDataBodyPart("file", file);
    MultiPart entity = new FormDataMultiPart()
            .bodyPart(filePart);
    Client client = Client.create();
    WebResource resource = client.resource("http://localhost:9998/service");
    ClientResponse response = resource
            .type(MediaType.MULTIPART_FORM_DATA_TYPE)
            .post(ClientResponse.class, entity);
    assertEquals(200, response.getStatus());
    assertEquals("Upload OK", response.getEntity(String.class));
    response.close();
}

对于 Jersey 多部分的 1.x 支持确实没有文档.但是很多时候,最好的文档是在测试中看到的.因此,如果您想要更多示例,查看 jersey-multipart 的测试.

There's really no documentation for the 1.x support for Jersey multipart. But a lot of times, the best documentation is seen in the tests. So if you want some more examples to go off of, look at the tests for jersey-multipart.

这是一个使用 Jersey 测试框架的完整测试.像任何其他 JUnit 测试一样运行它.将常量 FILE_ONEFILE_TWO 替换为系统上一些任意文件的位置.您应该会看到保存到当前工作目录(很可能是项目根目录)的文件

Here is a complete test using Jersey Test Framework. Run it like any other JUnit test. Replace the constants FILE_ONE and FILE_TWO with the location of some arbitrary files on your system. You should see the files saved to your current working directory (most likely the project root)

import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.core.header.ContentDisposition;
import com.sun.jersey.core.util.ReaderWriter;
import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataMultiPart;
import com.sun.jersey.multipart.FormDataParam;
import com.sun.jersey.multipart.MultiPart;
import com.sun.jersey.multipart.file.FileDataBodyPart;
import com.sun.jersey.spi.container.servlet.WebComponent;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.WebAppDescriptor;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import static org.junit.Assert.assertEquals;
import org.junit.Test;

/**
 * Run this like any other JUnit test. Dependencies for test are as follows.
 * 
 * <jersey.version>1.19</jersey.version>
 * 
 * <dependency>
 *    <groupId>com.sun.jersey</groupId>
 *    <artifactId>jersey-servlet</artifactId>
 *    <version>${jersey.version}</version>
 * </dependency>
 * <dependency>
 *    <groupId>com.sun.jersey</groupId>
 *    <artifactId>jersey-servlet</artifactId>
 *    <version>${jersey.version}</version>
 * </dependency>
 * <dependency>
 *    <groupId>com.sun.jersey.jersey-test-framework</groupId>
 *    <artifactId>jersey-test-framework-grizzly2</artifactId>
 *    <version>1.19</version>
 *    <scope>test</scope>
 * </dependency>
 * <dependency>
 *    <groupId>com.sun.jersey.contribs</groupId>
 *    <artifactId>jersey-multipart</artifactId>
 *    <version>${jersey.version}</version>
 * </dependency>
 * 
 */
public class MultipartTest extends JerseyTest {
    

    @Path("service")
    public static class Service {

        @POST
        @Consumes(MediaType.MULTIPART_FORM_DATA)
        @Produces(MediaType.TEXT_PLAIN)
        public String getTest(@FormDataParam("file") List<FormDataBodyPart> files) {
            for (FormDataBodyPart filePart: files) {
                ContentDisposition cd = filePart.getContentDisposition();
                try (FileOutputStream out = new FileOutputStream(cd.getFileName())) {
                    ReaderWriter.writeTo(filePart.getEntityAs(InputStream.class), out);
                } catch (IOException ex) {
                    ex.printStackTrace(System.out);
                    return "Oops";
                }
            }
            return "Upload OK";
        }
    }

    public static class AppConfig extends DefaultResourceConfig {
        public AppConfig() {
            super(Service.class);
        }
    }

    @Override
    public WebAppDescriptor configure() {
        return new WebAppDescriptor.Builder()
                .initParam(WebComponent.RESOURCE_CONFIG_CLASS, 
                           AppConfig.class.getName())
                .build();
    }
    
    private static final String FILE_ONE = "<enter-a-file-path>";
    private static final String FILE_TWO = "<enter-a-file-path>";
    
    @Test
    public void doit() {
        File file1 = new File(FILE_ONE);
        File file2 = new File(FILE_TWO);
        MultiPart entity = new FormDataMultiPart();
        FileDataBodyPart filePart = new FileDataBodyPart("file", file1);
        entity.bodyPart(filePart);
        filePart = new FileDataBodyPart("file", file2);
        entity.bodyPart(filePart);
        
        ClientResponse response = resource().path("service")
                .type(MediaType.MULTIPART_FORM_DATA_TYPE)
                .post(ClientResponse.class, entity);
        assertEquals(200, response.getStatus());
        assertEquals("Upload OK", response.getEntity(String.class));
        response.close();
    }
}


更新 2(泽西 2.x)

这是 Jersey 2.x 的相同测试.只需将常量 FILE_ONEFILE_TWO 替换为系统上的一些文件位置,然后运行测试.文件应保存到您当前的工作目录.


UPDATE 2 (Jersey 2.x)

Here is the same test with Jersey 2.x. Just replace the constants FILE_ONE and FILE_TWO with some file locations on your system, and run the test. The files should be saved to your current working directory.

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.media.multipart.ContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.FormDataParam;
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.message.internal.ReaderWriter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;

import org.junit.Test;
import static junit.framework.Assert.assertEquals;

/**
 * Run it like any other JUnit test. Required dependencies are as follows:
 * 
 *  <dependency>
 *     <groupId>org.glassfish.jersey.test-framework.providers</groupId>
 *     <version>2.22.1</version>
 *     <scope>test</scope>
 *  </dependency>
 *     <dependency>
 *     <groupId>org.glassfish.jersey.media</groupId>
 *     <artifactId>jersey-media-multipart</artifactId>
 *     <version>2.22.1</version>
 *     <scope>test</scope>
 *  </dependency>
 * 
 */
public class Jersey2MultipartTest extends JerseyTest {
    
    @Path("service")
    public static class Service {

        @POST
        @Consumes(MediaType.MULTIPART_FORM_DATA)
        @Produces(MediaType.TEXT_PLAIN)
        public String getTest(@FormDataParam("file") List<FormDataBodyPart> files) {
            for (FormDataBodyPart filePart: files) {
                ContentDisposition cd = filePart.getContentDisposition();
                try (FileOutputStream out = new FileOutputStream(cd.getFileName())) {
                    ReaderWriter.writeTo(filePart.getEntityAs(InputStream.class), out);
                } catch (IOException ex) {
                    ex.printStackTrace(System.out);
                    return "Oops";
                }
            }
            return "Upload OK";
        }
    }
    
    @Override
    public ResourceConfig configure() {
        return new ResourceConfig(Service.class)
                .register(MultiPartFeature.class);
    }
    
    @Override
    public void configureClient(ClientConfig config) {
        config.register(MultiPartFeature.class);
    }
    
    private static final String FILE_ONE = "<enter-file-location>";
    private static final String FILE_TWO = "<enter-file-location>";

    @Test
    public void doit() {
        MultiPart entity = new FormDataMultiPart();
        addFiles(entity, FILE_ONE, FILE_TWO);

        Response response = target("service").request()
                .post(Entity.entity(entity, MediaType.MULTIPART_FORM_DATA));
        assertEquals(200, response.getStatus());
        assertEquals("Upload OK", response.readEntity(String.class));
        response.close();
    }
    
    private void addFiles(MultiPart entity, String... files) {
        for (String file: files) {
            FileDataBodyPart filePart = new FileDataBodyPart("file", new File(file));
            entity.bodyPart(filePart);
        }
    }
}

这篇关于使用 Jersey 发送多个文件:找不到用于 multipart/form-data 的 MessageBodyWriter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆