In this tutorial, we will learn how do to file upload with Jersey, A RESTFul Webservice(JAX-RS) implementation.
File upload feature of html form works by wrapping the file content inside a multipart envelope as the content type “application/x-www-form-urlencoded” is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type “multipart/form-data” should be used for submitting forms that contain files, non-ASCII data, and binary data.
-
Resolve Dependency
For the “multipart/form-data” support we need to include “jersey-multipart.jar” and dependencies from here [for glassfish v3.1 & upward you will find it in glassfish\modules].
-
<html> <body> <h1>Upload File with RESTFul WebService</h1> <form action="rest/fileupload" method="post" enctype="multipart/form-data"> <p> Choose a file : <input type="file" name="file" /> </p> <input type="submit" value="Upload" /> </form> </body> </html>
-
Java File Upload Client
We will use Apache HTTPClient library to resolve dependency. It is an optional step & the code could be exploited to build a test-client.
HttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost(url); FileBody fileContent= new FileBody(new File(fileName)); StringBody comment = new StringBody("Filename: " + fileName); MultipartEntity reqEntity = new MultipartEntity(); reqEntity.addPart("file", fileContent); httppost.setEntity(reqEntity); HttpResponse response = httpclient.execute(httppost); HttpEntity resEntity = response.getEntity();
-
Create JAX-RS File Upload Service with Jersey
Jersey uses
@FormDataParam
to receive the uploaded file. To get the uploaded file name or header detail, compare with “FormDataContentDisposition
” which represents a “Content-Disposition” header whose value is “form-data”.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.POST; import javax.ws.rs.Path; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.sun.jersey.core.header.FormDataContentDisposition; import com.sun.jersey.multipart.FormDataParam; @Path("/fileupload") public class UploadFileService { @POST @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadFile( @FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail) { String uploadedFileLocation = "c://uploadedFiles/" + fileDetail.getFileName(); // save it saveToFile(uploadedInputStream, uploadedFileLocation); String output = "File uploaded via Jersey based RESTFul Webservice to: " + uploadedFileLocation; return Response.status(200).entity(output).build(); } // save uploaded file to new location private void saveToFile(InputStream uploadedInputStream, String uploadedFileLocation) { try { OutputStream out = null; int read = 0; byte[] bytes = new byte[1024]; out = new FileOutputStream(new File(uploadedFileLocation)); while ((read = uploadedInputStream.read(bytes)) != -1) { out.write(bytes, 0, read); } out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } }
-
Test Your Service
- Deploy & Browse to {App_URL}/{File_Upload_html}
- Upload A file and check.
-
Source Code
You can download source-code here.
kesavan said:
Hi, Is it possible to inject the uploaded file into HttpServletRequest object ?
getFile(@FormDataParam(“file”) HttpServletRequest request). When I tried, I am getting the exception “No message body reader found for request class : HttpServletRequest, ContentType : multipart/form-data;boundary”
Puspendu Banerjee said:
Can you please check if you have any mime parser in place.
Diego said:
hi, i have this problem:
A message body reader for Java class com.sun.jersey.multipart.FormDataMultiPart, and Java type class com.sun.jersey.multipart.FormDataMultiPart, and MIME media type application/octet-stream was not found.
Puspendu Banerjee said:
That indicates, your mime parser is not configured properly. Are you trying to upload an non-text file, e.g. jpg or wav?
Kishore said:
Hi, I was trying with the sample you provided. However while dumping the data to a file I see the following information is also dumped.
–U2BZz2mXCI9zSl_7WyaVKUQ5VHwQfTDKPIz2-
Content-Disposition: form-data; name=”image”; filename=”Image.png”
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Since this boundary markers, content information is also embed in the InputStream, the file that is created has become an invalid file. What am I missing here?
Any suggestions?
Thanks in advance,
Kishore
Puspendu Banerjee said:
It seems that you are handling it as raw inputstream rather Multipart formdata
Kishore said:
Thanks for the reply. I was trying the same sample you provided above. Following is the code snippet…
ResponseEntity uploadFile(
@FormDataParam(“file”) InputStream fileInputStream,
@FormDataParam(“file”) FormDataContentDisposition contentDispositionHeader) {
…..
}
Puspendu Banerjee said:
As I said earlier that, it seems that you are using RAW inputStream.
You need to modify
@FormDataParam("file")
to@FormDataParam("image")
Most likely your client-side code[ I assume html] has an input of
type="file" name="image"
.You need to match the name of the input to the argument to
FormDataParam
.Let me know & rate the blog.
Sudha Velan said:
Hi
Nice Post…
I tried it but i an getting 415 error..
Can u pls tell me where i could have done wrong..Because i tried as you post.
Puspendu Banerjee said:
HTTP 415 means Unsupported media type.
Check your server log. There might be more information.
preeti said:
Hi,
Cam you please upload the code to send an xml file from client to the restful webservice .
Puspendu Banerjee said:
Sorry for late in reply.
What kind of client you are using standalone-java/browser based javascript or something else?
yuwei said:
thank you very much. Your article is very clear and save me lots of time !
Gene said:
I, with the help of a friend, figured out what was causing my boundary error as stated by avitra back in January. I failed to add the mimepull to the in the pom.xml. The dependency was listed but not the include. Thanks again for a great example.
Puspendu Banerjee said:
Just seen, your reply.
Thanks for sharing the information.
It will be really nice, if you can share the code, that case I shall upload it with the post.
Gene said:
This is a great article, good job and thanks.
I am attempting to replicate this in an app using Maven and encountering the error listed by avitra on January 22, 2013 at 9:17 pm. I was able to run this as an independent app without Maven. Any suggestions?
Puspendu Banerjee said:
Hi Gene,
Most likely, you are missing some runtime dependency with maven.
If you send me the complete maven project & server/container details I shall try to look into that.
Thanks again. Keep up-voting 🙂
lakshmi said:
3rd step am not clear…. can u pls help me
Puspendu Banerjee said:
It’s optional
yuwei said:
lakshmi:
here are some class you may need to import while writing your client based on Puspendu’s work. you can be download jars on internet and place them into your application’s lib (or classpath)
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.util.EntityUtils;
although you do not need “mimepull.jar” to compile, but you need to put it in your lib while running. (if not, you may get a http 415 error and … I do not know why )
Puspendu Banerjee said:
Nice job Teer. Most Likely “mimepull.jar” is required to satisfy runtime dependency of Apache HttpClient.
Better I create a maven project & share.
John said:
Hi, thx for this tutorial. It’s my first web service.
I got a problem when I click on “upload”
State HTTP 404 – /UploadProject/rest/fileupload
Can you help me please ? I think that my web.xml is not good.
UploadProject
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
FileUpload
ws.pck.UploadFileService
FileUpload
/fileupload
Puspendu Banerjee said:
as you said that it is your 1st RESTful Webservice project, I suggest to start with a simpler one like https://puspendu.wordpress.com/2012/08/24/restful-web-service-submit-form-with-jersey-jax-rs/ & the gradually move towards complex samples.
joe s said:
Where does the apache code go?
Puspendu Banerjee said:
It has been clearly mentioned that that code-piece will be a part of RESTful Client application.
loulou said:
Hi ,I have to upload file from external machin can i do it with the same code? i use mule studio and i have to call restful web service from mule .
Puspendu Banerjee said:
ok, but what is the problem that you are facing in this context?
loulou said:
hello thanks for your replay ,First problem is that i don’t know if i can do it or not ,second problem how can to do it?
Puspendu Banerjee said:
Definitely you can do it. I shall try to put an example for Mule with REST during forthcoming weekends.
BTW, your vote counts, so vote it 🙂
shantanu said:
Hi Puspendu,
thank you for your help
i have completed upload code.
I have also written download code.
I am returning a file with “MediaType.APPLICATION_OCTET_STREAM” in Response
When i use JAVA client :-
—————————————————–
String url = “…”;
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet j = new HttpGet(url);
HttpResponse res=httpclient.execute(j);
HttpEntity resEntity = res.getEntity();
BufferedReader rd = new BufferedReader (new InputStreamReader(res.getEntity().getContent(),”UTF-8″));
String line = “”,tot=””;
File f= new File(fileName);
f.createNewFile();
FileOutputStream fos = new FileOutputStream(f);
while ((line = rd.readLine()) != null) {
tot+=line;
System.out.println(line);
}
fos.write(tot.getBytes());
—————————————————–
it is giving problem.
PDF file cannot be returned in proper format
in TXT file spaces get truncated
Can you help me here?
Puspendu Banerjee said:
BufferedReader.readLine
with something else.shantanu said:
Thank you for a wonderful upload!
REST is stateless protocol.
i am uploading files from different clients
i want to send the client id (String) as well as the file contents
For such multiple parameters how should i modify your code ?
Puspendu Banerjee said:
It depends on how you are planning to send the Identifier.
If you use a field in the form to carry that identifier as follows:
<input name="clientId" type="hidden" >
You can use the following method signature:
public Response uploadFile(
@FormDataParam("file") InputStream uploadedInputStream,
@FormDataParam("file") FormDataContentDisposition fileDetail,
@FormDataParam("clientId") String clientId
)
shantanu said:
Thank you
for your prompt reply
In the client JAVA file i have added code
reqEntity.addPart(“clientId”, new StringBody(clientID));
is it ok? or there is a better option?
How can i have array of string (String[]) sent to server?
Inkimar said:
Hello Puspendu!
Thank you for your example.
I am getting this to work.
instead of “clientId” i save the ‘owner’ of the file to a database:
-> @FormDataParam(“owner”) String owner .
Let say i want a larger ‘form’ with “owner”, “city”, “country” and such.
My argument list will gradually go from 3 args now to 5 args.
Is there a way to ‘bundle’ all those strings ( as in a servlet , fetching it from the request object ) in one object and pick that object a part in the code – that would look much more appealing to me.
Something like an object named ‘FormData’ ?
Best regards, inki
Puspendu Banerjee said:
Yes, you can use @Formdata to get hold of any form-input element.
The other way is to serialize form & send to service as JSON object, but that will not work for File input type[AFAIK]
yassinedz said:
Hi, i am using Apache HTTPClient library and how can i implement a progress bar while file uploading.
Puspendu Banerjee said:
Please bear with me for long delay in reply.
I need to understand the architecture of the part where you are trying to implement that progress-bar.
Anand said:
Hi, I have gone through this. Its Really usefule for the persons like me who are all new to REST API… Now I am working in REST API for file transfer. I am creating one statndlone HTTP Server. I want to transfer the file from REST Client to REST Service. While using your method, I am not able to start my server. I guess through the @FormDataParam.. Because I did not run the application through browser. I have just a java class to run the file transfer process… Could you please tell me how to do this? And also the error thrown while starting the server.. the method is not a valid resource method…
Puspendu Banerjee said:
Can you please share your project/codebase
Dan said:
Puspendu,
Can you upload your source code because that is the exact piece I’ve been looking for. I need it in our school for my major project..Thank you..
Sekhar said:
Hi Puspendu,
Thanks for the post, do you know to get Request headers in post Rest service where you will receive a file content. if so please post the piece of code.
Puspendu Banerjee said:
Inject directly with
@HeaderParam
Pragmatically via
@Context
avitra said:
Hi Banerjee,
I used the html file and file upload service, when I click the upload button from the html file I am getting following message.
com.sun.jersey.spi.container.ContainerRequest getEntity
SEVERE: A message body reader for Java class com.sun.jersey.multipart.FormDataMultiPart, and Java type class com.sun.jersey.multipart.FormDataMultiPart, and MIME media type multipart/form-data; boundary=—————————7ddb43920504 was not found.
The registered message body readers compatible with the MIME media type are:
*/* ->
com.sun.jersey.core.impl.provider.entity.FormProvider
com.sun.jersey.core.impl.provider.entity.MimeMultipartProvider
.
.
.
com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General
Puspendu Banerjee said:
Looks like a serialization issue. Check the serialization library you are using.
Additionally let me know the App Server/Web Container you are using.
hoshangvarshney said:
I am also getting the same error. Which library am I missing?
sabarish1274 said:
Am not understanding Step 3: Java File Upload Client what exactly that code does. In what name i have to add code to the class. Can you explain it a brief.
esthrim said:
Thanks, great sample, How about if upload/download using base64 string please give another sample i very appreciate it.
Puspendu Banerjee said:
Thanks!
Glad to hear that.
Not pretty sure, what do you mean by “upload/download using base64 string”.
Did you mean base64 encode/decode a file pre-upload/post-download?
esthrim said:
yes, that is what i meant, 🙂
Puspendu Banerjee said:
Till date, Cross browser compatibility for accessing Dom Element File from JavaScript is quite messy.
I shall try to post something on base64 encoding / decoding of file element which will be Firefox compatible, but no guarantee for IE.
irajghasemi said:
Hi
Where can I download you source-code?
Puspendu Banerjee said:
Thanks for pointing out the missing download link.
Copy it and paste for the time being.
I shall upload source at earliest.
Amanda Fenech said:
Could you please attach the source? Very nice post
Puspendu Banerjee said:
you can copy-paste the source & re-create the project.
latrse said:
good job man
Tim said:
Hi! Thanks for your post. That’s exactly what I was looking for. Tim
Puspendu Banerjee said:
Glad to know that! Thanks