文件与 Jersey 宁静网络服务中的其他对象一起上传 [英] File upload along with other object in Jersey restful web service

查看:23
本文介绍了文件与 Jersey 宁静网络服务中的其他对象一起上传的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过上传图片和员工数据在系统中创建员工信息.我可以使用球衣通过不同的休息电话来做到这一点.但我想在一次休息中实现.我在下面提供结构.请帮我这方面怎么做.

I want to create an employee information in the system by uploading an image along with employee data. I am able to do it with different rest calls using jersey. But I want to achieve in one rest call. I provide below the structure. Please help me how to do in this regard.

@POST
@Path("/upload2")
@Consumes({MediaType.MULTIPART_FORM_DATA,MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response uploadFileWithData(
        @FormDataParam("file") InputStream fileInputStream,
        @FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
        Employee emp) {

//..... business login

}

每当我尝试这样做时,Chrome 邮递员都会出错.下面给出了我的 Employee json 的简单结构.

Whenever I am trying to do, I get error in Chrome postman. The simple structure of my Employee json is given below.

{
    "Name": "John",
    "Age": 23,
    "Email": "john@gmail.com",
    "Adrs": {
        "DoorNo": "12-A",
        "Street": "Street-11",
        "City": "Bangalore",
        "Country": "Karnataka"
    }
}

不过我可以通过两次不同的调用来实现,但我想在一个休息调用中实现,以便我可以接收文件以及员工的实际数据.

However I can do it by making two different call, but I want to achieve in one rest call so that I can receive the file as well as the actual data of the employee.

请求您在这方面提供帮助.

Request you to help in this regard.

推荐答案

你不能有两个 Content-Type(技术上这就是我们下面要做的,但它们用多部分的每个部分,但主要类型是多部分).这基本上就是您对方法的期望.您期望 mutlipart json 一起作为主要媒体类型.Employee 数据需要是 multipart 的一部分.所以你可以为 Employee 添加一个 @FormDataParam("emp").

You can't have two Content-Types (well technically that's what we're doing below, but they are separated with each part of the multipart, but the main type is multipart). That's basically what you are expecting with your method. You are expecting mutlipart and json together as the main media type. The Employee data needs to be part of the multipart. So you can add a @FormDataParam("emp") for the Employee.

@FormDataParam("emp") Employee emp) { ...

这是我用来测试的类

@Path("/multipart")
public class MultipartResource {
    
    @POST
    @Path("/upload2")
    @Consumes({MediaType.MULTIPART_FORM_DATA})
    public Response uploadFileWithData(
            @FormDataParam("file") InputStream fileInputStream,
            @FormDataParam("file") FormDataContentDisposition cdh,
            @FormDataParam("emp") Employee emp) throws Exception{
        
        Image img = ImageIO.read(fileInputStream);
        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(img)));
        System.out.println(cdh.getName());
        System.out.println(emp);
        
        return Response.ok("Cool Tools!").build();
    } 
}

首先,我只是用客户端 API 进行了测试,以确保它可以正常工作

First I just tested with the client API to make sure it works

@Test
public void testGetIt() throws Exception {
    
    final Client client = ClientBuilder.newBuilder()
        .register(MultiPartFeature.class)
        .build();
    WebTarget t = client.target(Main.BASE_URI).path("multipart").path("upload2");

    FileDataBodyPart filePart = new FileDataBodyPart("file", 
                                             new File("stackoverflow.png"));
    // UPDATE: just tested again, and the below code is not needed.
    // It's redundant. Using the FileDataBodyPart already sets the
    // Content-Disposition information
    filePart.setContentDisposition(
            FormDataContentDisposition.name("file")
                                    .fileName("stackoverflow.png").build());

    String empPartJson
            = "{"
            + "  "id": 1234,"
            + "  "name": "Peeskillet""
            + "}";

    MultiPart multipartEntity = new FormDataMultiPart()
            .field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
            .bodyPart(filePart);
          
    Response response = t.request().post(
            Entity.entity(multipartEntity, multipartEntity.getMediaType()));
    System.out.println(response.getStatus());
    System.out.println(response.readEntity(String.class));

    response.close();
}

我刚刚创建了一个简单的 Employee 类,其中包含一个 idname 字段用于测试.这工作得很好.它显示图像,打印内容配置,并打印 Employee 对象.

I just created a simple Employee class with an id and name field for testing. This works perfectly fine. It shows the image, prints the content disposition, and prints the Employee object.

我对 Postman 不太熟悉,所以我把那个测试留到最后 :-)

I'm not too familiar with Postman, so I saved that testing for last :-)

它似乎也工作正常,因为您可以看到响应 Cool Tools".但是如果我们查看打印的 Employee 数据,我们会看到它是 null.这很奇怪,因为使用客户端 API 时它运行良好.

It appears to work fine also, as you can see the response "Cool Tools". But if we look at the printed Employee data, we'll see that it's null. Which is weird because with the client API it worked fine.

如果我们查看预览窗口,就会发现问题

If we look at the Preview window, we'll see the problem

emp 正文部分没有 Content-Type 标头.您可以在客户端 API 中看到我明确设置了它

There's no Content-Type header for the emp body part. You can see in the client API I explicitly set it

MultiPart multipartEntity = new FormDataMultiPart()
        .field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
        .bodyPart(filePart);

所以我想这实际上只是完整答案的部分.就像我说的,我不熟悉 Postman 所以我不知道如何为各个身体部位设置 Content-Types.图像的 image/png 是为我自动设置的图像部分(我猜这只是由文件扩展名决定的).如果你能弄清楚这一点,那么问题就应该解决了.如果您知道如何执行此操作,请将其作为答案发布.

So I guess this is really only part of a full answer. Like I said, I am not familiar with Postman So I don't know how to set Content-Types for individual body parts. The image/png for the image was automatically set for me for the image part (I guess it was just determined by the file extension). If you can figure this out, then the problem should be solved. Please, if you find out how to do this, post it as an answer.

请参阅下面的更新以获取解决方案

基本配置:

依赖:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
    <version>${jersey2.version}</version>
</dependency>

客户端配置:

final Client client = ClientBuilder.newBuilder()
    .register(MultiPartFeature.class)
    .build();

服务器配置:

// Create JAX-RS application.
final Application application = new ResourceConfig()
    .packages("org.glassfish.jersey.examples.multipart")
    .register(MultiPartFeature.class);

如果您在服务器配置方面遇到问题,以下帖子之一可能会有所帮助

If you're having problems with the server configuration, one of the following posts might help

所以从 Postman 客户端可以看到,一些客户端无法设置单个部件的 Content-Type,这包括浏览器,关于使用 FormData (js) 时的默认功能.

So as you can see from the Postman client, some clients are unable to set individual parts' Content-Type, this includes the browser, in regards to it's default capabilities when using FormData (js).

我们不能指望客户端解决这个问题,所以我们能做的就是在接收数据时,在反序列化之前显式设置 Content-Type.例如

We can't expect the client to find away around this, so what we can do, is when receiving the data, explicitly set the Content-Type before deserializing. For example

@POST
@Path("upload2")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFileAndJSON(@FormDataParam("emp") FormDataBodyPart jsonPart,
                                  @FormDataParam("file") FormDataBodyPart bodyPart) { 
     jsonPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
     Employee emp = jsonPart.getValueAs(Employee.class);
}

获取 POJO 需要一些额外的工作,但它比强迫客户尝试找到自己的解决方案更好.

It's a little extra work to get the POJO, but it is a better solution than forcing the client to try and find it's own solution.

另一种选择是使用 String 参数并使用您用来将 String 反序列化为 POJO 的任何 JSON 库(如 Jackson ObjectMapper).使用前一个选项,我们只让 Jersey 处理反序列化,它将使用与所有其他 JSON 端点相同的 JSON 库(这可能是首选).

Another option is to use a String parameter and use whatever JSON library you use to deserialze the String to the POJO (like Jackson ObjectMapper). With the previous option, we just let Jersey handle the deserialization, and it will use the same JSON library it uses for all the other JSON endpoints (which might be preferred).

  • 这些评论中有一个对话,如果您使用的连接器与默认连接器不同,您可能会感兴趣HttpUrlConnection.
  • There is a conversation in these comments that you may be interested in if you are using a different Connector than the default HttpUrlConnection.

这篇关于文件与 Jersey 宁静网络服务中的其他对象一起上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