简体   繁体   English

将文件从 Java 客户端上传到 HTTP 服务器

[英]Upload files from Java client to a HTTP server

I'd like to upload a few files to a HTTP server.我想将一些文件上传到 HTTP 服务器。 Basically what I need is some sort of a POST request to the server with a few parameters and the files.基本上我需要的是某种带有一些参数和文件的对服务器的 POST 请求。 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.最好的解决方案是不涉及任何第三方类或库的东西。

You'd normally use java.net.URLConnection to fire HTTP requests. 通常,您将使用java.net.URLConnection触发HTTP请求。 You'd also normally use multipart/form-data encoding for mixed POST content (binary and character data). 通常,您还会对混合的POST内容(二进制和字符数据)使用multipart/form-data编码。 Click the link, it contains information and an example how to compose a multipart/form-data request body. 单击该链接,其中包含信息和如何组成multipart/form-data请求正文的示例。 The specification is in more detail described in RFC2388 . 该规范在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 . 当您使用诸如Apache Commons HttpComponents Client之类的第三方库时,此代码不太冗长。

The Apache Commons FileUpload as some incorrectly suggest here is only of interest in the server side . 某些错误建议表明,Apache Commons FileUpload仅在服务器端有用。 You can't use and don't need it at the client side. 您不能在客户端使用它,也不需要它。

See also 也可以看看

Here is how you would do it with Apache HttpClient (this solution is for those who don't mind using a 3rd party library): 这是使用Apache HttpClient的方式 (此解决方案适用于那些不介意使用第3方库的用户):

    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);

click link get example file upload clint java with apache HttpComponents 单击链接获取示例文件,使用apache HttpComponents上传clint java

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

and library downalod link 和图书馆downalod链接

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

use 4.5.3.zip it's working fine in my code 使用4.5.3.zip在我的代码中工作正常

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

}

Here is how you could do it with Java 11's java.net.http package: 这是使用Java 11的java.net.http软件包的方法:

    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: 使用以下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;
    }

}
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;
}

I suggest to use Apache http classes instead of Vanilla Java.我建议使用 Apache http 类而不是原版 Java。 This is a Java 8 compatible simple solution:这是一个兼容 Java 8 的简单解决方案:

// Create http client.

CloseableHttpClient httpClient = HttpClients.createDefault();
final File file = new File("<FILE PATH TO POST>");

// Specify the content type of the attached file.

FileBody filebody = new FileBody(file, ContentType.MULTIPART_FORM_DATA);
MultipartEntityBuilder entitybuilder = MultipartEntityBuilder.create();
entitybuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

// Add the binary file to the entity we send later on.

entitybuilder.addBinaryBody("file", file);
HttpEntity mutiPartHttpEntity = entitybuilder.build();
RequestBuilder reqbuilder = RequestBuilder.post("URL TO POST DATA WITH ALL THE PARAMETERS");
reqbuilder.setEntity(mutiPartHttpEntity);
HttpUriRequest multipartRequest = reqbuilder.build();

// Using the http client, execute http post. Variable httpresponse would contain the reply back explaining http response code, and ...

HttpResponse httpresponse = httpClient.execute(multipartRequest);
httpClient.close();
  1. In order to embed the parameters to the post message, you can simply embed them in the URL used to post data.为了将参数嵌入到 post 消息中,您可以简单地将它们嵌入到用于 post 数据的 URL 中。 Use this rule: ?=&=.使用这条规则:?=&=。 An example would be the following: https://company.com/jobs/status?jobId=876&apiKey=123示例如下: https://company.com/jobs/status?jobId=876&apiKey=123
  2. To find out which data type suites your file which is posted with Http post, see this link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types要找出与 Http 帖子一起发布的文件的数据类型,请参阅此链接: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
  3. Import packages of org.apache.http.* org.apache.http.*的导入包
  4. In case importing did not work, you might need to change pom.xml file (if you are using Maven) and add the Apache package to this xml file. In case importing did not work, you might need to change pom.xml file (if you are using Maven) and add the Apache package to this xml file. See this. 看到这个。
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 并在HTML中使用<form enctype="multipart/form-data">并使用<input type="file">

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. 在这里查看如何使用apache commons fileupload。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何处理从Java客户端上传服务器端HTTP文件 - How to handle Server side HTTP file upload from Java client 从Java客户端应用程序枚举HTTP服务器上的目录/文件 - enumerating directories/files on an HTTP server from a Java client application java:使用POST将文件上传到HTTP服务器,服务器代码是否发布? - java : upload files to HTTP server using POST, server code issue? 如何从Android客户端将媒体文件(图像或mp3歌曲)上传到Java服务器 - How to upload media files(images or mp3 songs ) to java server from android client 如何使用Java将url(http文件)上传到我的Web服务器? - How to Upload url (http files) using Java to my web server? 在没有临时文件的情况下将文件上传到 Java 中的 HTTP 服务器内存? - Upload a file to an HTTP Server Memory in Java without temporal files? Java客户端如何将文件上传到远程HDFS服务器或从远程HDFS服务器下载文件? - How a Java client upload/download a file to/from remote HDFS server? Java Sonatype异步HTTP客户端上载进度 - Java Sonatype Async HTTP Client Upload Progress Java Http 客户端通过POST上传文件 - Java Http Client to upload file over POST Java客户端发送类,服务器从该文件执行方法 - java client send class and server execute a method from this files
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM