Java Servlets

We describe how to implement java servlets. Based on

1 Dynamic Content

1.1 Common Gateway Interface

R e q u e s t f o r C G I 1 R e q u e s t f o r C G I 2 R e q u e s t f o r C G I 1 C h i l d P r o c e s s 1 W e b S e r v e r C h i l d P r o c e s s 2 C h i l d P r o c e s s 3

1.2 FastCGI

R e q u e s t f o r C G I 1 R e q u e s t f o r C G I 2 R e q u e s t f o r C G I 1 C h i l d P r o c e s s 1 W e b S e r v e r C h i l d P r o c e s s 2

1.3 mod_perl

1.4 Server Extensions

1.5 Embedding Code in HTML

1.6 Servlet Process

Servlet Process

2 Why Servlets?

3 Basic HTTP Servlet

Servlet Get Post

3.1 HelloWorld

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

public class HelloWorld extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {

    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
    out.println("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">");
    out.println("<head><title>Hello World</title></head>");
    out.println("<body>");
    out.println("<h1>Hello World</h1>");
    out.println("</body></html>");
  }
}

3.2 Hello Forms

<html>
  <head>
    <title>Introductions</title>
  </head>
  <body>
    <form method="get" action="/servlet/hello">
      If you don't mind me asking, what is your name?
      <input type="text" name="name"/><p/>
        <input type="submit"/>
    </form>
  </body>
</html>
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Hello extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {

    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    String name = req.getParameter("name");
    out.println("<html>");
    out.println("<head><title>Hello, " + name + "</title></head>");
    out.println("<body>");
    out.println("Hello, " + name);
    out.println("</body></html>");
  }

  public String getServletInfo() {
    return "A servlet that knows the name of the person to whom it's" + 
           "saying hello";
  }
}

3.3 Handling POST



public void doPost(HttpServletRequest req, HttpServletResponse res)
  throws ServletException, IOException {

  doGet(req, res);
}

3.4 Handling HEAD

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

public class HelloWorld extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {

    res.setContentType("text/html");

    if (req.getMethod().equals("HEAD")) return;

    //its really a GET.....
  }
}

3.5 Web Applications

3.6 Deployment Descriptor

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
    <servlet>
        <servlet-name>
            hi
        </servlet-name>
        <servlet-class>
            HelloWorld
        </servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>
            hi
        </servlet-name>
        <url-pattern>
            /hello.html
        </url-pattern>
    </servlet-mapping>
</web-app>

4 Threads in the Server

  1. Create and initialize servlet.
  2. Handle zero or more calls from clients.
  3. Destroy servlet and garbage collect it.

4.1 Simple Counter

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

public class SimpleCounter extends HttpServlet {

  int count = 0;

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/plain");
    PrintWriter out = res.getWriter();
    count++;
    out.println("Since loading, this servlet has been accessed " +
                count + " times.");
  }
}
Note:

If you have not used Java threads recently I suggest you review them. Remember that all threads can have access to the same static variables and even the same objects if the threads can communicate with each other (for example, via a socket or a file). Each thread has a start() method which gets called when it is created and a run() method which does the actual work of the thread.

4.1.1 Synchronicity Problems

  1. Synchronize method:
    public synchronized void doGet(HttpServletRequest req,
                                   HttpServletResponse res)
    
  2. Synchronize code:
    PrintWriter out = res.getWriter();
    synchronized(this) {
      count++;
      out.printl(...);
    }
    
  3. Synchronize only needed functionality:
    PrintWriter out = res.getWriter();
    int local_count;
    synchronized(this) {
      local_count = ++ count;}
    out.println(..);
    
  4. Live with it.

4.2 Counting with Globals

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

public class HolisticCounter extends HttpServlet {

  static int classCount = 0;  // shared by all instances
  int count = 0;              // separate for each servlet
  static Hashtable instances = new Hashtable();  // also shared

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/plain");
    PrintWriter out = res.getWriter();

    count++;
    out.println("Since loading, this servlet instance has been accessed " +
                count + " times.");

    // Keep track of the instance count by putting a reference to this
    // instance in a Hashtable. Duplicate entries are ignored.
    // The size() method returns the number of unique instances stored.
    instances.put(this, this);
    out.println("There are currently " +
                instances.size() + " instances.");

    classCount++;
    out.println("Across all instances, this servlet class has been " +
                "accessed " + classCount + " times.");
  }
}

4.3 Init and Destroy

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

public class InitDestroyCounter extends HttpServlet {

  int count;

  public void init() throws ServletException {
    // Try to load the initial count from our saved persistent state
    FileReader fileReader = null;
    BufferedReader bufferedReader = null;
    try {
      fileReader = new FileReader("InitDestroyCounter.initial");
      bufferedReader = new BufferedReader(fileReader);
      String initial = bufferedReader.readLine();
      count = Integer.parseInt(initial);
      return;
    }
    catch (FileNotFoundException ignored) { }  // no saved state
    catch (IOException ignored) { }            // problem during read
    catch (NumberFormatException ignored) { }  // corrupt saved state
    finally {
      // Make sure to close the file
      try {
        if (bufferedReader != null) {
          bufferedReader.close();
        }
      }
      catch (IOException ignored) { }
    }

    // Default to an initial count of "0"                            
    count = 0;                                                       
  }                                                                  
                                                                     
  public void doGet(HttpServletRequest req, HttpServletResponse res) 
                               throws ServletException, IOException {
    res.setContentType("text/plain");                                
    PrintWriter out = res.getWriter();                               
    count++;                                                         
    out.println("Since the beginning, this servlet has been accessed " +
                count + " times.");                                  
  }                                                                  
                                                                     
  public void destroy() {                                            
    super.destroy();  // entirely optional

    FileWriter fileWriter = null;
    PrintWriter printWriter = null;
    try {                                                            
      fileWriter = new FileWriter("InitDestroyCounter.initial");
      printWriter = new PrintWriter(fileWriter);         
      printWriter.println(count);                                  
      return;                                                        
    }                                                                
    catch (IOException e) {  // problem during write                 
      // Log the exception. See Chapter 5.                           
    }
    finally {
      // Make sure to close the file
      if (printWriter != null) {
        printWriter.close();
      }
    }
  }
}

4.4 In the Background

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

public class PrimeSearcher extends HttpServlet implements Runnable {

  long lastprime = 0;                    // last prime found
  Date lastprimeModified = new Date();   // when it was found
  Thread searcher;                       // background search thread

  public void init() throws ServletException {
    searcher = new Thread(this);
    searcher.setPriority(Thread.MIN_PRIORITY);  // be a good citizen
    searcher.start();
  }

  public void run() {
    //do work, say, search for primes.
  }

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/plain");
    PrintWriter out = res.getWriter();
    out.println("The last prime discovered was " + lastprime);
    out.println(" at " + lastprimeModified);
  }

  public void destroy() {
    searcher.stop();
  }
}

4.5 Avoid Sending Unchanged Data

5 Getting Information

5.1 Information About the Server

5.2 Context Init Parameters

5.3 What Machine?

5.4 Who Are You?

5.5 Getting at the Parameters

5.6 Getting the Path

5.7 What Did You Want?

5.8 Request Headers

5.9 Reading the Input Stream

6 Sending A Response

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

public class HelloWorld extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {

    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
    out.println("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">");
    out.println("<head><title>Hello World</title></head>");
    out.println("<body>");
    out.println("<h1>Hello World</h1>");
    out.println("</body></html>");
  }
}

6.1 Persistent Connections

6.2 Buffering

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

public class Buffering extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setBufferSize(8 * 1024); // 8K buffer
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    int size = res.getBufferSize(); // returns 8096 or greater

    out.println("The client won't see this");
    res.reset();
    out.println("Nor will the client see this!");
    res.reset();
    out.println("And this won't be seen if sendError() is called");
    if (req.getParameter("important_parameter") == null) {
      res.sendError(res.SC_BAD_REQUEST, "important_parameter needed");
    }
  }
}

