我需要编写REST服务来支持文件上传;我正在使用JBOSS / Resteasy / Jersey,如下:
@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但是找不到任何有用的东西。
答案 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提供程序,不要让事情复杂化;这是毫无意义的。