20.01.2013

Servlets

In diesem Artikel wird kurz beschrieben, wie ein Servlet aufgebaut ist und wie es verwendet werden kann. Dies wird an dem "bekannten" Beispiel eines Einkaufswagens (Shopping-Cart) erklärt. Dieser Artikel ist keine Einführung in die Servlet-Programmierung. Er soll vielmehr zeigen, wie fehleranfällig und umständlich das Erstellen von Servlets ist. In den folgenden Artikeln zum Thema Java EE6 Web-Client werden andere Technologien vorgestellt, um einfacher Web-Oberflächen und Web-Clients zu erstellen.

Die fertige Anwendung, die in diesem Artikel erstellt wird, sieht im Browser folgendermaßen aus:

Auf der linken Seite lassen sich in dem Textfeld Artikelbezeichnungen eintragen und über die ComboBox wird eine Menge von 1 bis 5 ausgewählt. Mit dem Button Hinzufügen wird der Artikel in den Warenkorb gelegt und in einer Liste oberhalb angezeigt. Mit dem Button Warenkorb leeren werden alle Artikel aus dem Warenkorb entfernt und die Liste wird nicht mehr angezeigt.

Die folgende Abbildung zeigt den Ablauf einer Anfrage an den Servlet-Container und die Antwort an den Client.

Man sieht, dass ein Request vom Browser, in dem der Web-Client läuft, an den Web-Container, in dem das Servlet läuft, gestellt wird. Als Antwort sendet das Servlet eine Response zurück an dem Browser. In der Response enthalten ist die komplette HTML-Seite, die der Browser anzeigt.

Der zugehörige Quellcode sieht folgendermaßen aus:

package org.hameister.shoppingcarts;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 *
 * @author hameister
 */
@WebServlet(name = "CartServlet", urlPatterns = {"/CartServlet"})
public class CartServlet extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            
            //Get items in Cart for the Session
            HttpSession session = request.getSession();
            List<String> items = (List<String>)session.getAttribute("items");
            if(items == null) {
                items = new ArrayList<String>();
                session.setAttribute("items", items);
            }

            // Reset Cart
            String reset = request.getParameter("reset");
            if(reset!=null) {
                items.clear();
            }
            
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Warenkorb</title>");            
            out.println("</head>");
            out.println("<body>");
       
            String name = request.getParameter("item");
            if(name != null) {
                String quantity = request.getParameter("quantity");
                //Add item to list
                items.add(quantity+" &times; "+name);
            } 
            
            // List output
            if(items.size()>0) {
                out.println("<h2>Artikel im Warenkorb:</h2>");
                out.println("<ul>");
                for(String item : items) {
                    out.println("<li>"+item+"</li>");
                }
                out.println("</ul>");
            }
                 
            out.println("<strong>Artikel zum Warenkorb hinzufügen:</strong>");
            // Add button
            out.println("<form method=\"POST\" action=\"CartServlet\" >");
            out.println("<input type=\"text\" name=\"item\" >");
            out.println("   <select name=\"quantity\" size=\"1\">");
            out.println("     <option selected>1</option>");
            out.println("     <option>2</option>");
            out.println("     <option>3</option>");
            out.println("     <option>4</option>");
            out.println("     <option>5</option>");
            out.println("   </select>");
            out.println("<input type=\"submit\" value=\"Hinzufügen\" >");
            out.println("</form>");
            
            // Reset button
            out.println("<form method=\"POST\" action=\"CartServlet\" >");
            out.println("<input type=\"submit\" name=\"reset\" value=\"Warenkorb leeren\" >");
            out.println("</form>");
            
            
            out.println("</body>");
            out.println("</html>");
        } finally {            
            out.close();
        }
    }

    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Shopping Cart Servlet";
    }
}

Wie man sieht, erbt das Servlet (CartServlet) von der Klasse HttpServlet und überschreibt die drei Methoden doGet, doPost und getServletInfo. Die Methode getServletInfo liefert eine kurze Beschreibung des Servlets zurück. Wichtiger sind die beiden anderen Methoden, die die Anfragen an das Servlet verarbeiten. Also den Request. Da in dem Beispiel nicht zwischen HTTP-GET und HTTP-POST unterschieden wird, werden die Anfragen an die Methode processRequest weitergeleitet. In dieser Methode wird aus dem Request-Objekt die HttpSession abgefragt, um festzustellen, ob sich schon items im Warenkorb befinden. Ggf. muss eine neue ArrayList angelegt und in der Session abgelegt werden.

Falls der Reset-Button angeklickt wurde, wird der Warenkorb durch den Aufruf von clear zurückgesetzt.

Anschliessend wird die HTML-Seite Element für Element erstellt. Dazu wird als erstes der HTML-Rahmen mit HEAD und BODY angelegt. Dann wird der hinzugefügte Artikel aus dem Request ausgelesen und inklusive der Menge in der items-Liste ergänzt. Danach wird für alle schon im Warenkorb befindlichen Artikel ein <LI>-Elemente angelegt, so dass sie in einer Liste angezeigt werden können.

Abschließend wird noch das Eingabeformular in der HTML-Seite ergänzt, so dass weitere Artikel erfasst werden können.

Das wirklich unschöne an Servlets ist, dass die HTML-Ergebnisseite, die zurück an den Browser geschickt wird, per Hand zusammengebaut werden muss. Man kann sich leicht vorstellen, dass dies extrem fehleranfällig ist. Deshalb sollte man im Java EE-Umfeld auch eher JSF-Seiten und falls notwendig JSP-Seiten verwendet werden.

Weitere Informationen

Weitere Informationen zu Web-Clients findet man in den folgenden Artikeln:

  1. Einleitung - Teil 1
  2. Servlets - Teil 2
  3. JSP-Seiten - Teil 3
  4. JSP-Seiten mit JSTL - Teil 4
  5. JSF-Seiten - Teil 5
  6. JSF-Seiten mit Ajax - Teil 6
  7. JSF-Templates - Teil 7