Search code examples
javaangularjsjax-rsresteasy

How can I upload image and data in the same request with angular and resteasy?


I'm facing a problem to make a angular crud with jax-rs on backend. The crud is very simple, some text fields and a image field.

I have the code working to upload a image:

@POST
@Consumes("multipart/form-data")
public Response uploadFile(MultipartFormDataInput input) {
    ...
}

And in the html layer:

<form action="http://localhost:8080/app/api/user" method="post" enctype="multipart/form-data">
   <p>
    Choose a file : <input type="file" name="file" />
   </p>
   <input type="submit" value="Upload" />
</form>

So, my question is how can I do this in one step like this:

@POST
@Consumes("multipart/form-data")
public Response save(MultipartFormDataInput input, MyEntity entity) {
    ...
}

If I try to call the code above from view layer, the wildfly give a error that doesn't found data to bind with MyEntity parameter.

[org.jboss.resteasy.core.ExceptionHandler] (default task-3) failed to execute: javax.ws.rs.NotSupportedException: 
Could not find message body reader for type: class mypackage.MyEntity of content type: multipart/form-data;boundary=----WebKitFormBoundaryRXVvqLpZACPylNgS

Does anyone knows how can I do that? Or shoud I do it in two steps?


Solution

  • Technically, you can just get both pieces of data from the MultipartFormDataInput. For example

    <form action="api/upload" method="post" enctype="multipart/form-data">
        Choose a file : <input type="file" name="file" />
        First name: <input type="text" name="firstname" />
        List name: <input type="text" name="lastname" />
        <input type="submit" value="Upload" />
    </form>
    
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response upload(MultipartFormDataInput multipart) throws IOException {
    
        try (InputStream in = multipart.getFormDataPart("file", InputStream.class, null);
             FileOutputStream fos = new FileOutputStream("file.png")) {
            byte[] buff = new byte[1024];
            int count;
            while ((count = in.read(buff)) != -1) {
                fos.write(buff, 0, count);
            }
        }
    
        String firstname = multipart.getFormDataPart("firstname", String.class, null);
        String lastname = multipart.getFormDataPart("lastname", String.class, null);
        return Response.ok(firstname + ":" + lastname).build();
    }
    

    If you want to put everything into a POJO, you can do something like this

    public class MyEntity {
    
        @FormParam("firstname")
        private String firstname;
    
        @FormParam("lastname")
        private String lastname;
    
        @FormParam("file")
        private byte[] file;
    
        // Getter and Setters
    }
    

    Then in your resource method

    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response upload(@MultipartForm MyEntity entity) throws IOException {
    
        try (FileOutputStream fos = new FileOutputStream("file.png")) {
            byte[] filebytes = entity.getFile();
            fos.write(filebytes);
        }
    
        String firstname = entity.getFirstname();
        String lastname = entity.getLastname();
        return Response.ok(firstname + ":" + lastname).build();
    }
    

    See more: