Create Rest Web Service to receive an Image

17,819

Solution 1

Example REST Web Service Java Class to Recieve Image

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataParam;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;


@Path("/upload")
public class Upload_Documents {


    private static final String UPLOAD_FOLDER = "c:/uploadedFiles/";

    @Context
    private UriInfo context;
    /**
     * Returns text response to caller containing uploaded file location
     * 
     * @return error response in case of missing parameters an internal
     *         exception or success response if file has been stored
     *         successfully
     */
    @POST
    @Path("/pic")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadFile(
            @FormDataParam("file") InputStream uploadedInputStream,
            @FormDataParam("file") FormDataContentDisposition fileDetail) {

        System.out.println("Called Upload Image");
        // check if all form parameters are provided
        if (uploadedInputStream == null || fileDetail == null)
            return Response.status(400).entity("Invalid form data").build();
        // create our destination folder, if it not exists
        try {
            createFolderIfNotExists(UPLOAD_FOLDER);
        } catch (SecurityException se) {
            return Response.status(500)
                    .entity("Can not create destination folder on server")
                    .build();
        }
        String uploadedFileLocation = UPLOAD_FOLDER + fileDetail.getFileName();
        try {
            saveToFile(uploadedInputStream, uploadedFileLocation);
        } catch (IOException e) {
            return Response.status(500).entity("Can not save file").build();
        }
        return Response.status(200)
                .entity("File saved to " + uploadedFileLocation).build();
    }
    /**
     * Utility method to save InputStream data to target location/file
     * 
     * @param inStream
     *            - InputStream to be saved
     * @param target
     *            - full path to destination file
     */
    private void saveToFile(InputStream inStream, String target)
            throws IOException {
        OutputStream out = null;
        int read = 0;
        byte[] bytes = new byte[1024];
        out = new FileOutputStream(new File(target));
        while ((read = inStream.read(bytes)) != -1) {
            out.write(bytes, 0, read);
        }
        out.flush();
        out.close();
    }
    /**
     * Creates a folder to desired location if it not already exists
     * 
     * @param dirName
     *            - full path to the folder
     * @throws SecurityException
     *             - in case you don't have permission to create the folder
     */
    private void createFolderIfNotExists(String dirName)
            throws SecurityException {
        File theDir = new File(dirName);
        if (!theDir.exists()) {
            theDir.mkdir();
        }
}
}

Solution 2

Receiving an InputStream is possible in JAX-RS. You just put the InputStream parameter without annotations:

@POST
public void uploadImage(InputStream stream) {
    // store image
}

Pay attention that it will work for any content type.

Although it will work, I would suggest a more "JAX-RS way":

1 Create provider that will create an image class (e.g. java.awt.Image) from the InputStream:

@Provider
@Consumes("image/jpeg")
class ImageProvider implements MessageBodyReader<Image> {

    public Image readFrom(Class<Image> type,
                                Type genericType,
                                Annotation[] annotations,
                                MediaType mediaType,
                                MultivaluedMap<String, String> httpHeaders,
                                InputStream entityStream) throws IOException,
        WebApplicationException {
       // create Image from stream
    }
}

2 Register the provider the same way you register a resource.
3 Make your resource class to receive Image instead of InputStream.

Why is this approach better?
You separate the deserialization logic from your resource class. So if in the future you would like to support more image formats, you just need to add additional providers, while the resource will stay the same.

Share:
17,819
c12
Author by

c12

Updated on June 12, 2022

Comments

  • c12
    c12 almost 2 years

    How would you design a REST based web service that receives an image file in the form of an InputStream? If the InputStream is posted to a REST end point, how does that end point receive it so that it can create an image file?

  • c12
    c12 about 13 years
    Hi Tarlog, for your first method, how would you send the request to the endpoint? Would the InputStream be a form param? I'm using the google rest client to simulate a request and I don't understand how to test this...
  • Tarlog
    Tarlog about 13 years
    @c12: Sorry, I'm not familiar with Google Rest Client. But it should not be a form param, but a request body. With Wink Client it would be something like: new RestClient().resource(url).post(body), while body is OutputStream.
  • c12
    c12 about 13 years
    thanks for the quick reply, I don't think the Rest Client supports it. I will try what you suggested with HTTPClient, maybe that will work..
  • c12
    c12 about 13 years
    for the second solution, is it possible to augment it so it accepts form params as well?
  • c12
    c12 about 13 years
    sorry for all the questions, but how would you execute the second solution based off the url context? How would a post map to that provider?
  • Tarlog
    Tarlog about 13 years
    Apache Wink (incubator.apache.org/wink) supports the code I wrote, the benefit using it: you can reuse the JAX-RS providers.
  • Tarlog
    Tarlog about 13 years
    You cannot receive an InputStream as a form-parameter with JAX-RS.
  • Tarlog
    Tarlog about 13 years
    >how would you execute the second solution based off the url context? How would a post map to that provider? - sorry, but I don't understand the question. Provider is used to serialize/deserialize the message body. If you need an access to request information, you can use @Context UriInfo.
  • Sudheer Kumar
    Sudheer Kumar almost 11 years
    @Tarlog Can you send me example? Please mail me [email protected]
  • GGO
    GGO over 6 years
    We would like to have some explanations
  • Mallikarjuna
    Mallikarjuna over 6 years
    The file is pushed over HTTP POST with encoding type “multipart/form-data” from the client to our web-service. This way you can add multiple parameters to the POST request in addition to the file. Lets start with the requirements. You will need an web/application server like Tomcat, GlassFish or JBoss to deploy the service. In addition we will use jersey framework to build our service endpoint. Please note, GlassFish 4.x version requires jersey version 2 libraries, so if you are using GlassFish 4 use jersey 2.x dependencies. javatutorial.net/java-file-upload-rest-service
  • GGO
    GGO over 6 years
    You can edit answer instead ;) sorry it's the moderation
  • sns
    sns over 5 years
    how can I do it without Jersey or spring. without any annotation or special framework. I use plain httphandler and maven dependencies.