6.3 Response Code

Mnemonic Code Meaning
SC_OK 200 Everything's OK.
SC_NO_CONTENT 204 There is nothing to return.
SC_MOVED_PERMANENTLY 301 The requested resource has moved. Put new URL in Location header.
SC_MOVED_TEMPORARILY 302 Temporary move. Put new URL in Location header.
SC_UNAUTHORIZED 401 Not authorized.
SC_NOT_FOUND 404 Document was not found.
SC_INTERNAL_SERVER_ERROR 500 Server is broken.

6.4 Setting Headers

6.5 Client Refresh

6.6 Handling Errors

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
  <error-page>
    <error-code>
      400
    </error-code>
    <location>
      /400.html
    </location>
  </error-page>
    <error-page>
    <error-code>
      404
    </error-code>
    <location>
      /404.html
    </location>
  </error-page>
</web-app>

6.7 Log Files

6.8 Exceptions

6.9 The Stop Button

7 Serving Dynamic Images

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

import Acme.JPM.Encoders.GifEncoder; //3rd party

public class HelloWorldGraphics extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    ServletOutputStream out = res.getOutputStream();  // binary output!

    Graphics g = null;

    try {
      Image image = new BufferedImage(400, 60, TYPE_INT_BGR);
      g = image.getGraphics();
      
      // Draw "Hello World!" to the off-screen graphics context
      g.setFont(new Font("Serif", Font.ITALIC, 48));
      g.drawString("Hello World!", 10, 50);

      // Encode the off-screen image into a GIF and send it to the client
      res.setContentType("image/gif");
      GifEncoder encoder = new GifEncoder(image, out);
      encoder.encode();
    }
    finally {
      // Clean up resources
      if (g != null) g.dispose();
    }
  }
}

7.1 About Images

8 Serving Compressed Content

  1. Set the Content-Encoding header to the appropriate of gzip (best), compress, or deflate.
  2. Wrap the output in a GZIPOutputStream or ZipOutputStream, make sure to close().

9 Session Tracking

Dory

Dory suffers from short-term memory loss.

9.1 User Authentication

  1. It requires everyone to create account and log in.
  2. There is no logout mechanism, just kill browser.
  3. Cannot have more than one session at a time.

9.2 Hidden Form Fields

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

public class ShoppingCartViewerHidden extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    out.println("...");
    
    // Cart items are passed in as the item parameter.
    String[] items = req.getParameterValues("item");

    // Ask if the user wants to add more items or check out.
    // Include the current items as hidden fields so they'll be passed on.
    out.println("<form action=\"/servlet/ShoppingCart\" method=\"POST\">");
    if (items != null) {
      for (int i = 0; i < items.length; i++) {
        out.println("<input type=\"HIDDEN\" name=\"item\" value=\"" +
          items[i] + "\">");
      }
    }
    out.println("...");
  }
}

9.3 URL Rewriting

9.4 Cookies

9.4.1 Cookies Example

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

public class ShoppingCartViewerCookie extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    // Get the current session ID by searching the received cookies.
    String sessionid = null;
    Cookie[] cookies = req.getCookies();
    if (cookies != null) {
      for (int i = 0; i < cookies.length; i++) {
        if (cookies[i].getName().equals("sessionid")) {
          sessionid = cookies[i].getValue();
          break;
        }
      }
    }

    // If the session ID wasn't sent, generate one.
    // Then be sure to send it to the client with the response.
    if (sessionid == null) {
      sessionid = generateSessionId();
      Cookie c = new Cookie("sessionid", sessionid);
      res.addCookie(c);
    }

  private static String generateSessionId() {
    String uid = new java.rmi.server.UID().toString();  // guaranteed unique
    return java.net.URLEncoder.encode(uid);  // encode any special chars
  }


}

