Sending multiple files with Jersey: MessageBodyWriter not found for multipart/form-data

后端 未结 1 1243
面向向阳花
面向向阳花 2020-12-11 23:42

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 m         


        
相关标签:
1条回答
  • 2020-12-12 00:03

    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.

    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.

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

    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.


    UPDATE

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

    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);
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题