文件上传以及Jersey restful web服务中的其他对象

时间:2022-09-15 21:44:37

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

}

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

每当我想要做的时候,我都会在Chrome邮递员中出错。我的Employee json的简单结构如下所示。

{
    "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.

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

6 个解决方案

#1


72  

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.

你不能有两个内容类型(技术上我们正在下面做的,但是它们与多部分的每个部分分开,但主要类型是多部分)。这基本上就是你对你的方法所期望的。您期望将mutlipart和json一起作为主要媒体类型。 Employee数据需要成为multipart的一部分。因此,您可以为Employee添加@FormDataParam(“emp”)。

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

Here's the class I used for testing

这是我用于测试的类

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

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

首先,我刚刚使用客户端API测试,以确保它的工作原理

@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("*.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("*.png").build());

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

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

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.

我刚刚创建了一个简单的Employee类,其中包含用于测试的id和name字段。这完全没问题。它显示图像,打印内容配置,并打印Employee对象。

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

我对Postman不太熟悉,所以我把测试保存到最后:-)

文件上传以及Jersey restful web服务中的其他对象

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.

它似乎工作正常,因为你可以看到响应“酷工具”。但是,如果我们查看打印的员工数据,我们会看到它是空的。这很奇怪,因为客户端API工作得很好。

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

如果我们查看预览窗口,我们会看到问题

文件上传以及Jersey restful web服务中的其他对象

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

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

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

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 explicitly set for me for the image part. 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.

所以我想这只是完整答案的一部分。就像我说的,我不熟悉Postman所以我不知道如何设置个人身体部位的内容类型。我为图像部分明确设置了图像的图像/ png。如果你能解决这个问题,那么问题就应该解决了。如果您发现如何操作,请将其作为答案发布。


And just for completeness...

Basic configurations:

基本配置:

Dependency:

相关性:

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

Client config:

客户端配置:

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

Server config:

服务器配置:

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

UPDATE

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).

从Postman客户端可以看出,一些客户端在使用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

我们不能指望客户找到这个,所以我们可以做的是,在接收数据时,在反序列化之前明确设置Content-Type。例如

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

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.

获得POJO需要额外的工作,但这比强迫客户尝试找到自己的解决方案更好。

#2


1  

You can access the Image File and data from a form using MULTIPART FORM DATA By using the below code.

您可以使用MULTIPART FORM DATA从表单访问图像文件和数据使用以下代码。

@POST
@Path("/UpdateProfile")
@Consumes(value={MediaType.APPLICATION_JSON,MediaType.MULTIPART_FORM_DATA})
@Produces(value={MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public Response updateProfile(
    @FormDataParam("file") InputStream fileInputStream,
    @FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
    @FormDataParam("ProfileInfo") String ProfileInfo,
    @FormDataParam("registrationId") String registrationId) {

    String filePath= "/filepath/"+contentDispositionHeader.getFileName();

    OutputStream outputStream = null;
    try {
        int read = 0;
        byte[] bytes = new byte[1024];
        outputStream = new FileOutputStream(new File(filePath));

        while ((read = fileInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, read);
        }

        outputStream.flush();
        outputStream.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (outputStream != null) { 
            try {
                outputStream.close();
            } catch(Exception ex) {}
        }
    }
}

#3


0  

Your ApplicationConfig should register the MultiPartFeature.class from the glassfish.jersey.media.. so as to enable file upload

您的ApplicationConfig应该注册glassfish.jersey.media中的MultiPartFeature.class ..以便启用文件上传

@javax.ws.rs.ApplicationPath(ResourcePath.API_ROOT)
public class ApplicationConfig extends ResourceConfig {  
public ApplicationConfig() {
        //register the necessary headers files needed from client
        register(CORSConfigurationFilter.class);
        //The jackson feature and provider is used for object serialization
        //between client and server objects in to a json
        register(JacksonFeature.class);
        register(JacksonProvider.class);
        //Glassfish multipart file uploader feature
        register(MultiPartFeature.class);
        //inject and registered all resources class using the package
        //not to be tempered with
        packages("com.flexisaf.safhrms.client.resources");
        register(RESTRequestFilter.class);
    }

#4


0  

I used file upload example from,

我使用了文件上传示例,

http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/

http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/

in my resource class i have below method

在我的资源类中,我有以下方法

@POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response  attachupload(@FormDataParam("file") byte[] is,
@FormDataParam("file") FormDataContentDisposition fileDetail,
@FormDataParam("fileName") String flename){
attachService.saveAttachment(flename,is);
}

in my attachService.java i have below method

在我的attachService.java我有以下方法

 public void saveAttachment(String flename,  byte[] is) {
            // TODO Auto-generated method stub
         attachmentDao.saveAttachment(flename,is);

        }

in Dao i have

在Dao我有

attach.setData(is);
attach.setFileName(flename);

in my HBM mapping is like

在我的HBM映射中就像

<property name="data" type="binary" >
            <column name="data" />
</property>

This working for all type of files like .PDF,.TXT, .PNG etc.,

这适用于所有类型的文件,如.PDF,.TXT,.PNG等,

#5


0  

I want add a comment on peeskillet but don't have 50 reputation points, hence adding as an answer:

我想在peeskillet上添加评论,但没有50个声望点,因此添加一个答案:

When I tried @peeskillet solution with Jersey client 2.21.1, there was 400 error. It worked when I added following in my client code:

当我使用Jersey客户端2.21.1尝试@peeskillet解决方案时,出现了400错误。当我在客户端代码中添加以下内容时,它工作正常

  MediaType contentType = MediaType.MULTIPART_FORM_DATA_TYPE;
  contentType = Boundary.addBoundary(contentType);

  Response response = t.request().post(
        Entity.entity(multipartEntity, contentType));

instead of hardcoded MediaType.MULTIPART_FORM_DATA in post request call.

而不是在发布请求调用中硬编码的MediaType.MULTIPART_FORM_DATA。

#6


-4  

Set the "Content-Type: multipart/form-data" on the client side and that should do the job

在客户端设置“Content-Type:multipart / form-data”,这应该可以完成工作

#1


72  

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.

你不能有两个内容类型(技术上我们正在下面做的,但是它们与多部分的每个部分分开,但主要类型是多部分)。这基本上就是你对你的方法所期望的。您期望将mutlipart和json一起作为主要媒体类型。 Employee数据需要成为multipart的一部分。因此,您可以为Employee添加@FormDataParam(“emp”)。

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

Here's the class I used for testing

这是我用于测试的类

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

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

首先,我刚刚使用客户端API测试,以确保它的工作原理

@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("*.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("*.png").build());

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

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

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.

我刚刚创建了一个简单的Employee类,其中包含用于测试的id和name字段。这完全没问题。它显示图像,打印内容配置,并打印Employee对象。

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

我对Postman不太熟悉,所以我把测试保存到最后:-)

文件上传以及Jersey restful web服务中的其他对象

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.

它似乎工作正常,因为你可以看到响应“酷工具”。但是,如果我们查看打印的员工数据,我们会看到它是空的。这很奇怪,因为客户端API工作得很好。

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

如果我们查看预览窗口,我们会看到问题

文件上传以及Jersey restful web服务中的其他对象

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

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

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

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 explicitly set for me for the image part. 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.

所以我想这只是完整答案的一部分。就像我说的,我不熟悉Postman所以我不知道如何设置个人身体部位的内容类型。我为图像部分明确设置了图像的图像/ png。如果你能解决这个问题,那么问题就应该解决了。如果您发现如何操作,请将其作为答案发布。


And just for completeness...

Basic configurations:

基本配置:

Dependency:

相关性:

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

Client config:

客户端配置:

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

Server config:

服务器配置:

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

UPDATE

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).

从Postman客户端可以看出,一些客户端在使用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

我们不能指望客户找到这个,所以我们可以做的是,在接收数据时,在反序列化之前明确设置Content-Type。例如

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

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.

获得POJO需要额外的工作,但这比强迫客户尝试找到自己的解决方案更好。

#2


1  

You can access the Image File and data from a form using MULTIPART FORM DATA By using the below code.

您可以使用MULTIPART FORM DATA从表单访问图像文件和数据使用以下代码。

@POST
@Path("/UpdateProfile")
@Consumes(value={MediaType.APPLICATION_JSON,MediaType.MULTIPART_FORM_DATA})
@Produces(value={MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public Response updateProfile(
    @FormDataParam("file") InputStream fileInputStream,
    @FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
    @FormDataParam("ProfileInfo") String ProfileInfo,
    @FormDataParam("registrationId") String registrationId) {

    String filePath= "/filepath/"+contentDispositionHeader.getFileName();

    OutputStream outputStream = null;
    try {
        int read = 0;
        byte[] bytes = new byte[1024];
        outputStream = new FileOutputStream(new File(filePath));

        while ((read = fileInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, read);
        }

        outputStream.flush();
        outputStream.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (outputStream != null) { 
            try {
                outputStream.close();
            } catch(Exception ex) {}
        }
    }
}

#3


0  

Your ApplicationConfig should register the MultiPartFeature.class from the glassfish.jersey.media.. so as to enable file upload

您的ApplicationConfig应该注册glassfish.jersey.media中的MultiPartFeature.class ..以便启用文件上传

@javax.ws.rs.ApplicationPath(ResourcePath.API_ROOT)
public class ApplicationConfig extends ResourceConfig {  
public ApplicationConfig() {
        //register the necessary headers files needed from client
        register(CORSConfigurationFilter.class);
        //The jackson feature and provider is used for object serialization
        //between client and server objects in to a json
        register(JacksonFeature.class);
        register(JacksonProvider.class);
        //Glassfish multipart file uploader feature
        register(MultiPartFeature.class);
        //inject and registered all resources class using the package
        //not to be tempered with
        packages("com.flexisaf.safhrms.client.resources");
        register(RESTRequestFilter.class);
    }

#4


0  

I used file upload example from,

我使用了文件上传示例,

http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/

http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/

in my resource class i have below method

在我的资源类中,我有以下方法

@POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response  attachupload(@FormDataParam("file") byte[] is,
@FormDataParam("file") FormDataContentDisposition fileDetail,
@FormDataParam("fileName") String flename){
attachService.saveAttachment(flename,is);
}

in my attachService.java i have below method

在我的attachService.java我有以下方法

 public void saveAttachment(String flename,  byte[] is) {
            // TODO Auto-generated method stub
         attachmentDao.saveAttachment(flename,is);

        }

in Dao i have

在Dao我有

attach.setData(is);
attach.setFileName(flename);

in my HBM mapping is like

在我的HBM映射中就像

<property name="data" type="binary" >
            <column name="data" />
</property>

This working for all type of files like .PDF,.TXT, .PNG etc.,

这适用于所有类型的文件,如.PDF,.TXT,.PNG等,

#5


0  

I want add a comment on peeskillet but don't have 50 reputation points, hence adding as an answer:

我想在peeskillet上添加评论,但没有50个声望点,因此添加一个答案:

When I tried @peeskillet solution with Jersey client 2.21.1, there was 400 error. It worked when I added following in my client code:

当我使用Jersey客户端2.21.1尝试@peeskillet解决方案时,出现了400错误。当我在客户端代码中添加以下内容时,它工作正常

  MediaType contentType = MediaType.MULTIPART_FORM_DATA_TYPE;
  contentType = Boundary.addBoundary(contentType);

  Response response = t.request().post(
        Entity.entity(multipartEntity, contentType));

instead of hardcoded MediaType.MULTIPART_FORM_DATA in post request call.

而不是在发布请求调用中硬编码的MediaType.MULTIPART_FORM_DATA。

#6


-4  

Set the "Content-Type: multipart/form-data" on the client side and that should do the job

在客户端设置“Content-Type:multipart / form-data”,这应该可以完成工作