9.5 Session Tracking API

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

public class SessionTracker extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    // Get the current session object, create one if necessary
    HttpSession session = req.getSession();

    // Increment the hit count for this page. The value is saved
    // in this client's session under the name "tracker.count".
    Integer count = (Integer)session.getAttribute("tracker.count");
    if (count == null)
      count = new Integer(1);
    else
      count = new Integer(count.intValue() + 1);
    session.setAttribute("tracker.count", count);

    out.println("<html><head><title>SessionTracker</title></head>");
    out.println("<body><h1>Session Tracking Demo</h1>");

    // Display the hit count for this page
    out.println("You've visited this page " + count +
      ((count.intValue() == 1) ? " time." : " times."));

    out.println("<p/>");

    out.println("<h2>Here is your session data:</h2>");
    Enumeration e = session.getAttributeNames();
    while (e.hasMoreElements()) {
      String name = (String) e.nextElement();
      out.println(name + ": " + session.getAttribute(name) + "<br/>");
    }
    out.println("</body></html>");
  }
}

9.5.1 Session Tracking Customizations

9.5.2 Session Tracking: Behind the Scenes

10 Security

  1. Authentication
  2. Authorization
  3. Confidentiality
  4. Integrity

10.1 HTTP Authentication

10.2 Form-Based Authentication

10.3 Custom Authentication

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

import com.oreilly.servlet.Base64Decoder;

public class CustomAuth extends HttpServlet {

  Hashtable users = new Hashtable();

  public void init(ServletConfig config) throws ServletException {
    super.init(config);

    // Names and passwords are case sensitive!
    users.put("Wallace:cheese",     "allowed");
    users.put("Gromit:sheepnapper", "allowed");
    users.put("Penguin:evil",       "allowed");
  }

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/plain");
    PrintWriter out = res.getWriter();

    // Get Authorization header
    String auth = req.getHeader("Authorization");

    // Do we allow that user?
    if (!allowUser(auth)) {
      // Not allowed, so report he's unauthorized
      res.setHeader("WWW-Authenticate", "BASIC realm=\"users\"");
      res.sendError(res.SC_UNAUTHORIZED);
      // Could offer to add him to the allowed user list
    }
    else {
      // Allowed, so show him the secret stuff
      out.println("Top-secret stuff");
    }
  }

  // This method checks the user information sent in the Authorization
  // header against the database of users maintained in the users Hashtable.
  protected boolean allowUser(String auth) throws IOException {
    if (auth == null) return false;  // no auth

    if (!auth.toUpperCase().startsWith("BASIC "))
      return false;  // we only do BASIC

    // Get encoded user and password, comes after "BASIC "
    String userpassEncoded = auth.substring(6);

    // Decode it, using any base 64 decoder (we use com.oreilly.servlet)
    String userpassDecoded = Base64Decoder.decode(userpassEncoded);

    // Check our user list to see if that user and password are "allowed"
    if ("allowed".equals(users.get(userpassDecoded)))
      return true;
    else
      return false;
  }
}

10.4 Custom Form-Based Authorization

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

public class LoginHandler extends HttpServlet {

  public void doPost(HttpServletRequest req, HttpServletResponse res)
                                throws ServletException, IOException {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    // Get the user's account number, password, and pin
    String account = req.getParameter("account");
    String password = req.getParameter("password");
    String pin = req.getParameter("pin");

    // Check the name and password for validity
    if (!allowUser(account, password, pin)) {
      out.println("...Access Denied...");
    }
    else {
      // Valid login. Make a note in the session object.
      HttpSession session = req.getSession();
      session.setAttribute("logon.isDone", account);  // just a marker object

      // Try redirecting the client to the page he first tried to access
      try {
        String target = (String) session.getAttribute("login.target");
        if (target != null) {
          res.sendRedirect(target);
          return;
        }
      }
      catch (Exception ignored) { }

      // Couldn't redirect to the target. Redirect to the site's home page.
      res.sendRedirect("/");
    }
  }

