DevX HomePage
 
http://www.devx.com Printed from http://www.devx.com/Java/Article/17679/1954
 
Send Form Data from Java: A Painless Solution

Sending multipart/form data from Java is a painful process that bogs developers down in protocol details. This article provides a simple, real-world solution that makes sending POST requests as simple as sending GET requests, even when sending multiple files of varying type. 
ending simple GET requests from Java is extremely easy (be it an application or a servlet), but sending multipart forms, like when you upload files, is painful. The former can be done in one method call that does all the underground work. The latter requires explicitly creating an HTTP request, which may include generating multipart boundaries while being careful with the exact amount and selection of newlines (e.g., println() would not always do the right job).

This article provides a simple solution that will relieve the pain of sending form data (like POST requests) from Java in most real-world scenarios. The intention is to make POST requests as simple as GET requests, even when sending multiple files of varying type (archives, XML, HTML, plain text, etc.).

GET and POST Requests
The two main methods for sending form data to a Web server are GET and POST. This section demonstrates how each method works in three scenarios. (Do not try to reproduce these at home. The URLs and e-mail addresses are fake.)

Example 1. GET Request
The following form uses the GET method:


<form method="get" action="hi.iq/register.jsp">
  Name:  <input type="text" name="name" value="J.Doe">
  email: <input type="text" name="email" value="abuse@spamcop.com">
  <input type="submit">
</form> 

It performs the same task as requesting the following URL: http:hi.iq/register.jsp?name=J.Doe&email=abuse%40spamcop.com

If you were using Mozilla 5.0, the following would be the HTTP request sent to the server:


GET register.jsp?name=J.Doe&email=abuse%40spamcop.com HTTP/1.1
Host: hi.iq
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2) Gecko/20021126
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,
video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en-us, en;q=0.50 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66Keep-Alive: 300Connection: keep-alive



Example 2. POST Request
Now, let's replace 'GET' with 'POST' in the form HTML tag:


<form method="post" action="hi.iq/register.jsp">
  Name:  <input type="text" name="name" value="J.Doe">
  email: <input type="text" name="email" value="abuse@spamcop.com">
  <input type="submit">
</form> 

In this case, the HTTP request sent to the server looks like this:


POST register.jsp HTTP/1.1
Host: hi.iq
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2) Gecko/20021126
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,
video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en-us, en;q=0.50 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66 Keep-Alive: 300Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 36 name=J.Doe&email=abuse%40spamcop.com

Example 3. Multipart POST Request
If the form contains file upload, you have to add enctype="multipart/form-data" to the form tag. Otherwise, the file won't be sent:


<form method="post" action="hi.iq/register.jsp" enctype="multipart/form-data">
  Name:  <input type="text" name="name" value="J.Doe">
  email: <input type="text" name="email" value="abuse@spamcop.com">
  file: <input type="file" name="file-upload">
  <input type="submit">
</form> 

This form will produce the following HTTP request when sent from Mozilla 5:


POST register.jsp HTTP/1.1
Host: hi/iq
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2) Gecko/20021126
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,
video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en-us, en;q=0.50 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66 Keep-Alive: 300 Connection: keep-alive Content-Type: multipart/form-data; boundary=---------------------------29772313742745 Content-Length: 452 -----------------------------29772313742745 Content-Disposition: form-data; name="name" J.Doe -----------------------------29772313742745 Content-Disposition: form-data; name="email" abuse@spamcop.com -----------------------------29772313742745 Content-Disposition: form-data; name="file-upload"; filename="test.txt" Content-Type: text/plain test data with some high ascii: ¿Como estás? -----------------------------29772313742745--



Send POST Requests from Java
Using the GET request from Java is very easy. You just create a URL with the request and then get an input stream:

InputStream is = new 
URL("hi.iq/register?name=J.Doe&email=abuse@spamcop.com").getInputStream();

In most cases, servers that process POST requests won't reject your GET request. Still, sometimes you'll have to POST instead of GET, particularly when you upload a file. Wouldn't having a solution like the form from Example 2 be nice? The corresponding Java request could look like this:


InputStream serverInput = ClientHttpRequest.post(
                              new java.net.URL("hi.iq/register"), 
                              new Object[] {
                                            "name", "J.Doe",
                                            "email", "abuse@spamcop.com",
                                            "test.txt", new 
File("C:\home\vp\tmp\test.txt")
                                           });

Unfortunately, so far no such solution exists.

The Solution: ClientHttpRequest
If you search the Internet, you will find some partial or complicated solutions for using POST requests in Java. The best commercial solution probably is JScape's HTTP(S) component. Its well-designed API covers everything specified in HTTP (see RFC 2068). Other solutions are either too weird and complicated (see Ronald Tschalär's HttpClient) or too literal to be useful (check out this post from JavaRanch).

Because of this lack of free, simple solutions, I had to develop my own (download the source code). It is of moderate complexity and has an obvious interface that I hope is both simple and relatively universal. It can be instantiated from a URL String, URL, or an already open URLConnection.

After a user creates an instance of ClientHttpRequest, the user can add request parameters and cookies. Cookies are an important part of a request, especially with servlets that use cookies to keep track of sessions.

One can add parameters one by one, using the following:


setParameter(String name, String value); 
setParameter(String name, File file); 
setParameter(String parametername, String filename, InputStream fileinput) 

Or set them all at once, using the following:


setParameters(Map parameterMap) 

or


setParameters(Object[] parameterArray). 

The following method sets parameter as a string value or as a file depending on the argument type:


setParameter(String parametername, Object parameterdata).

This method works the same way for cookies. One can add cookies one by one, using the following:


setCookie(String name, String value) 

Or set them all at once, using one of these:


setCookies(Map cookieMap)
setCookies(String[] cookieArray)

After the request is ready, the post() method posts the request and returns an input stream that will contain the server's response, the same way as in URL.getInputStream(). For convenience, additional post methods are available:


post(Map parameters); 
post(Object[] parameters); 
post(String[] cookies, Object[] parameters); 
post(Map cookies, Map parameters). 

The following group of static post methods does all of this in one fell swoop:


InputStream serverInput = post(URL url, Map parameters); 
InputStream serverInput = post(URL url, Map cookies, Map parameters); 
InputStream serverInput = post(URL url, String[] cookies, Object[] parameters); 
InputStream serverInput = post(URL url, Object[] parameters).

All these methods let the user post a complicated form and receive an input stream in one expression, like the one in Example 2 at the beginning of this article.

Answer to the Eternal Question
Now you know how an HTML form (GET or POST) gets passed to the server as an HTTP request and how you can reproduce this behavior in your Java program—without overloading it with protocol details. You could say this solution answers the eternal question: How can one call a servlet or JSP from another servlet or JSP?

Vlad Patryshev is an R&D engineer at the Java Business Unit of Borland. He recently started the myjavatools.com project. by e-mail.


DevX is a division of Jupitermedia Corporation
© Copyright 2007 Jupitermedia Corporation. All Rights Reserved. Legal Notices