20.01.2013

Java Server Pages - JSPs

In diesem Artikel wird kurz beschrieben, wie eine JSP-Seite aufgebaut ist und wie sie verwendet werden kann. Dies wird an dem "bekannten" Beispiel eines Einkaufswagens (Shopping-Cart) erklärt. Dieser Artikel ist keine Einführung in die JSP-Programmierung. Er soll vielmehr zeigen, wie die grundlegende Funktionsweise von JSP-Seiten 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 Web-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 ein Servlet läuft, gestellt wird. Das Servlet dient in diesem Kontext als Controller und arbeitet die Business-Logik ab. Dann wird das Erstellen der Antwort an die JSP-Seite weitergeleitet. Die View, die der Web-Container an den Browser als Response zurückgeliefert, wird also durch das Verarbeiter der JSP-Seite erstellt. D.h. die JSP-Deklarationen (<%! DEKLARATION %>), JSP-Skriptlets (<% SKRIPTLET %>), JSP-Ausdrücke (<%= AUSDRUCK %>) und JSP-Direktiven (<@ DIREKTIVE %>) werden verarbeitet, so dass eine fertige HTML-Seite an den Browser gesendet werden kann.

Der zugehörige Java-Quellcode des Servlets sieht folgendermaßen aus:

package org.hameister.shoppingcarts;

import java.io.IOException;
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 = "CartJSP", urlPatterns = {"/CartJSP"})
public class CartJSP 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 {

            //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();
            }


            String name = request.getParameter("item");
            if(name != null) {
                String quantity = request.getParameter("quantity");
                //Add item to list
                items.add(quantity+" &times; "+name);
            }


        RequestDispatcher requestDispatcher = request.getRequestDispatcher("jspcart.jsp");
        requestDispatcher.forward(request, response);

    }

    /**
     * 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 JSP-Servlet";
    }
}

Wie schon bei dem Servlet-Beispiel erbt das Servlet von HttpServlet und 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.

Anschließend wird der hinzugefügte Artikel aus dem Request ausgelesen und inklusive der Menge in der items-Liste ergänzt.

Was sofort auffällt ist, dass die Response-Seite nicht in der Klasse erstellt wird, wie das normalerweise bei Servlets der Fall ist. Es ist vielmehr so, dass nur die Business-Logik abgearbeitet wird und dann die Anfrage über den RequestDispatcher an die JSP-Seite weitergeleitet wird. Im Vergleich zu einem herkömmlichen Servlet, ist diese Variante erheblich einfacher umzusetzen und nicht so fehleranfällig.

Die passende JSP-Seite zu dem CartJSP-Servlet sieht folgendermaßen aus:

<%--
    Document   : jspcart.jsp
    Created on : 08.12.2012, 09:19:05
    Author     : hameister
--%>

<%@page import="java.util.List"%>
<%@page import="java.util.ArrayList"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Shopping Cart</title>
    </head>
    <body>

        <%
        //Get items in Cart for the Session
        List<String> items = (List<String>)session.getAttribute("items");
        if(items!=null && items.size()>0) {
        %>
            <h2>Artikel im Warenkorb:</h2>
            <ul>
            <% for(String item : items) { %>
                <li><%= item %></li>
            <% } %>
            </ul>
        <% } %>

        <strong>Artikel zum JSP-Warenkorb hinzufügen:</strong><br/><br/>
        <% // Add button %>
        <form method="POST" action="CartJSP" >
        <input type="text" name="item" >
           <select name="quantity" size="1">
             <option selected>1</option>
             <option>2</option>
             <option>3</option>
             <option>4</option>
             <option>5</option>
           </select>
        <input type="submit" value="Hinzufügen" >
        </form>

        <% // Reset button %>
        <form method="POST" action="CartJSP" >
        <input type="submit" name="reset" value="Warenkorb leeren" >
        </form>

    </body>
</html>

Die JSP-Seite besteht aus einem HTML-Template, welches um JSP-Skriptlets und JSP-Ausdrücke angereichter wird. Innerhalb der JSP-Skriptlets wird der Java-Code eingefügt, der beim Erstellen der HTML-Seite interpretiert wird. D.h. der Java-Code wird im Web-Container ausgeführt, so dass an den Browser nur reines HTML gesendet werden muss. Wie man leicht sehen, kann ist diese JSP-Seite nicht besonders "Fehlertolerant" und die Pflege und Erweiterung ist auch kompliziert, weil zwischen den Sprachen Java und HTML gewechselt werden muss. Deshalb gibt es bei JSP-Seiten die Möglichkeit die sogenannte JSTL-Library zu verwenden. Wie dies funktioniert, wird im nächsten Artikel JSP+JSTL beschrieben.

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