  protected boolean allowUser(String account, String password, String pin) {
    return true;  // trust everyone
  }
}

10.5 Digital Certificates

  1. User connects to server using https.
  2. Server signs its own public key with its own private key and send it back to browser.
  3. Browser uses the server's public key to verify that the same person who signed the key also owns it.
  4. Browser checks if authority (Verisign) signed the public key (avoid man-in-middle attack). Otherwise, asks user if key can be trusted.
  5. Client generates symmetric key for session, encrypts it with server's public key, and sends to server.

10.6 Configuring SSL Security

10.7 Security Summary

11 Enterprise Servlets

11.1 Load Distribution

11.2 J2EE Integration

11.3 Referencing External Resources

12 Element Construction Set

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

import org.apache.ecs.*;
import org.apache.ecs.html.*;

public class ECSHello extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {

    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    Document doc = new Document();
    doc.appendTitle("Testing ECS");
    doc.appendBody(new Big("Hello!"))
       .appendBody(new P())
       .appendBody("The current time is " + new Date());
    doc.output(out);
  }
}

13 JavaServer Pages

13.1 JSP Includes

<html>
<head><title>Hello</title></head>
<body>

<p>
One way is by using an expression:
<%= request.getParameter("name") %>
</p>

<p>
Another is by using a scriplet:

<% //scriptlet example
if (request.getParameter("name") == null) {
   out.println("Hello World");
}
else {
  out.println("Hello, " + request.getParameter("name"));
}
%>
</p>
<p>
Finally, there are the declarations:
<p>
<%!
/**Instance variable for this servlet */
private int counter = 0;

/**Member function for this servlet */
private String randomNumber() {
      return(Math.random().toString());
}
%>
now call it: <%= randomNumber()%=>
</body></html>

13.2 Available Variables

13.3 Directives

13.3.1 Page Import

13.3.2 More Page Attributes

13.4 JSP:Include

13.4.1 Include

13.5 JavaBeans in JSP

<%@ page import="HelloBean" %>

<jsp:useBean id="hello" class="HelloBean">
  <jsp:setProperty name="hello" property="name" param="name"/>
</jsp:useBean>

<HTML>
<HEAD><TITLE>Hello</TITLE></HEAD>
<BODY>
<H1>
Hello, <jsp:getProperty name="hello" property="name" />

</H1>
</BODY>
</HTML>
with the bean defined as
public class HelloBean {
  private String name = "World";

  public void setName(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }
}

13.5.1 StringBean Example

package mywebapp;
/** A simple bean that has a single String property
 * called message.
 */
public class StringBean {

  private String message = "No message specified";

  public String getMessage() {
    return(message);
  }

  public void setMessage(String message) {
    this.message = message;
  }
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
  <HEAD>
    <TITLE>Using JavaBeans with JSP</TITLE>
    <LINK REL=STYLESHEET
      HREF="JSP-Styles.css"
      TYPE="text/css">
  </HEAD>
  <BODY>
    <TABLE BORDER=5 ALIGN="CENTER">
        <TR><TH CLASS="TITLE">
            Using JavaBeans with JSP</TABLE>
    <jsp:useBean id="stringBean" class="coreservlets.StringBean"/>
      <OL>
       <LI>Initial value (from jsp:getProperty):
        <I><jsp:getProperty name="stringBean"   property="message" /></I></LI>

        <LI>Initial value (from JSP expression):
          <I><%= stringBean.getMessage() %></I></LI>

        <LI><jsp:setProperty name="stringBean" property="message" value="Best string bean: Fortex" />
          Value after setting property with jsp:setProperty:
          <I><jsp:getProperty name="stringBean" property="message" /></I>

        <LI><% stringBean.setMessage("My favorite: Kentucky Wonder"); %>
      Value after setting property with scriptlet:
            <I><%= stringBean.getMessage() %></I>
      </OL>
  </BODY></HTML>

13.5.2 Setting Properties to Parameter Values

13.5.3 Sharing Beans

14 Model View Controller

14.1 MVC Example

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

/** Servlet that reads a customer ID and displays
 * information on the account balance of the customer
 * who has that ID.
 */

public class ShowBalance extends HttpServlet {

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response) throws ServletException, IOException {

    //Fill up the bean
    BankCustomer customer = BankCustomer.getCustomer(request.getParameter("id"));

    String address;

    //Use a different view depending on the customer.
    //
    if (customer == null) {
      address = "/bank-account/UnknownCustomer.jsp";
    } else if (customer.getBalance() < 0) {
      address = "/bank-account/NegativeBalance.jsp";
      request.setAttribute("badCustomer", customer);
    } else if (customer.getBalance() < 10000) {
      address = "/bank-account/NormalBalance.jsp";
      request.setAttribute("regularCustomer", customer);
    } else {
      address = "/bank-account/HighBalance.jsp";
      request.setAttribute("eliteCustomer", customer);
    }

    //Forward control to the .jsp page
    RequestDispatcher dispatcher = request.getRequestDispatcher(address);
    dispatcher.forward(request, response);
  }
}
package coreservlets;
import java.util.*;

/** Bean to represent a bank customer. */
public class BankCustomer {
  private String id, firstName, lastName;
  private double balance;
  
  public BankCustomer(String id,
                      String firstName,
                      String lastName,
                      double balance) {
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
    this.balance = balance;
  }
  
  public String getId() {
    return(id);
  }
  
  public String getFirstName() {
    return(firstName);
  }

  public String getLastName() {
    return(lastName);
  }

  public double getBalance() {
    return(balance);
  }

  public double getBalanceNoSign() {
    return(Math.abs(balance));
  }

  public void setBalance(double balance) {
    this.balance = balance;
  }
  
  // Makes a small table of banking customers. for Testing purposes.
  private static HashMap customers;
  static {
    customers = new HashMap();
    customers.put("id001",
                  new BankCustomer("id001",
                                   "John",
                                   "Hacker",
                                   -3456.78));
    customers.put("id002",
                  new BankCustomer("id002",
                                   "Jane",
                                   "Hacker",
                                   1234.56));
    customers.put("id003",
                  new BankCustomer("id003",
                                   "Juan",
                                   "Hacker",
                                   987654.32));
  }
  /** Finds the customer with the given ID.
   * Returns null if there is no match.
   */
  public static BankCustomer getCustomer(String id) {
    return((BankCustomer)customers.get(id));
  }
}

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
  <HEAD>
    <TITLE>Your Balance</TITLE>
    <LINK REL=STYLESHEET
      HREF="/bank-support/JSP-Styles.css"
      TYPE="text/css">
  </HEAD>
  <BODY>
     <H1>Your Balance</H1>
    <P>
      <IMG SRC="/bank-support/Money.gif" ALIGN="RIGHT"/>
      <jsp:useBean id="regularCustomer"
        type="coreservlets.BankCustomer"
        scope="request" />
      <UL>
      <LI>First name: <jsp:getProperty name="regularCustomer" property="firstName" />
  
      <LI>Last name: <jsp:getProperty name="regularCustomer" property="lastName" />

      <LI>ID: <jsp:getProperty name="regularCustomer" property="id" />

      <LI>Balance: $<jsp:getProperty name="regularCustomer" property="balance" />
    </UL>
  </BODY>
</HTML>

14.2 Scope

14.3 Forwarding from JSP

<% String destination;
  if (Math.random() > 0.5) {
     destination = "/examples/page1.jsp";
  } else {
     destination = "/examples/page2.jsp";
  }
%>
<jsp:forward page="<%= destination %>" />

14.4 Multiple Included JSP

String firstTable, secondTable, thirdTable;

if (someCondition) {
  firstTable = "/WEB-INF/Sports-Scores.jsp";
  secondTable = "/WEB-INF/Stock-Prices.jsp";
  thirdTable = "/WEB-INF/Weather.jsp";
} else if (...) { ... }

