70

I'd like to upload a few files to a HTTP server. Basically what I need is some sort of a POST request to the server with a few parameters and the files. I've seen examples of just uploading files, but didn't find how to also pass additional parameters.

What's the simplest and free solution of doing this? Does anyone have any file upload examples that I could study? I've been googling for a few hours, but (maybe it's just one of those days) couldn't find exactly what I needed. The best solution would be something that doesn't involve any third party classes or libraries.

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
Marius
  • 3,726
  • 5
  • 33
  • 50

7 Answers7

102

You'd normally use java.net.URLConnection to fire HTTP requests. You'd also normally use multipart/form-data encoding for mixed POST content (binary and character data). Click the link, it contains information and an example how to compose a multipart/form-data request body. The specification is in more detail described in RFC2388.

Here's a kickoff example:

String url = "http://example.com/upload";
String charset = "UTF-8";
String param = "value";
File textFile = new File("/path/to/file.txt");
File binaryFile = new File("/path/to/file.bin");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
String CRLF = "\r\n"; // Line separator required by multipart/form-data.

URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

try (
    OutputStream output = connection.getOutputStream();
    PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
) {
    // Send normal param.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
    writer.append(CRLF).append(param).append(CRLF).flush();

    // Send text file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); // Text file itself must be saved in this charset!
    writer.append(CRLF).flush();
    Files.copy(textFile.toPath(), output);
    output.flush(); // Important before continuing with writer!
    writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.

    // Send binary file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF);
    writer.append("Content-Transfer-Encoding: binary").append(CRLF);
    writer.append(CRLF).flush();
    Files.copy(binaryFile.toPath(), output);
    output.flush(); // Important before continuing with writer!
    writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.

    // End of multipart/form-data.
    writer.append("--" + boundary + "--").append(CRLF).flush();
}

// Request is lazily fired whenever you need to obtain information about response.
int responseCode = ((HttpURLConnection) connection).getResponseCode();
System.out.println(responseCode); // Should be 200

This code is less verbose when you use a 3rd party library like Apache Commons HttpComponents Client.

The Apache Commons FileUpload as some incorrectly suggest here is only of interest in the server side. You can't use and don't need it at the client side.

See also

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • Thanks, i'll try it. The question is though about this line: writer.println(paramToSend); Shouldn't i use Encoder to encode this value? Or is it sent the way it is? – Marius Mar 18 '10 at 12:07
  • No, it's `multipart/form-data`, not `application/x-www-form-urlencoded`. You however would like to specify the charset used. I've updated the answer accordingly. – BalusC Mar 18 '10 at 12:18
  • I've just tried it. Something's wrong :( The PHP script on the other end sees the entire thing as a post parameter. It thinks that the "Content-type...etc." is the parameter and everything else is the value. I'm using linux, can it be an issue with println, since AFAIK these things should use \r\n endlines? Or is it just something missing? – Marius Mar 18 '10 at 13:01
  • Never mind, i figured that content type shouldn't be written to the body and sent as a header so the following line fixed it: connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); – Marius Mar 18 '10 at 13:21
  • Yes, you're right. I updated the example accordingly (it was just written from head, you see ;) ). – BalusC Mar 18 '10 at 13:25
  • When i am using this code to upload a text file , its getting upload correctly but In case of image file its uploading incorrectly , I had changed content-type also to image/jpeg. for ex: if i am uploading an image of 6kb its showing 10kb on server and when trying to view that image showing nothing. please suggest me what changes need to make. – vips Oct 23 '13 at 06:21
  • @vips: just write it as byte stream not as character stream. See also http://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests/2793153#2793153 – BalusC Oct 23 '13 at 09:09
  • Balus, your example in no location ever uses a catch block! Every exception must be caught or thrown! .... Also, i am new to URL based things in java, but are the nested try blocks needed? It seems a bit messy in my mind, but feel free to correct me if this is actually needed for some strange reason :P I'm used to running one thing that throws an exception within a try, catching its errors, then closing the try-catch and moving on.... perhaps just a difference in style. :) – Drifter64 Jan 24 '14 at 20:35
  • 1
    @Drifter64: uh, just add `throws IOException` to method as in `public void foo() throws IOException`. There's no sensible way to handle the exception in the code posted so far, so the caller is responsible for doing that. See also Oracle's basic Java tutorial on exceptions. The nested try blocks are in this particular case definitely needed as external resources must guaranteed be freed up after use, otherwise your application will kill the runtime environment sooner or later by letting it to run out of resources. This is absolutely not a style matter. It's just writing code the right way. – BalusC Jan 24 '14 at 20:36
  • Great, it worked! and now, the problem is I want to get a response that returned from Server. How can I catch it? :) Thanks! – Disapamok Jun 02 '16 at 11:26
  • @Sahan: in my answers, you usually just have to check the "See also" list in bottom to find links to spinoff questions. – BalusC Jun 02 '16 at 11:34
38

Here is how you would do it with Apache HttpClient (this solution is for those who don't mind using a 3rd party library):

    HttpEntity entity = MultipartEntityBuilder.create()
                       .addPart("file", new FileBody(file))
                       .build();

    HttpPost request = new HttpPost(url);
    request.setEntity(entity);

    HttpClient client = HttpClientBuilder.create().build();
    HttpResponse response = client.execute(request);
Emmanuel Bourg
  • 8,902
  • 2
  • 42
  • 71
  • 13
    MultipartEntity is deprecated, we have to use MultipartBuilder instead: `HttpEntity entity = MultipartEntityBuilder.create().addTextBody("field1", "value1").addBinaryBody("myfile", new File("/path/file1.txt"), ContentType.create("application/octet-stream"), "file1.txt").build();` – encrest Sep 14 '15 at 17:57
  • You will also need to replace the deprecated DefaultHttpClient like this: HttpClient client = HttpClientBuilder.create().build(); – mmaceachran Sep 29 '17 at 22:19
6

click link get example file upload clint java with apache HttpComponents

http://hc.apache.org/httpcomponents-client-ga/httpmime/examples/org/apache/http/examples/entity/mime/ClientMultipartFormPost.java

and library downalod link

https://hc.apache.org/downloads.cgi

use 4.5.3.zip it's working fine in my code

and my working code..

import java.io.File;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class ClientMultipartFormPost {

     public static void main(String[] args) throws Exception {

          CloseableHttpClient httpclient = HttpClients.createDefault();
          try {
             HttpPost httppost = new HttpPost("http://localhost:8080/MyWebSite1/UploadDownloadFileServlet");

             FileBody bin = new FileBody(new File("E:\\meter.jpg"));
             StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN);

             HttpEntity reqEntity = MultipartEntityBuilder.create()
                .addPart("bin", bin)
                .addPart("comment", comment)
                .build();


             httppost.setEntity(reqEntity);

             System.out.println("executing request " + httppost.getRequestLine());
             CloseableHttpResponse response = httpclient.execute(httppost);
           try {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                     System.out.println("Response content length: " +    resEntity.getContentLength());
                }
              EntityUtils.consume(resEntity);
             } finally {
                 response.close();
            }
       } finally {
          httpclient.close();
      }
   }

}
Prashant
  • 121
  • 1
  • 5
1

Here is how you could do it with Java 11's java.net.http package:

    var fileA = new File("a.pdf");
    var fileB = new File("b.pdf");

    var mimeMultipartData = MimeMultipartData.newBuilder()
            .withCharset(StandardCharsets.UTF_8)
            .addFile("file1", fileA.toPath(), Files.probeContentType(fileA.toPath()))
            .addFile("file2", fileB.toPath(), Files.probeContentType(fileB.toPath()))
            .build();

    var request = HttpRequest.newBuilder()
            .header("Content-Type", mimeMultipartData.getContentType())
            .POST(mimeMultipartData.getBodyPublisher())
            .uri(URI.create("http://somehost/upload"))
            .build();

    var httpClient = HttpClient.newBuilder().build();
    var response = httpClient.send(request, BodyHandlers.ofString());

With the following MimeMultipartData:

public class MimeMultipartData {

    public static class Builder {

        private String boundary;
        private Charset charset = StandardCharsets.UTF_8;
        private List<MimedFile> files = new ArrayList<MimedFile>();
        private Map<String, String> texts = new LinkedHashMap<>();

        private Builder() {
            this.boundary = new BigInteger(128, new Random()).toString();
        }

        public Builder withCharset(Charset charset) {
            this.charset = charset;
            return this;
        }

        public Builder withBoundary(String boundary) {
            this.boundary = boundary;
            return this;
        }

        public Builder addFile(String name, Path path, String mimeType) {
            this.files.add(new MimedFile(name, path, mimeType));
            return this;
        }

        public Builder addText(String name, String text) {
            texts.put(name, text);
            return this;
        }

