如何防止HTTP Rest Jboss resteasy Fileupload因失败而无法找到邮件正文阅读器'错误?

时间:2014-04-16 23:59:00

标签: file-upload jboss7.x resteasy

我需要编写REST服务来支持文件上传;我正在使用JBOSS / Resteasy / Jersey,如下:

服务器HTTP REST处理程序:

@Path("document")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public Response uploadFile(@FormDataParam("file") InputStream fileInputStream,
                           @FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
                           @FormDataParam("selectedName") String selectedName,
                           @FormDataParam("name") String name,
                           @FormDataParam("notes") String notes) {
   String documentId;
   // upload the file
   String filePath = SERVER_UPLOAD_LOCATION_FOLDER + contentDispositionHeader.getFileName();
   try { fileUpload(fileInputStream, filePath); 
   }
   catch (IOException e) { throw new ApplicationRuntimeException( "Unable to upload file: " + selectedName); 
   }
   // create the document record
   documentId = create(selectedName, name, notes);
   return Response.ok("123456789").build();
}

单元测试

为了测试服务,我编写了以下单元测试:

@Test
public void testCreateDocument() throws Exception {
    Assert.assertNotNull(file);  
    Assert.assertTrue(file.canRead());
    given()
    .multiPart("notes", "my notes") .multiPart("selectedName", "selectedName")    
    .multiPart("name", "test.txt") .multiPart("file",file) 
    .contentType(MediaType.APPLICATION_OCTET_STREAM) .expect().body(equalTo("This is an uploaded test file."))
    .when().post(DOCUMENT_URL);
}

单元测试失败。以下是单元测试收到的错误消息以及服务器日志

单元测试错误消息

The server refused this request because the request entity is in a format not supported by the requested resource for the requested method.

此外,在发出上述单元测试时会记录以下服务器日志:

09:26:40,340 WARN  [org.jboss.resteasy.core.ExceptionHandler] (http-/127.0.0.1:8080-7) failed to execute: javax.ws.rs.NotSupportedException: Could not find message body reader for type: class com.sun.jersey.core.header.FormDataContentDisposition of content type: multipart/form-data;boundary=J6UnCyDNsA50mzrPqDb2ctHPBb6fEpFJRF
    at org.jboss.resteasy.core.interception.ServerReaderInterceptorContext.throwReaderNotFound(ServerReaderInterceptorContext.java:52) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.getReader(AbstractReaderInterceptorContext.java:73) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:50) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor.aroundReadFrom(GZIPDecodingInterceptor.java:59) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:53) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:150) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:89) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:112) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:288) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:242) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:229) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56) [resteasy-jaxrs-3.0.7.Final.jar:]
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51) [resteasy-jaxrs-3.0.7.Final.jar:]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-1.jar:1.0.2.Final-redhat-1]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]
    at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]
    at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169) [jboss-as-web-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:920) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
    at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_45]

我遍地搜索了无法找到消息正文阅读器的类型:class com.sun.jersey.core.header.FormDataContentDisposition of content type:multipart / form-data error但是找不到任何有用的东西。

2 个答案:

答案 0 :(得分:3)

我有同样的问题,为了解决这个问题,我使用了volkerbenders repository中描述的解决方案。以下是对我有用的解决方案:

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jaxrs</artifactId>
    <version>3.0.11.Final</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-multipart-provider</artifactId>
    <version>3.0.11.Final</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jaxb-provider</artifactId>
    <version>3.0.11.Final</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

这是资源类:

import org.apache.commons.io.IOUtils;
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

@Path("/file")
public class FileResource {

    public static final String UPLOADED_FILE_PARAMETER_NAME = "file";

    @Path("/upload")
    @POST
    @Consumes("multipart/form-data")
    public Response uploadFile(MultipartFormDataInput input) {

        Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
        List<InputPart> inputParts = uploadForm.get(UPLOADED_FILE_PARAMETER_NAME);

        for (InputPart inputPart : inputParts) {
            MultivaluedMap<String, String> headers = inputPart.getHeaders();
            try {
                InputStream inputStream = inputPart.getBody(InputStream.class, null);
                byte[] bytes = IOUtils.toByteArray(inputStream);
                String filename = getFileName(headers);
                //TODO: HERE you do whatever you want to do with the file
                //...
            } catch (IOException e) {
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
            }
        }
        return Response.status(Response.Status.OK).build();
    }

    private String getFileName(MultivaluedMap<String, String> headers) {
        String[] contentDisposition = headers.getFirst("Content-Disposition").split(";");

        for (String filename : contentDisposition) {
            if ((filename.trim().startsWith("filename"))) {

                String[] name = filename.split("=");

                String finalFileName = sanitizeFilename(name[1]);
                return finalFileName;
            }
        }
        return "unknown";
    }

    private String sanitizeFilename(String s) {
        return s.trim().replaceAll("\"", "");
    }

}

答案 1 :(得分:1)

在这种情况下,Jersey不需要通过多部分POST来支持文件上传。 RESTEasy支持multi-part POST request processing in a different way

使用Jersey也是你首先看到警告的原因 - 我怀疑某些类(特别是来自Jersey的FormDataContentDisposition类及其相关的类不能被JBoss中的RESTEasy模块访问通过在不了解JBoss模块系统的情况下添加两个JAX-RS提供程序,不要让事情复杂化;这是毫无意义的。