RequestDispatcher dispatcher =
  request.getRequestDispatcher("/WEB-INF/Header.jsp");
dispatcher.include(request, response);

dispatcher = request.getRequestDispatcher(firstTable);
dispatcher.include(request, response);

dispatcher = request.getRequestDispatcher(secondTable);
dispatcher.include(request, response);

dispatcher = request.getRequestDispatcher(thirdTable);
dispatcher.include(request, response);

dispatcher = request.getRequestDispatcher("/WEB-INF/Footer.jsp");
dispatcher.include(request, response);

15 JSP Expression Language

15.1 JSP Expressions Example

package coreservlets;
/** Servlet that creates some scoped variables (objects stored
 * as attributes in one of the standard locations). Forwards
 * to a JSP page that uses the expression language to
 * display the values.
 */

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ScopedVars extends HttpServlet {

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
    throws ServletException, IOException {
    
    request.setAttribute("attribute1", "First Value");
    
    HttpSession session = request.getSession();
    session.setAttribute("attribute2", "Second Value");

    ServletContext application = getServletContext();
    application.setAttribute("attribute3", new java.util.Date());
    request.setAttribute("repeated", "Request");
    session.setAttribute("repeated", "Session");
    application.setAttribute("repeated", "ServletContext");
    
    RequestDispatcher dispatcher =request.getRequestDispatcher("/el/scoped-vars.jsp");
    dispatcher.forward(request, response);
  }
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
  <HEAD><TITLE>Accessing Scoped Variables</TITLE>
    <LINK REL=STYLESHEET
      HREF="/el/JSP-Styles.css"
      TYPE="text/css">
  </HEAD>
  <BODY>
    <H1>Accessing Scoped Variables</H1>
    <UL>
      <LI><B>attribute1:</B> ${attribute1} <!--First value-->
      <LI><B>attribute2:</B> ${attribute2} <!--Second value-->
      <LI><B>attribute3:</B> ${attribute3} <!-- the date-->
      <LI><B>Source of "repeated" attribute:</B> ${repeated} <!-- Request -->
</UL>

</BODY></HTML>

15.2 Beans as Values

16 Struts

16.1 Struts Flow

  1. User submits form, goes to URL something.do
  2. struts-config.xml maps that something to an Action class (that is, a class you define which extends Action)
  3. The execute method on that class is executed, it is passed a form bean
  4. This method places all its results in beans.
  5. A JSP page is chosen (by struts-config.xml) as the response to the user. Page can use bean:write

URLs

  1. Java Servlet Programming, Second Edition, http://www.amazon.com/exec/obidos/ASIN/0596000405/multiagentcom/
  2. servlets.com, http://www.servlets.com/
  3. Core Servlets and JavaServer Pages, http://jmvidal.cse.sc.edu/lib/hall03a.html
  4. RFC 1867, http://www.ietf.org/rfc/rfc1867.txt
  5. Java Advanced Imaging API, http://java.sun.com/products/java-media/jai/
  6. RFC 2109, http://www.faqs.org/rfcs/rfc2109.html
  7. RFC 2246, http://www.ietf.org/rfc/rfc2246.txt
  8. Enterprise Java Beans, http://java.sun.com/products/ejb
  9. JNDI API, http://java.sun.com/products/jndi/
  10. Element Construction Set, http://jakarta.apache.org/ecs/
  11. wikipedia:Model-view-controller, http://www.wikipedia.org/wiki/Model-view-controller
  12. netbeans struts tutorial, http://www.netbeans.org/kb/50/quickstart-webapps-struts.html
  13. this overview, http://courses.coreservlets.com/Course-Materials/struts.html
  14. this one, http://www.ibm.com/developerworks/library/j-struts/

This talk available at http://jmvidal.cse.sc.edu/talks/servlets/
Copyright © 2009 José M. Vidal . All rights reserved.

04 February 2008, 04:00PM