处理多附件在CXF的API(Handling multipart attachments in CX

2019-09-17 13:56发布

我想开发使用Apache CXF这需要在附件中随请求的API调用。 我跟着这个教程,这是我这么远。

@POST
@Path("/upload")
@RequireAuthentication(false)
public Response uploadWadl(MultipartBody multipartBody){
    List<Attachment> attachments = multipartBody.getAllAttachments();
    DataHandler dataHandler = attachments.get(0).getDataHandler();
    try {
        InputStream is = dataHandler.getInputStream();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return Response("OK");
}

我得到一个InputStream对象附件及一切工作正常。 但是我需要通过附接作为java.io.File的对象到另一功能。 我知道我可以在这里创建一个文件,从InputStream读取和写入。 但有一个更好的解决办法? 有CXF已经存储为文件? 如果是这样我可以继续使用这一点。 有什么建议么?

Answer 1:

我也有兴趣在这个问题上。 虽然与CXF邮件列表上讨论谢尔盖,我学到如果附件超过一定阈值CXF使用临时文件。

在这个过程中,我发现这个博客帖子 ,介绍如何安全地使用CXF附件。 您可以通过上为例感兴趣此页为好。

这就是我当时可以说是我调查,现在,我希望帮助。


编辑:目前这里是我们如何处理附件与CXF 2.6.x. 关于使用多内容类型上传文件。

在我们的REST资源,我们定义了以下方法:

  @POST
  @Produces(MediaType.APPLICATION_JSON)
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  @Path("/")
  public Response archive(
          @Multipart(value = "title", required = false) String title,
          @Multipart(value = "hash", required = false) @Hash(optional = true) String hash,
          @Multipart(value = "file") @NotNull Attachment attachment) {

    ...

    IncomingFile incomingFile = attachment.getObject(IncomingFile.class);

    ...
  }

在该段的几个注意事项:

  • @Multipart不是标准JAXRS,它甚至不是在JAXRS 2,这是CXF的一部分。
  • 在我们的代码,我们已经实现了Bean验证(你必须自己做,在JAXRS 1)
  • 您不必使用MultipartBody ,这里的关键是使用类型的参数Attachment

所以,是的,据我们知道有没有可能直接得到我们想要的方法签名的类型。 因此,例如,如果你只是想在InputStream的附件,你不能把它的方法的签名。 你必须使用org.apache.cxf.jaxrs.ext.multipart.Attachment类型,并撰写了以下声明:

InputStream inputStream = attachment.getObject(InputStream.class);

同时,我们也发现了谢尔盖Beryozkin的帮助下,我们可以改变或包装这个InputStream ,这就是为什么在上面的代码中,我们写道:

IncomingFile incomingFile = attachment.getObject(IncomingFile.class);

IncomingFile是我们周围的定制包装InputStream ,对于你必须注册一个MessageBodyReaderParamHandler不会帮助,因为他们不流,但一起工作String

@Component
@Provider
@Consumes
public class IncomingFileAttachmentProvider implements MessageBodyReader<IncomingFile> {
  @Override
  public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return type != null && type.isAssignableFrom(IncomingFile.class);
  }

  @Override
  public IncomingFile readFrom(Class<IncomingFile> type,
                              Type genericType,
                              Annotation[] annotations,
                              MediaType mediaType,
                              MultivaluedMap<String, String> httpHeaders,
                              InputStream entityStream
  ) throws IOException, WebApplicationException {

    return createIncomingFile(entityStream, fixedContentHeaders(httpHeaders)); // the code that will return an IncomingFile
  }
}

但是请注意,已经出现了一些试验,以了解事情经过,怎么了,顺便烫的错误(例如附着部的第一头的第一个字母是吃让你过ontent-Type而非Content-Type )。

当然, entityStream表示实际InputStream的附件。 该物流将或者从存储器或从磁盘读取数据,这取决于其中CXF把数据; 有一个大小的阈值特性( attachment-memory-threshold也如此)。 你也可以说在那里临时联结部会( attachment-directory )。

只是不要忘了关闭流 ,当你完成(一些工具为你做)。

一旦一切都被配置我们用测试它休息保证的 ,从约翰·Haleby。 (有些代码是我们的测试utils的一部分,虽然):

given().log().all()
        .multiPart("title", "the.title")
        .multiPart("file", file.getName(), file.getBytes(), file.getMimeType())
.expect().log().all()
        .statusCode(200)
        .body("store_event_id", equalTo("1111111111"))
.when()
        .post(host().base().endWith("/store").toStringUrl());

或者,如果你需要通过卷曲上传文件以这样一种方式:

curl --trace -v -k -f
     --header "Authorization: Bearer b46704ff-fd1d-4225-9dd4-e29065532b73"
     --header "Content-Type: multipart/form-data"
     --form "hash={SHA256}3e954efb149aeaa99e321ffe6fd581f84d5a497b6fab5c86e0d5ab20201f7eb5"
     --form "title=fantastic-video.mp4"
     --form "archive=@/the/path/to/the/file/fantastic-video.mp4;type=video/mp4"
     -X POST http://localhost:8080/api/video/event/store

要完成这个答案,我想提就可以在多JSON有效载荷,对于您可以使用Attachment中的签名类型,然后写

Book book = attachment.getObject(Book.class)

或者你可以写这样的参数:

@Multipart(value="book", type="application/json") Book book

只是不要忘记给加Content-Type执行请求时,头相关的部分。

这可能是值得一说,有可能在一个列表中的所有部分,只写一个方法与类型的单个参数List<Attachment> 。 不过,我更喜欢有实际参数的方法签名,因为它是更清洁和更小的样板。

@POST
void takeAllParts(List<Attachment> attachments)


文章来源: Handling multipart attachments in CXF APIs