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

将文件从Java客户端上载到HTTP服务器,java,file-upload,urlconnection,Java,File Upload,Urlconnection,我想上传一些文件到HTTP服务器。基本上,我需要的是向服务器发送一个POST请求,其中包含一些参数和文件。我看过一些上传文件的例子,但没有找到如何传递额外的参数 最简单的免费解决方案是什么?有没有人有我可以学习的文件上传示例?我已经在谷歌上搜索了几个小时,但(也许这只是其中的一天)找不到我真正需要的东西。最好的解决方案是不涉及任何第三方类或库的解决方案。这可能取决于您的框架。(对于每一个问题都可能存在一个更简单的解决方案) 但要回答您的问题:对于此功能,有很多。查看如何使用apache comm

我想上传一些文件到HTTP服务器。基本上,我需要的是向服务器发送一个POST请求,其中包含一些参数和文件。我看过一些上传文件的例子,但没有找到如何传递额外的参数


最简单的免费解决方案是什么?有没有人有我可以学习的文件上传示例?我已经在谷歌上搜索了几个小时,但(也许这只是其中的一天)找不到我真正需要的东西。最好的解决方案是不涉及任何第三方类或库的解决方案。

这可能取决于您的框架。(对于每一个问题都可能存在一个更简单的解决方案)

但要回答您的问题:对于此功能,有很多。查看如何使用apache commons文件上载。

通常用于触发HTTP请求。您通常也会对混合的帖子内容(二进制和字符数据)使用编码。单击该链接,它包含信息和如何组成
多部分/表单数据的示例。有关规范的详细信息,请参阅

以下是一个启动示例:

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
当您使用第三方库(如ApacheCommons)时,此代码就不那么冗长了

有些人错误地认为,Apache Commons只对服务器端感兴趣。您不能在客户端使用,也不需要它

另见

以下是您使用的方法(此解决方案适用于不介意使用第三方库的用户):


并在html中使用
,单击链接获取示例文件上载clint java with apache HttpComponents

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

和图书馆downalod链接

使用4.5.3.zip在我的代码中运行良好

还有我的工作代码

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

}

以下是如何使用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());
使用以下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;
    }

}
公共类MimeMultipartData{
公共静态类生成器{
私有字符串边界;
私有字符集Charset=StandardCharsets.UTF_8;
私有列表文件=新的ArrayList();
私有映射文本=新LinkedHashMap();
私人建筑商(){
this.boundary=new BigInteger(128,new Random()).toString();
}
带有字符集的公共生成器(字符集字符集){
this.charset=charset;
归还这个;
}
带边界的公共生成器(字符串边界){
this.boundary=边界;
归还这个;
}
公共生成器addFile(字符串名称、路径、字符串mimeType){
添加(新的mimefile(名称、路径、mimeType));
归还这个;
}
公共生成器addText(字符串名称、字符串文本){
文本。输入(名称、文本);
归还这个;
}
public MimeMultipartData build()引发IOException{
MimeMultipartData MimeMultipartData=新的MimeMultipartData();
mimeMultipartData.boundary=边界;
var newline=“\r\n”.getBytes(字符集);
var byteArrayOutputStream=新的byteArrayOutputStream();
for(var f:files){
byteArrayOutputStream.write(“-”+boundary.getBytes(charset));
byteArrayOutputStream.write(换行符);
byteArrayOutputStream.write((“内容处置:表单数据;名称=\”“+f.name+”\“文件名=\”“+f.path.getFileName()+”\).getBytes(字符集));
byteArrayOutputStream.write(换行符);
byteArrayOutputStream.write((“内容类型:+f.mimeType).getBytes(字符集));
byteArrayOutputStream.write(换行符);
byteArrayOutputStream.write(换行符);
byteArrayOutputStream.write(Files.readAllBytes(f.path));
byteArrayOutputStream.write(换行符);
}
for(变量条目:text.entrySet()){
byteArrayOutputStream.write(“-”+boundary.getBytes(charset));
byteArrayOutputStream.write(换行符);
byteArrayOutputStream.write((“内容处置:表单数据;名称=\”“+entry.getKey()+“\”).getBytes(字符集));
byteArrayOutputStream.write(换行符);
byteArrayOutputStream.write(换行符);
byteArrayOutputStream.write(entry.getValue().getBytes(charset));
byteArrayOutputStream.write(换行符);
}
byteArrayOutputStream.write((“-”+boundary+“-”).getBytes(字符集));
mimeMultipartData.bodyPublisher=bodyPublisher.of字节数组(byteArrayOutputStream.toByteArray());
返回mimultipartdata;
}
公共类模拟文件{
公共最终字符串名;
公共最终路径;
公共最终字符串mimeType;
公共mimefile(字符串名称、路径、字符串mimeType){
this.name=名称;
this.path=path;
this.mimeType=mimeType;
}
}
}
私有字符串边界;
私人实体出版商;
私有MimeMultipartData(){
}
公共静态生成器newBuilder(){
返回新的生成器();
}
public BodyPublisher getBodyPublisher()引发IOException{
返回bodyPublisher;
}
公共字符串getContentType(){
返回“多部分/表单数据;边界=”+边界;
}
}

谢谢,我试试看。问题是关于这一行:writer.println(paramToSend);我不应该使用编码器来编码这个值吗?还是按原样发送?不,它是
多部分/表单数据
,而不是
应用程序/x-www-form-urlencoded
。但是,您希望指定使用的字符集。我已经相应地更新了答案。我刚刚尝试过。有点问题:(另一端的PHP脚本将整个内容视为post参数
    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());
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;
    }

}