Uploading a file along with another object on a web service in Jersey.

I want to create employee information in the system by uploading an image along with employee data. I can do this with various leisure challenges using knitwear. But I want to make one call. I provide below structure. Please help me how to do this.

@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 try to do this, I get an error in my Chrome mail device. Below is a simple structure of my json employee.

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

However, I can do this by making two different calls, but I want to achieve one call to get the file, as well as the actual employee data.

Ask you for help in this regard.

+43
java jersey multipartform-data jax-rs postman
Dec 22 '14 at 19:59
source share
6 answers

You cannot have two Content-Type (well technically, what we do below, but they are shared with each part of multipart, but the main type is multipart). This is basically what you expect from your method. You expect mutlipart and json together to become the main type of media. Employee data should be part of a multi-party system. This way you can add @FormDataParam("emp") for Employee .

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

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

At first I just tested the client API to make sure that 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 redundant. Using the FileDataBodyPart already sets the // Content-Disposition information filePart.setContentDisposition( FormDataContentDisposition.name("file") .fileName("stackoverflow.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. It works great. It displays the image, prints the contents, and prints the Employee object.

I'm not too familiar with Postman, so I saved this testing for the latter :-)

enter image description here

It also works great, as you can see the answer "Cool Tools" . But if we look at the printed data of Employee , we will see that it is null. Which is strange, because it worked perfectly with the client API.

If we look at the preview window, we will see a problem

enter image description here

There is no Content-Type header for the emp body part. In the client API you can explicitly specify it

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

So I think this is really only part of the complete answer. As I said, I am not familiar with Postman. Therefore, I do not know how to set the Content-Type for individual parts of the body. image/png for the image was automatically configured for me for part of the image (I think it was just determined by the file extension). If you can understand this, then the problem must be solved. Please, if you learn how to do this, send it as an answer.




And just for completeness ...

Basic configurations:

Dependence:

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

Client Configuration:

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

Server configuration:

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



UPDATE

Thus, as you can see on the Postman client, some clients cannot set individual Content-Type elements, including the browser, regarding the default capabilities when using FormData (js).

We cannot expect the client to detect this, so when we get the data, we 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); } 

This is a little extra work to get a POJO, but this is a better solution than getting a client to try and find their own solution.

+75
Dec 23 '14 at 5:09
source share

You can access the image file and data from the form using MULTIPART FORM DATA. Using the code below.

 @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) {} } } } 
+1
Oct 18 '15 at 2:08
source share

Your ApplicationConfig must register MultiPartFeature.class from glassfish.jersey.media .. to allow file download

 @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); } 
0
Jan 04 '16 at 18:08
source share

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

When I tried the @peeskillet solution with client-client version 2.21.1, there were 400 errors. It worked when I added the following to my client code:

  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 the call after the request.

0
03 Feb '17 at 9:25
source share

I used the file upload example,

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

in my resource class i am below the 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 a method

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

in tao i

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

in my HBM mapping it looks like

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

This works for all types of files, such as .PDF, .TXT, .PNG, etc.,

-2
Jul 20 '16 at 6:37
source share

Install "Content-Type: multipart / form-data" on the client side and this should complete the task

-four
Mar 13 '18 at 19:52
source share



All Articles