In the article
Upload file to servlet without using HTML form,
we discussed how to fire an HTTP POST request to transfer a file to a server – but that request’s content type is not of
multipart/form-data, so it may not work with the servers which handle multipart request and it requires both client and server are implemented in Java. To overcome that limitation, in this article, we are going to discuss a different solution for uploading files from a Java client to any web server in a programmatic way, without using upload form in HTML code. Let’s examine this interesting solution now.
This utility class uses
java.net.HttpURLConnection class and follows the
RFC 1867
(Form-based File Upload in HTML) to make an HTTP POST request with
multipart/form-data content type in order to upload files to a given URL. It has one constructor and three methods:
Coding multipart utility class
We build the utility class called MultipartUtility with the following code:
1
2
3
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;
import
java.io.BufferedReader;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.io.OutputStream;
import
java.io.OutputStreamWriter;
import
java.io.PrintWriter;
import
java.net.HttpURLConnection;
import
java.net.URL;
import
java.net.URLConnection;
import
java.util.ArrayList;
import
java.util.List;
/**
* This utility class provides an abstraction layer for sending multipart HTTP
* POST requests to a web server.
* @author www.codejava.net
*
*/
public
class
MultipartUtility {
private
final
String boundary;
private
static
final
String LINE_FEED =
"\r\n"
;
private
HttpURLConnection httpConn;
private
String charset;
private
OutputStream outputStream;
private
PrintWriter writer;
/**
* This constructor initializes a new HTTP POST request with content type
* is set to multipart/form-data
* @param requestURL
* @param charset
* @throws IOException
*/
public
MultipartUtility(String requestURL, String charset)
throws
IOException {
this
.charset = charset;
// creates a unique boundary based on time stamp
boundary =
"==="
+ System.currentTimeMillis() +
"==="
;
URL url =
new
URL(requestURL);
httpConn = (HttpURLConnection) url.openConnection();
httpConn.setUseCaches(
false
);
httpConn.setDoOutput(
true
);
// indicates POST method
httpConn.setDoInput(
true
);
httpConn.setRequestProperty(
"Content-Type"
,
"multipart/form-data; boundary="
+ boundary);
httpConn.setRequestProperty(
"User-Agent"
,
"CodeJava Agent"
);
httpConn.setRequestProperty(
"Test"
,
"Bonjour"
);
outputStream = httpConn.getOutputStream();
writer =
new
PrintWriter(
new
OutputStreamWriter(outputStream, charset),
true
);
}
/**
* Adds a form field to the request
* @param name field name
* @param value field value
*/
public
void
addFormField(String name, String value) {
writer.append(
"--"
+ boundary).append(LINE_FEED);
writer.append(
"Content-Disposition: form-data; name=\""
+ name +
"\""
)
.append(LINE_FEED);
writer.append(
"Content-Type: text/plain; charset="
+ charset).append(
LINE_FEED);
writer.append(LINE_FEED);
writer.append(value).append(LINE_FEED);
writer.flush();
}
/**
* Adds a upload file section to the request
* @param fieldName name attribute in <input type="file" name="..." />
* @param uploadFile a File to be uploaded
* @throws IOException
*/
public
void
addFilePart(String fieldName, File uploadFile)
throws
IOException {
String fileName = uploadFile.getName();
writer.append(
"--"
+ boundary).append(LINE_FEED);
writer.append(
"Content-Disposition: form-data; name=\""
+ fieldName
+
"\"; filename=\""
+ fileName +
"\""
)
.append(LINE_FEED);
writer.append(
"Content-Type: "
+ URLConnection.guessContentTypeFromName(fileName))
.append(LINE_FEED);
writer.append(
"Content-Transfer-Encoding: binary"
).append(LINE_FEED);
writer.append(LINE_FEED);
writer.flush();
FileInputStream inputStream =
new
FileInputStream(uploadFile);
byte
[] buffer =
new
byte
[
4096
];
int
bytesRead = -
1
;
while
((bytesRead = inputStream.read(buffer)) != -
1
) {
outputStream.write(buffer,
0
, bytesRead);
}
outputStream.flush();
inputStream.close();
writer.append(LINE_FEED);
writer.flush();
}
/**
* Adds a header field to the request.
* @param name - name of the header field
* @param value - value of the header field
*/
public
void
addHeaderField(String name, String value) {
writer.append(name +
": "
+ value).append(LINE_FEED);
writer.flush();
}
/**
* Completes the request and receives response from the server.
* @return a list of Strings as response in case the server returned
* status OK, otherwise an exception is thrown.
* @throws IOException
*/
public
List<String> finish()
throws
IOException {
List<String> response =
new
ArrayList<String>();
writer.append(LINE_FEED).flush();
writer.append(
"--"
+ boundary +
"--"
).append(LINE_FEED);
writer.close();
// checks server's status code first
int
status = httpConn.getResponseCode();
if
(status == HttpURLConnection.HTTP_OK) {
BufferedReader reader =
new
BufferedReader(
new
InputStreamReader(
httpConn.getInputStream()));
String line =
null
;
while
((line = reader.readLine()) !=
null
) {
response.add(line);
}
reader.close();
httpConn.disconnect();
}
else
{
throw
new
IOException(
"Server returned non-OK status: "
+ status);
}
return
response;
}
}
|
-
- MultipartUtility(String requestURL, String charset): creates a new instance of this class for a given request URL and charset.
- void addFormField(String name, String value): adds a regular text field to the request.
- void addHeaderField(String name, String value): adds an HTTP header field to the request.
- void addFilePart(String fieldName, File uploadFile): attach a file to be uploaded to the request.
- List<String> finish(): this method must be invoked lastly to complete the request and receive response from server as a list of String.
Coding a test program
Since the MultipartUtility class abstracts all the detailed implementation, a usage example would be pretty simple as shown in the following program:
1
2
3
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;
import
java.io.File;
import
java.io.IOException;
import
java.util.List;
/**
* This program demonstrates a usage of the MultipartUtility class.
* @author www.codejava.net
*
*/
public
class
MultipartFileUploader {
public
static
void
main(String[] args) {
String charset =
"UTF-8"
;
File uploadFile1 =
new
File(
"e:/Test/PIC1.JPG"
);
File uploadFile2 =
new
File(
"e:/Test/PIC2.JPG"
);
String requestURL =
"http://localhost:8080/FileUploadSpringMVC/uploadFile.do"
;
try
{
MultipartUtility multipart =
new
MultipartUtility(requestURL, charset);
multipart.addHeaderField(
"User-Agent"
,
"CodeJava"
);
multipart.addHeaderField(
"Test-Header"
,
"Header-Value"
);
multipart.addFormField(
"description"
,
"Cool Pictures"
);
multipart.addFormField(
"keywords"
,
"Java,upload,Spring"
);
multipart.addFilePart(
"fileUpload"
, uploadFile1);
multipart.addFilePart(
"fileUpload"
, uploadFile2);
List<String> response = multipart.finish();
System.out.println(
"SERVER REPLIED:"
);
for
(String line : response) {
System.out.println(line);
}
}
catch
(IOException ex) {
System.err.println(ex);
}
}
}
|
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.