Home > Articles > Programming > Java

  • Print
  • + Share This
This chapter is from the book

2.4 The Client Request: Form Data

One of the main motivations for building Web pages dynamically is to base the result upon query data submitted by the user. This section briefly shows you how to access that data. More details are provided in Chapter 3 of Core Servlets and JavaServer Pages (available in PDF at http://www.moreservlets.com).

If you've ever used a search engine, visited an online bookstore, tracked stocks on the Web, or asked a Web-based site for quotes on plane tickets, you've probably seen funny-looking URLs like http://host/path?user=Marty+Hall&origin=bwi&dest=nrt. The part after the question mark (i.e., user=Marty+Hall&origin=bwi&dest=nrt) is known as form data (or query data) and is the most common way to get information from a Web page to a server-side program. Form data can be attached to the end of the URL after a question mark (as above) for GET requests or sent to the server on a separate line for POST requests. If you're not familiar with HTML forms, see Chapter 16 of Core Servlets and JavaServer Pages (in PDF at http://www.moreservlets.com) for details on how to build forms that collect and transmit data of this sort.

Reading Form Data from CGI Programs

Extracting the needed information from form data is traditionally one of the most tedious parts of CGI programming. First, you have to read the data one way for GET requests (in traditional CGI, this is usually through the QUERY_STRING environment variable) and a different way for POST requests (by reading the standard input in traditional CGI). Second, you have to chop the pairs at the ampersands, then separate the parameter names (left of the equal signs) from the parameter values (right of the equal signs). Third, you have to URL-decode the values. Alphanumeric characters are sent unchanged, but spaces are converted to plus signs and other characters are converted to %XX where XX is the ASCII (or ISO Latin-1) value of the character, in hex.

Reading Form Data from Servlets

One of the nice features of servlets is that all the form parsing is handled automatically. You simply call the getParameter method of HttpServletRequest, supplying the case-sensitive parameter name as an argument. You use getParameter exactly the same way when the data is sent by GET as you do when it is sent by POST. The servlet knows which request method was used and automatically does the right thing behind the scenes. The return value is a String corresponding to the URL-decoded value of the first occurrence of that parameter name. An empty String is returned if the parameter exists but has no value, and null is returned if there is no such parameter in the request.

Technically, it is legal for a single HTML form to use the same parameter name twice, and in fact this situation really occurs when you use SELECT elements that allow multiple selections (see Section 16.6 of Core Servlets and JavaServer Pages). If the parameter could potentially have more than one value, you should call getParameterValues (which returns an array of strings) instead of getParameter (which returns a single string). The return value of getParameterValues is null for nonexistent parameter names and is a one-element array when the parameter has only a single value.

Parameter names are case sensitive, so, for example, request.getParameter("Param1") and request.getParameter("param1") are not interchangeable.

Core Note

The values supplied to getParameter and getParameterValues are case sensitive.

Finally, although most real servlets look for a specific set of parameter names, for debugging purposes it is sometimes useful to get a full list. Use getParameterNames to get this list in the form of an Enumeration, each entry of which can be cast to a String and used in a getParameter or getParameterValues call. Just note that the HttpServletRequest API does not specify the order in which the names appear within that Enumeration.

Example: Reading Three Explicit Parameters

Listing 2.8 presents a simple servlet called ThreeParams that reads form data parameters named param1, param2, and param3 and places their values in a bulleted list. Listing 2.9 shows an HTML form that collects user input and sends it to this servlet. By use of an ACTION URL that begins with a slash (e.g., /servlet/moreservlets.ThreeParams), the form can be installed anywhere in the server's Web document hierarchy; there need not be any particular association between the directory containing the form and the servlet installation directory. When you use Web applications, HTML files (and images and JSP pages) go in the directory above the one containing the WEB-INF directory; see Section 4.2 (Structure of a Web Application) for details. The directory for HTML files that are not part of an explicit Web application varies from server to server. As described in Section 1.5 (Try Some Simple HTML and JSP Pages) HTML and JSP pages go in install_dir/webapps/ROOT for Tomcat, in install_dir/servers/default/default-app for JRun, and in install_dir/public_html for ServletExec. For other servers, see the appropriate server documentation.

Also note that the ThreeParams servlet reads the query data after it starts generating the page. Although you are required to specify response settings before beginning to generate the content, there is no requirement that you read the request parameters at any particular time.

Listing 2.8 ThreeParams.java

package moreservlets;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

/** Simple servlet that reads three parameters from the
 * form data.
 */

public class ThreeParams extends HttpServlet {
 public void doGet(HttpServletRequest request,
          HttpServletResponse response)
   throws ServletException, IOException {
  response.setContentType("text/html");
  PrintWriter out = response.getWriter();
  String title = "Reading Three Request Parameters";
  out.println(ServletUtilities.headWithTitle(title) +
        "<BODY BGCOLOR=\"#FDF5E6\">\n" +
        "<H1 ALIGN=\"CENTER\">" + title + "</H1>\n" +
        "<UL>\n" +
        " <LI><B>param1</B>: "
        + request.getParameter("param1") + "\n" +
        " <LI><B>param2</B>: "
        + request.getParameter("param2") + "\n" +
        " <LI><B>param3</B>: "
        + request.getParameter("param3") + "\n" +
        "</UL>\n" +
        "</BODY></HTML>");
 }
}

Listing 2.9 ThreeParamsForm.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
 <TITLE>Collecting Three Parameters</TITLE>
</HEAD>
<BODY BGCOLOR="#FDF5E6">
<H1 ALIGN="CENTER">Collecting Three Parameters</H1>

<FORM ACTION="/servlet/moreservlets.ThreeParams">
 First Parameter: <INPUT TYPE="TEXT" NAME="param1"><BR>
 Second Parameter: <INPUT TYPE="TEXT" NAME="param2"><BR>
 Third Parameter: <INPUT TYPE="TEXT" NAME="param3"><BR>
 <CENTER><INPUT TYPE="SUBMIT"></CENTER>
</FORM>

</BODY>
</HTML>

Figure 2–6 shows the HTML form after the user enters the home directories of three famous Internet personalities (OK, two famous Internet personalities). Figure 2–7 shows the result of the form submission. Note that, although the form contained ~, a non-alphanumeric character that was transmitted by use of its hex-encoded Latin-1 value (%7E), the servlet had to do nothing special to get the value as it was typed into the HTML form. This conversion (called URL decoding) is done automatically. Servlet authors simply specify the parameter name as it appears in the HTML source code and get back the parameter value as it was entered by the end user: a big improvement over CGI and many alternatives to servlets and JSP.

Figure 2-6Figure 2–6 HTML front end resulting from ThreeParamsForm.html.

Figure 2-7Figure 2–7 Output of ThreeParams servlet.

If you're accustomed to the traditional CGI approach where you read POST data through the standard input, you should note that it is possible to do the same thing with servlets by calling getReader or getInputStream on the HttpServletRequest and then using that stream to obtain the raw input. This is a bad idea for regular parameters; getParameter is simpler and yields results that are parsed and URL-decoded. However, reading the raw input might be of use for uploaded files or POST data being sent by custom clients. Note, however, that if you read the POST data in this manner, it might no longer be found by getParameter.

Core Warning

Do not use getParameter when you also call getInputStream and read the raw servlet input.

Filtering Query Data

In the previous example, we read the param1, param2, and param3 request parameters and inserted them verbatim into the page being generated. This is not necessarily safe, since the request parameters might contain HTML characters such as "<" that could disrupt the rest of the page processing, causing some of the subsequent tags to be interpreted incorrectly. For an example, see Section 3.6 of Core Servlets and JavaServer Pages (available in PDF at http://www.moreservlets.com). A safer approach is to filter out the HTML-specific characters before inserting the values into the page. Listing 2.10 shows a static filter method that accomplishes this task.

Listing 2.10 ServletUtilities.java

package moreservlets;

import javax.servlet.*;
import javax.servlet.http.*;

public class ServletUtilities {
 // Other parts shown elsewhere.

 // Given a string, this method replaces all occurrences of
 // '<' with '&lt;', all occurrences of '>' with
 // '&gt;', and (to handle cases that occur inside attribute
 // values), all occurrences of double quotes with
 // '&quot;' and all occurrences of '&' with '&amp;'.
 // Without such filtering, an arbitrary string
 // could not safely be inserted in a Web page.

 public static String filter(String input) {
  StringBuffer filtered = new StringBuffer(input.length());
  char c;
  for(int i=0; i<input.length(); i++) {
   c = input.charAt(i);
   if (c == '<') {
    filtered.append("&lt;");
   } else if (c == '>') {
    filtered.append("&gt;");
   } else if (c == '"') {
    filtered.append("&quot;");
   } else if (c == '&') {
    filtered.append("&amp;");
   } else {
    filtered.append(c);
   }
  }
  return(filtered.toString());
 }
}
  • + Share This
  • 🔖 Save To Your Account