http://evgeny-goldin.com/blog/uploading-files-multipart-post-apache/
I had to implement a files transferring mechanism where one machine was sending files to another using "multipart/form-data"
POST request. It can be done using Apache’s Commons FileUpload
andHttpClient
.
The receiving part was an easy one:
1
2
3
4
5
|
<
dependency
>
<
groupid
>commons-fileupload</
groupid
>
<
artifactid
>commons-fileupload</
artifactid
>
<
version
>1.2.1</
version
>
</
dependency
>
|
We parse an incoming request with ServletFileUpload
and get a list of FileItem
s
in return. EachFileItem
is either form’s input field or a file uploaded:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
if
( ServletFileUpload.isMultipartContent( request ))
{
List<fileitem> fileItems =
new
ServletFileUpload(
new
DiskFileItemFactory(
1024
*
1024
, DIR )).
parseRequest( request );
for
( FileItem item : fileItems )
{
String fieldName = item.getFieldName();
if
( item.isFormField()) { item.getString() }
// Form's input field
else
{ item.getInputStream() }
// File uploaded
}
}
|
In our case, we use DiskFileItemFactory
to store files larger than 1Mb in a temporary DIR
. After reading file’s InputStream
and storing the data in a proper storage – we need to delete the temporary copy:item.delete()
.
It’s the sending part that came out to be a bit trickier. Initially, I was using a simple HTML form:
1
2
3
4
5
|
<
input
type
=
"file"
name
=
"file"
>
<
input
type
=
"text"
name
=
"paramName"
>
<
input
type
=
"submit"
name
=
"Submit"
value
=
"Upload File"
>
</
form
>
|
But then I’ve switched back to Java and assumed HttpClient
will do the job.
1
2
3
4
5
|
<
dependency
>
<
groupid
>org.apache.httpcomponents</
groupid
>
<
artifactid
>httpclient</
artifactid
>
<
version
>4.0.1</
version
>
</
dependency
>
|
Eventually, it did but it took me some time to figure out how. The problem with HttpClient
is that it provides a nice tutorial and various usage examples but none of them actually mentions a word about uploading files!
I’ve figured out I need to set an instance of HttpEntity
to request but it seemed like it’s going to be either a StringEntity
or FileEntity
but not both. How come ?! Why is it so hard to send a usual POST request with String and file parameters?
Ok, it’s Google time.
Some examples and documentation were referring to an outdated version when HttpClient
was part of Apache Commons and, therefore, were of no use for me – the API has changed dramatically. Until I’ve found this example that finally saved my day. Radomir, thank you!
The solution is to use an additional Apache component – HttpMime:
1
2
3
4
5
6
7
8
9
10
11
|
<
dependency
>
<
groupid
>org.apache.httpcomponents</
groupid
>
<
artifactid
>httpclient</
artifactid
>
<
version
>4.0.1</
version
>
</
dependency
>
<
dependency
>
<
groupid
>org.apache.httpcomponents</
groupid
>
<
artifactid
>httpmime</
artifactid
>
<
version
>4.0.1</
version
>
</
dependency
>
|
and then we finally get to use a magical MultipartEntity
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
HttpClient client =
new
DefaultHttpClient();
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost post =
new
HttpPost( url );
MultipartEntity entity =
new
MultipartEntity( HttpMultipartMode.BROWSER_COMPATIBLE );
// For File parameters
entity.addPart( paramName,
new
FileBody((( File ) paramValue ),
"application/zip"
));
// For usual String parameters
entity.addPart( paramName,
new
StringBody( paramValue.toString(),
"text/plain"
,
Charset.forName(
"UTF-8"
)));
post.setEntity( entity );
// Here we go!
String response = EntityUtils.toString( client.execute( post ).getEntity(),
"UTF-8"
);
client.getConnectionManager().shutdown();
|
Note the use of EntityUtils
for reading the response.
That’s it.
I only wish library authors were providing better support and examples for more common cases like files uploading in our case. I mean, come on, when people get to use HttpClient
they either want to send a usual request or upload a file, same thing they do with browser. Am I wrong here?