使用Jersey发送多个文件:找不到multipart / form-data的MessageBodyWriter

时间:2016-01-06 21:44:55

标签: java jersey jax-rs multipartform-data

我是java rest应用程序的新手。 我试图运行一个应用程序,但我有这个例外

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我有一些事情:

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

listFormArrayList<InputStream>

的位置

在其他申请中我有:

@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中,我有这些依赖项:

<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>

1 个答案:

答案 0 :(得分:5)

Jersey使用MessageBodyWriter来处理请求流(或服务器端的响应流,以及MessageBodyReader)的Java对象序列化以处理 de - 序列化响应流(或服务器端的请求流)到Java对象。您可以在JAX-RS Entity Providers了解更多信息。

话虽这么说,每当你看到像&#34;没有找到类型的MessageBodyReader(Writer)这样的错误以及java类型某某&#34; 时,它意味着有没有序列化程序来处理转换。在您的特定情况下,它表示没有编写者可以处理ArrayList到multipart / form-data的转换。这是有道理的,因为作者将如何知道如何进行这种转换。

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

以下是发送文件的示例

@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 multipart的1.x支持,实际上没有任何文档。但很多时候,测试中都会看到最好的文档。因此,如果您想要更多示例,请look at the tests for jersey-multipart

更新

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

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替换为系统上的某些文件位置,然后运行测试。这些文件应保存到您当前的工作目录中。

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);
        }
    }
}