この投稿では、プログラムでWebサーバーにファイルをアップロードするJavaクライアントプログラムをコーディングする方法を学びます。

記事「HTMLフォームを使用せずにファイルをサーブレットにアップロードする」では、HTTP POSTリクエストを起動してファイルをサーバーに転送する方法について説明しましたが、そのリクエストのコンテンツタイプはmultipart / form-dataではないため、マルチパートリクエストを処理するサーバーでは機能せず、クライアントとサーバーの両方が必要です。 Javaで実装されています。

この制限を克服するために、この記事では、HTMLコードのアップロードフォームを使用せずに、プログラムでJavaクライアントからWebサーバーにファイルをアップロードする別のソリューションについて説明します。この興味深い解決策を見てみましょう。

 

Javaマルチパートユーティリティクラスのコード:

MultipartUtilityというユーティリティクラスを作成します次のコードで:

1
2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26日
27日
28
29日
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package net.codejava.networking;<font></font>
<font></font>
import java.io.BufferedReader;<font></font>
<font></font>
import java.io.File;<font></font>
import java.io.FileInputStream;<font></font>
import java.io.IOException;<font></font>
import java.io.InputStreamReader;<font></font>
import java.io.OutputStream;<font></font>
import java.io.OutputStreamWriter;<font></font>
import java.io.PrintWriter;<font></font>
import java.net.HttpURLConnection;<font></font>
import java.net.URL;<font></font>
import java.net.URLConnection;<font></font>
import java.util.ArrayList;<font></font>
import java.util.List;<font></font>
<font></font>
/**<font></font>
 * This utility class provides an abstraction layer for sending multipart HTTP<font></font>
 * POST requests to a web server. <font></font>
 * @author www.codejava.net<font></font>
 *<font></font>
 */<font></font>
public class MultipartUtility {<font></font>
    private final String boundary;<font></font>
    private static final String LINE_FEED = "\r\n";<font></font>
    private HttpURLConnection httpConn;<font></font>
    private String charset;<font></font>
    private OutputStream outputStream;<font></font>
    private PrintWriter writer;<font></font>
<font></font>
    /**<font></font>
     * This constructor initializes a new HTTP POST request with content type<font></font>
     * is set to multipart/form-data<font></font>
     * @param requestURL<font></font>
     * @param charset<font></font>
     * @throws IOException<font></font>
     */<font></font>
    public MultipartUtility(String requestURL, String charset)<font></font>
            throws IOException {<font></font>
        this.charset = charset;<font></font>
        <font></font>
        // creates a unique boundary based on time stamp<font></font>
        boundary = "===" + System.currentTimeMillis() + "===";<font></font>
        <font></font>
        URL url = new URL(requestURL);<font></font>
        httpConn = (HttpURLConnection) url.openConnection();<font></font>
        httpConn.setUseCaches(false);<font></font>
        httpConn.setDoOutput(true); // indicates POST method<font></font>
        httpConn.setDoInput(true);<font></font>
        httpConn.setRequestProperty("Content-Type",<font></font>
                "multipart/form-data; boundary=" + boundary);<font></font>
        httpConn.setRequestProperty("User-Agent", "CodeJava Agent");<font></font>
        httpConn.setRequestProperty("Test", "Bonjour");<font></font>
        outputStream = httpConn.getOutputStream();<font></font>
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),<font></font>
                true);<font></font>
    }<font></font>
<font></font>
    /**<font></font>
     * Adds a form field to the request<font></font>
     * @param name field name<font></font>
     * @param value field value<font></font>
     */<font></font>
    public void addFormField(String name, String value) {<font></font>
        writer.append("--" + boundary).append(LINE_FEED);<font></font>
        writer.append("Content-Disposition: form-data; name=\"" + name + "\"")<font></font>
                .append(LINE_FEED);<font></font>
        writer.append("Content-Type: text/plain; charset=" + charset).append(<font></font>
                LINE_FEED);<font></font>
        writer.append(LINE_FEED);<font></font>
        writer.append(value).append(LINE_FEED);<font></font>
        writer.flush();<font></font>
    }<font></font>
<font></font>
    /**<font></font>
     * Adds a upload file section to the request <font></font>
     * @param fieldName name attribute in <input type="file" name="..." /><font></font>
     * @param uploadFile a File to be uploaded <font></font>
     * @throws IOException<font></font>
     */<font></font>
    public void addFilePart(String fieldName, File uploadFile)<font></font>
            throws IOException {<font></font>
        String fileName = uploadFile.getName();<font></font>
        writer.append("--" + boundary).append(LINE_FEED);<font></font>
        writer.append(<font></font>
                "Content-Disposition: form-data; name=\"" + fieldName<font></font>
                        + "\"; filename=\"" + fileName + "\"")<font></font>
                .append(LINE_FEED);<font></font>
        writer.append(<font></font>
                "Content-Type: "<font></font>
                        + URLConnection.guessContentTypeFromName(fileName))<font></font>
                .append(LINE_FEED);<font></font>
        writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);<font></font>
        writer.append(LINE_FEED);<font></font>
        writer.flush();<font></font>
<font></font>
        FileInputStream inputStream = new FileInputStream(uploadFile);<font></font>
        byte[] buffer = new byte[4096];<font></font>
        int bytesRead = -1;<font></font>
        while ((bytesRead = inputStream.read(buffer)) != -1) {<font></font>
            outputStream.write(buffer, 0, bytesRead);<font></font>
        }<font></font>
        outputStream.flush();<font></font>
        inputStream.close();<font></font>
        <font></font>
        writer.append(LINE_FEED);<font></font>
        writer.flush();     <font></font>
    }<font></font>
<font></font>
    /**<font></font>
     * Adds a header field to the request.<font></font>
     * @param name - name of the header field<font></font>
     * @param value - value of the header field<font></font>
     */<font></font>
    public void addHeaderField(String name, String value) {<font></font>
        writer.append(name + ": " + value).append(LINE_FEED);<font></font>
        writer.flush();<font></font>
    }<font></font>
    <font></font>
    /**<font></font>
     * Completes the request and receives response from the server.<font></font>
     * @return a list of Strings as response in case the server returned<font></font>
     * status OK, otherwise an exception is thrown.<font></font>
     * @throws IOException<font></font>
     */<font></font>
    public List<String> finish() throws IOException {<font></font>
        List<String> response = new ArrayList<String>();<font></font>
<font></font>
        writer.append(LINE_FEED).flush();<font></font>
        writer.append("--" + boundary + "--").append(LINE_FEED);<font></font>
        writer.close();<font></font>
<font></font>
        // checks server's status code first<font></font>
        int status = httpConn.getResponseCode();<font></font>
        if (status == HttpURLConnection.HTTP_OK) {<font></font>
            BufferedReader reader = new BufferedReader(new InputStreamReader(<font></font>
                    httpConn.getInputStream()));<font></font>
            String line = null;<font></font>
            while ((line = reader.readLine()) != null) {<font></font>
                response.add(line);<font></font>
            }<font></font>
            reader.close();<font></font>
            httpConn.disconnect();<font></font>
        } else {<font></font>
            throw new IOException("Server returned non-OK status: " + status);<font></font>
        }<font></font>
<font></font>
        return response;<font></font>
    }<font></font>
}

このユーティリティクラスはjava.net.HttpURLConnectionクラスを使用しRFC 1867(HTMLでのフォームベースのファイルアップロード)に従って、ファイルを特定のURLにアップロードするためにマルチパート/フォームデータコンテンツタイプのHTTP POSTリクエストを作成します。1つのコンストラクタと3つのメソッドがあります。

    • MultipartUtility(String requestURL、String charset):指定されたリクエストURLと文字セットに対して、このクラスの新しいインスタンスを作成します。
    • void addFormField(String name、String value):通常のテキストフィールドをリクエストに追加します。
    • void addHeaderField(String name、String value):HTTPヘッダーフィールドをリクエストに追加します。
    • void addFilePart(String fieldName、File uploadFile):アップロードするファイルをリクエストに添付します。
    • List <String> finish():リクエストを完了してサーバーからの応答を文字列のリストとして受信するには、このメソッドを最後に呼び出す必要があります。

次に、このユーティリティクラスの使用例を見てみましょう。

 

ファイルをアップロードするためのJavaクライアントプログラムのコーディング:

MultipartUtility以降クラスはすべての詳細な実装を抽象化します。使用例は次のプログラムに示すように非常に単純です。

1
2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26日
27日
28
29日
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package net.codejava.networking;<font></font>
<font></font>
import java.io.File;<font></font>
import java.io.IOException;<font></font>
import java.util.List;<font></font>
<font></font>
/**<font></font>
 * This program demonstrates a usage of the MultipartUtility class.<font></font>
 * @author www.codejava.net<font></font>
 *<font></font>
 */<font></font>
public class MultipartFileUploader {<font></font>
<font></font>
    public static void main(String[] args) {<font></font>
        String charset = "UTF-8";<font></font>
        File uploadFile1 = new File("e:/Test/PIC1.JPG");<font></font>
        File uploadFile2 = new File("e:/Test/PIC2.JPG");<font></font>
        String requestURL = "http://localhost:8080/FileUploadSpringMVC/uploadFile.do";<font></font>
<font></font>
        try {<font></font>
            MultipartUtility multipart = new MultipartUtility(requestURL, charset);<font></font>
            <font></font>
            multipart.addHeaderField("User-Agent", "CodeJava");<font></font>
            multipart.addHeaderField("Test-Header", "Header-Value");<font></font>
            <font></font>
            multipart.addFormField("description", "Cool Pictures");<font></font>
            multipart.addFormField("keywords", "Java,upload,Spring");<font></font>
            <font></font>
            multipart.addFilePart("fileUpload", uploadFile1);<font></font>
            multipart.addFilePart("fileUpload", uploadFile2);<font></font>
<font></font>
            List<String> response = multipart.finish();<font></font>
            <font></font>
            System.out.println("SERVER REPLIED:");<font></font>
            <font></font>
            for (String line : response) {<font></font>
                System.out.println(line);<font></font>
            }<font></font>
        } catch (IOException ex) {<font></font>
            System.err.println(ex);<font></font>
        }<font></font>
    }<font></font>
}

In this program, we connect to the servlet’s URL of the application FileUploadSpringMVC (see this tutorial: Upload files with Spring MVC):

http://localhost:8080/FileUploadSpringMVC/uploadFile.do

We added two header fields, two form fields and two upload files under the name “fileUpload” – which must match the fields declared in the upload form of the FileUploadSpringMVC application.

When running the above program, it will produce the following output:

サーバーの応答

We can realize that the server’s response is actually HTML code of the application FileUploadSpringMVC’s result page.

So far in this article, we’ve discussed about how to implement a command line program in Java which is capable of upload files to any URL that can handle multipart request, without implementing an HTML upload form. This would be very useful in case we want to upload files to a web server programmatically.

 

Related Java File Upload Tutorials:

 

Other Java network tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on Facebook and watch his Java videos you YouTube.
Attachments:
このファイル(MultipartFileUploader.java)をダウンロードします。MultipartFileUploader.java[Demo program]1 kB
このファイル(MultipartUtility.java)をダウンロードします。MultipartUtility.java[Utility class]4 kB

Add comment

   


Comments 

#110Nath2020-05-03 12:35
Thanks !
To solve null returned value after using addFilePart method in addFormField, you must add :
writer.append("--").append(boundary)

between inputStream.close() and writer.append(LINE_FEED)
(line 105)

so final code at the end of this method is :

outputStream.flush();
inputStream.close();
writer.append("--").append(boundary);
writter.append(LINE_FEED);
writer.flush();

Hope it help someone :)
Quote
#109Flavio Santana2020-01-08 13:33
Ótimo artigo, parabéns.
Quote
#108SHEKH SHAKEEL AHMAD2020-01-04 10:36
i am facing issues when i am using you code as reference, I am able to upload the .docx file but when we opening file after upload its saying error in content.
"We are sorry we can't open because we found a problem with its content"
look like during upload some issues.. can help to fix that.
Quote
#107Umar2019-08-04 01:48
The files contents are not being uploaded, something missing between lines 98 - 108
Quote
#106tania2018-09-28 04:09
is this use in android studio
Quote