< Zurück | Inhalt | Weiter >

18.7.2 Design

Let’s review what we need our servlet application to do for us. Given an account name and the initial dollar amount, we need to:

• Create a top-level account with that amount of dollars

• Display the current account and its total and remaining dollars, along with a list of its subaccounts, if any

• Create subaccounts, specifying a name and dollar amount

• Make a selected subaccount be the current one, displayed as above

image

After each or any of these actions, the servlet has to spit out the HTML page for the user to view. If the user wants to create a subaccount, then the servlet produces a form page for entering the name and dollar amount for the subaccount. When the user presses a Create button on that page, the browser tells the servlet (via the form data) that the servlet should create the subaccount and redisplay the current account with this new subaccount added to its list.



TIP

It may help to think of the servlet as a two-step process, with a current and fu- ture perspective. The first step is the action that the servlet must perform based on the supplied parameters (e.g., create a new account). The second step is the creation of the page allowing the user to take the next (future) action. That page reflects the state of things after the parameter-driven action has occurred. In our example, that means showing the list of subaccounts including the one that we just created.


Let’s spell out in more detail what our interactions with the servlet will be, and describe what output we expect for each of those inputs. We will create a keyword to tell the servlet what function we want it to perform; we’ll call the parameter func. We will sometimes need two other parameters: name and dollars.

Table 18.1 shows our design as a compact reference.

The code for our servlet is at http://www.javalinuxbook.com/. Let’s look at some of the key parts of the servlet in more detail. We’ll look at:

1) reading the parameters, 2) the core business logic of the servlet, as described in Table 18.1, and 3) how we create and output the HTML.


Table 18.1 BudgetPro servlet actions


image

image

func parameter


begin


mkacct cancel create


cd


back

Other params

name, dollars


none none

name, dollars name


none

Action

Create a top-level account, save in the session.

none

Get account from session.

Get account from session; create subaccount.

Get account from session, look up subaccount by name, save as current in session.

Get account from session, get parent from account, save as current in session.

Next screen


main


subacct main main


main


main


image


The parsing of the parameters is very straightforward. The request param- eter, part of the signature of the doGet() and doPost() methods, can be used to retrieve the parameters we need:


String act = request.getParameter("func"); String name = request.getParameter("name");

String dollars = request.getParameter("dollars");


Notice that we always ask for all three parameters, even though we will often use only one (act). Once we have the requested function in act, it’s just a matter of if-then-else-ing our way through the possible values and taking the appropriate actions. We store, or retrieve, the current account in the session manager, thereby providing continuity between browser requests (Example 18.2).

The output is the page to send back to the browser. We create that page as an object, either an AccountView or a SubPage. The HttpServletResponse provides us with an output channel on which to write.


java.io.PrintWriter out = response.getWriter(); if (nextPage != null) {

response.setContentType("text/html"); out.println(nextPage.toString());

}


image

Example 18.2 Implementing the BudgetPro servlet actions

if ("begin".equals(act)) {

Account top = new Account(name, theUser, dollars); session.setAttribute("top", top); session.setAttribute("current", top);

nextPage = new AccountView(top);

} else if ("mkacct".equals(act)) {

// show the subaccount creation page nextPage = new SubPage(null);

} else if ("cancel".equals(act)) {

Account current = (Account) session.getAttribute("current"); nextPage = new AccountView(current);

} else if ("create".equals(act)) {

Account current = (Account) session.getAttribute("current"); try {

current.createSub(name, dollars); nextPage = new AccountView(current);

} catch (NumberFormatException nfe) {

// show the subaccount creation page (with error message) nextPage = new SubPage("Bad number format");

}

} else if ("cd".equals(act)) {

Account current = (Account) session.getAttribute("current"); Account nextAcct = current.getSub(name); session.setAttribute("current", nextAcct);

nextPage = new AccountView(nextAcct);

} else if ("back".equals(act)) {

Account current = (Account) session.getAttribute("current"); Account nextAcct = current.getParent(); session.setAttribute("current", nextAcct);

nextPage = new AccountView(nextAcct);

} else {

log("Unknown func=["+act+"]"); response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);

}


image


The way that we construct the output, it will all get sent back to the user in one fell swoop. That’s fine for relatively short pages with rapid response time. If response time is a major concern and you are sending large quantities of data, you may want to change things a bit. Instead of building up the output in a StringBuffer and then getting it all back with a toString() call, you could take each of our append() calls and make them individual out.println()


calls, to send each snippet of HTML separately. The output can be flushed explicitly, too, using


response.flushBuffer();


You might do such a call just before beginning a database operation, or place such calls at strategic points through your output.


18.8 REVIEW


We have seen that servlets are Java programs that are run by a Web server. They typically, but not necessarily, produce output intended for a browser. By imple- menting the HttpServlet interface, your Java class will have all the methods needed for it to be run by a Web server. We looked at a simple example and saw its output to a Web browser, then we looked at another example using our BudgetPro application.


18.9 WHAT YOU STILL DONT KNOW


There is more that we haven’t discussed, so if you’re going to do some serious work with servlets, be sure to do some additional reading, especially on these topics:

• The servlet lifecycle and the need for thread safety.

• How to keep the servlet output from being cached.

• Dealing with failures.

• Initialization parameters.

• Other kinds of output.

• Sharing between servlets.

• How to configure and deploy servlets (this is coming up in the next chapter).

image

18.11 Exercises 421

18.10 RESOURCES


The definitive place for all the details is the Java Web site at Sun,3 particularly the pages dealing with javax.servlet.http classes.

Some of the best material on servlets comes from:

Core Servlets and JavaServer Pages by Marty Hall and Larry Brown, ISBN 0-13-009229-0, a Prentice Hall PTR book.

• Its sequel, More Servlets and JavaServer Pages by Marty Hall, ISBN 0-13-067614-1, also by Prentice Hall PTR.

Java Servlet Programming, Second Edition by Jason Hunter and William Crawford, ISBN 0596000405, from O’Reilly.


18.11 EXERCISES


1. Modify the BudgetPro servlet so that it responds differently for the doGet() and doPost() methods. Have doPost() continue to work as is, but have doGet() report the number of different users and the number of accounts that they have created. (You may need to “instrument” the code—that is, add additional statements—to start counting such things.)

2. Change BudgetPro to do its output on the fly instead of building the entire page before output. Can you notice any difference in the display time?

3. Design error handling for BudgetPro to prevent the user from allocating more than is available in the (sub)account. Will you use Java exceptions? If so, which object will throw them and which will catch them? How will you inform the user of the error? Implement your design.


image

3. http://java.sun.com/j2ee/1.4/docs/api/