        public MimeMultipartData build() throws IOException {
            MimeMultipartData mimeMultipartData = new MimeMultipartData();
            mimeMultipartData.boundary = boundary;

            var newline = "\r\n".getBytes(charset);
            var byteArrayOutputStream = new ByteArrayOutputStream();
            for (var f : files) {
                byteArrayOutputStream.write(("--" + boundary).getBytes(charset)); 
                byteArrayOutputStream.write(newline);
                byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"" + f.name + "\"; filename=\"" + f.path.getFileName() + "\"").getBytes(charset));
                byteArrayOutputStream.write(newline);
                byteArrayOutputStream.write(("Content-Type: " + f.mimeType).getBytes(charset));
                byteArrayOutputStream.write(newline);
                byteArrayOutputStream.write(newline);
                byteArrayOutputStream.write(Files.readAllBytes(f.path));
                byteArrayOutputStream.write(newline);
            }
            for (var entry: texts.entrySet()) {
                byteArrayOutputStream.write(("--" + boundary).getBytes(charset));
                byteArrayOutputStream.write(newline);
                byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"").getBytes(charset));
                byteArrayOutputStream.write(newline);
                byteArrayOutputStream.write(newline);
                byteArrayOutputStream.write(entry.getValue().getBytes(charset));
                byteArrayOutputStream.write(newline);
            }
            byteArrayOutputStream.write(("--" + boundary + "--").getBytes(charset));

            mimeMultipartData.bodyPublisher = BodyPublishers.ofByteArray(byteArrayOutputStream.toByteArray());
            return mimeMultipartData;
        }

        public class MimedFile {

            public final String name;
            public final Path path;
            public final String mimeType;

            public MimedFile(String name, Path path, String mimeType) {
                this.name = name;
                this.path = path;
                this.mimeType = mimeType;
            }
        }
    }

    private String boundary;
    private BodyPublisher bodyPublisher;

    private MimeMultipartData() {
    }

    public static Builder newBuilder() {
        return new Builder();
    }

    public BodyPublisher getBodyPublisher() throws IOException {
        return bodyPublisher;
    }

    public String getContentType() {
        return "multipart/form-data; boundary=" + boundary;
    }

}
0
public static String simSearchByImgURL(int  catid ,String imgurl) throws IOException{
    CloseableHttpClient httpClient = HttpClients.createDefault();
    CloseableHttpResponse response = null;
    String result =null;
    try {
        HttpPost httppost = new HttpPost("http://api0.visualsearchapi.com:8084/vsearchtech/api/v1.0/apisim_search");
        StringBody catidBody = new StringBody(catid+"" , ContentType.TEXT_PLAIN);
        StringBody keyBody = new StringBody(APPKEY , ContentType.TEXT_PLAIN);
        StringBody langBody = new StringBody(LANG , ContentType.TEXT_PLAIN);
        StringBody fmtBody = new StringBody(FMT , ContentType.TEXT_PLAIN);
        StringBody imgurlBody = new StringBody(imgurl , ContentType.TEXT_PLAIN);
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.addPart("apikey", keyBody).addPart("catid", catidBody)
        .addPart("lang", langBody)
        .addPart("fmt", fmtBody)
        .addPart("imgurl", imgurlBody);
        HttpEntity reqEntity =  builder.build();
        httppost.setEntity(reqEntity);
        response = httpClient.execute(httppost);
        HttpEntity resEntity = response.getEntity();
        if (resEntity != null) {
           // result = ConvertStreamToString(resEntity.getContent(), "UTF-8");
            String charset = "UTF-8";   
          String content=EntityUtils.toString(response.getEntity(), charset);   
            System.out.println(content);
        }
        EntityUtils.consume(resEntity);
    }catch(Exception e){
        e.printStackTrace();
    }finally {
        response.close();
        httpClient.close();
    }
    return result;
}
deeplinks
  • 36
  • 2
  • Try example above. It's from this site http://www.visualsearchapi.com . Full code link is here http://www.visualsearchapi.com/apiDoc/apiDoc?apiDoc=V . Good luck. – deeplinks Sep 04 '16 at 11:20
-2
protected void doPost(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {

    boolean isMultipart = ServletFileUpload.isMultipartContent(request);

    if (!isMultipart) {
        return;
    }

    DiskFileItemFactory factory = new DiskFileItemFactory();

    factory.setSizeThreshold(MAX_MEMORY_SIZE);

    factory.setRepository(new File(System.getProperty("java.io.tmpdir")));

    String uploadFolder = getServletContext().getRealPath("")
            + File.separator + DATA_DIRECTORY;//DATA_DIRECTORY is directory where you upload this file on the server

    ServletFileUpload upload = new ServletFileUpload(factory);

    upload.setSizeMax(MAX_REQUEST_SIZE);//MAX_REQUEST_SIZE is the size which size you prefer

And use <form enctype="multipart/form-data"> and use <input type="file"> in the html

aman207
  • 878
  • 2
  • 10
  • 19
user1693371
  • 95
  • 1
  • 3
  • That's for the server side (servlet). OP was asking for a Java CLIENT. – Stefan Reich Jul 26 '16 at 21:48
  • there is no reason to downvote just because it does not directly answer OPs question. most of the people coming here are from badly framed google seaches and they would find an answer like this helpful. – Kinjal Dixit Jan 27 '20 at 08:06
-6

It could depend on your framework. (for each of them could exist an easier solution).

But to answer your question: there are a lot of external libraries for this functionality. Look here how to use apache commons fileupload.

Karussell
  • 16,303
  • 14
  • 88
  • 188
  • 1
    I didn't downvote, but I would guess that it is for the same reason the other answer got downvoted. You answer how to receive an uploaded file using servlets, the question is asking how to send a file. And specifically, with additional data in the POST. In general, if you paraphrase or copy out the useful/relevant sections from the pages you link to it will make the answers more useful to readers and preserve the usefulness if the links ever go dead. – Arkaine55 Oct 15 '14 at 14:13