Файлы загрузки от клиента Java к серверу HTTP

Я бы предложил разделить вашу функцию на две части. Оставьте итеративную часть doSomething и выделите то, что вы хотите сделать.

template<typename T> void theThing(T one);

template<>
void theThing<MyClass_one>(MyClass_one one) {
    cout << "im one" << endl;
}

template<>
void theThing<MyClass_two>(MyClass_two one) {
    cout << "im two" << endl;
}

template<typename T, typename ... Ts>
void doSomething(T one, Ts...two) {
    theThing(one);
}

Таким образом, вы можете иметь специализированные вещи для каждого класса, который вы хотите использовать. Бонус, он не будет компилироваться для типов, для которых theThing не специализируется.

64
задан BalusC 3 February 2016 в 13:44
поделиться

3 ответа

Обычно вы используете java.net.URLConnection для запуска HTTP-запросов. Вы также обычно используете кодировку multipart / form-data для смешанного содержимого POST (двоичные и символьные данные). Щелкните ссылку, она содержит информацию и пример того, как составить тело запроса multipart / form-data . Спецификация более подробно описана в RFC2388 .

Вот начальный пример:

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

Этот код менее подробен, если вы используете стороннюю библиотеку, такую ​​как Apache Commons HttpComponents Client .

Apache Commons FileUpload , как некоторые ошибочно предполагают, представляет интерес только на стороне сервера . Вы не можете использовать и не нуждаетесь в нем на стороне клиента.

См. Также

93
ответ дан 24 November 2019 в 15:50
поделиться

Вот то, как Вы могли сделать это с java.net.http пакетом 11 Java:

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

}
1
ответ дан 24 November 2019 в 15:50
поделиться

Это может зависеть от вашего фреймворка. (для каждого из них могло существовать более простое решение).

Но отвечу на ваш вопрос: существует множество внешних библиотек для этой функции. Посмотрите здесь , как использовать apache commons fileupload.

-6
ответ дан 24 November 2019 в 15:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: