r18-05.doc

(290 KB) Pobierz
Szablon dla tlumaczy

W niniejszym rozdziale:

·         Wykorzystywanie JavaServer Pages

·         Zasady działania

·         Wyrażenia i deklaracje

·         Instrukcje

·         JSP i JavaBeans

·         Dołączenia i przekazania

·         Aplikacja „Narzędzia”

·         Biblioteki własnych znaczników

Rozdział 18.

JavaServer Pages

JavaServer Pages, znana powszechnie jako JSP, to technologia utworzona przez Sun Microsystems, blisko związana z serwletami. JSP była jedną z pierwszych prób utworzenia ogólno dostępnego systemu tworzenia zawartości opartego na serwletach. Osoby od dawna zajmujące się serwletami mogą pamiętać, że JSP została przedstawiona po raz pierwszy na wiosnę 1998 — na tyle wcześnie, by pierwsze wydanie niniejszej książki mogło zawierać krótki samouczek testowej wersji 0.91 JSP. Oczywiście JSP zmieniła się bardzo od tego czasu. W tym rozdziale opisana zostanie JSP 1.1, opierająca się na Servlet API 2.2.

Podobnie jak w przypadku serwletów, Sun udostępnia specyfikację JSP (utworzoną przez grupę ekspertów składającą się z niezależnych producentów i osób), po czym inni producenci konkurują w swoich implementacjach tego standardu. Różnica pomiędzy JSP i innymi technologiami opartymi bezpośrednio na serwletach polega na tym, że JSP jest specyfikacją, nie produktem i wymaga wsparcia ze strony serwera. Większość producentów kontenerów serwletów zapewnia tę obsługę, między innymi Tomcat, w którym mechanizm JSP nosi nazwę Jasper. JSP jest podstawowym składnikiem Java 2, Enterprise Edition (J2EE).

Jednym z głoszonych celów JSP (cytat ze specyfikacji) jest „umożliwienie oddzielenia zawartości dynamicznej i statycznej”. Innym celem jest „umożliwienie tworzenia stron WWW, które zawierają elementy dynamiczne w łatwy sposób, ale z maksymalną mocą i elastycznością”. JSP spełnia dobrze oba te zadania. Jednak, zgodnie z kwestią „maksymalnej mocy” przy tworzeniu JSP, autor strony JSP zawsze posiada całkowitą kontrolę nad systemem, i w związku z tym można powiedzieć, że JSP umożliwia oddzielenie zawartości od grafiki, ale nie wymusza jej ani nie narzuca, jak to się dzieje w przypadku jej alternatyw. Jest to zjawisko podobne do tego, że C++ umożliwia projektowanie obiektowe, ale nie promuje tego doskonałego sposobu tak mocno, jak to się dzieje w przypadku Javy.

JSP jest również technologią bardzo elastyczną, i istnieje wiele sposobów jej wykorzystania. Jednym z nich jest „skrótowy” sposób tworzenia serwletów — programista serwletów, dobrze znający Javę, może umieścić kod Javy bezpośrednio na stronie JSP, zamiast pisać kompletny serwlet — co daje ułatwienia takie jak wyeliminowanie wywołań wyj.println(), umożliwienie bezpośredniego wskazywania na pliki JSP i wykorzystanie własności autokompilacji JSP, Jednak poprzez tworzenie strony JSP zamiast serwletu programista traci pełny kontakt z kodem oraz możliwość kontroli prawdziwego środowiska uruchomieniowego (np. rozszerzanie com.oreilly.servlet.CacheHttpServlet lub tworzenie wyniku binarnego (obrazka)). Z tego powodu najlepiej jest pozostawić prawdziwe kodowanie zwykłym serwletom, a strony JSP wykorzystać przede wszystkim do tworzenia logiki prezentacyjnej.

Nawet podczas zastosowania stron JSP jedynie do logiki prezentacyjnej, można je wykorzystać na wiele sposobów. Jednym z nich jest użycie komponentów JavaBeans osadzonych na stronie. Innym tworzenie własnych znaczników wyglądających jak HTML, ale będących tak naprawdę punktami zaczepienia do wspomagającego kodu Javy. Jeszcze innym jest wysyłanie wszystkich żądań do serwletu, który wykonuje logikę biznesową, po czym przesyła żądanie do JSP tworzącej stronę przy pomocy mechanizmu RequestDispatcher. Technika ta jest często nazywana architekturą Model 2, która to nazwa pochodzi od specyfikacji JSP 0.92. Istnieją również inne mechanizmy noszące dziwne nazwy takie jak Model 1½, Model 2½, czy Model 2+1. Niemożliwe jest wskazanie najlepszej techniki stosowania JSP.

W niniejszym rozdziale opisane zostaną różne sposoby wykorzystania JSP, począwszy od „skrótu do serwletu” a skończywszy na własnych znacznikach. Opis będzie krótki, ale powinien dostarczyć podstaw do porównania JSP z jej alternatywami. Nie zostaną opisane wszystkie opcje architektury, a zamiast tego nacisk zostanie położony na szczegóły techniczne. Opcje architektury i większa ilość informacji na temat JavaServer Pages jest dostępna na stronie głównej JSP pod adresem http://java.sun.com/products/jsp („ściąga” składni jest dostępna pod adresem http://java.sun.com/products/jsp/syntax.pdf) oraz w książce „JavaServer Pages” autorstwa Hansa Bergstena (O'Reilly).

Wykorzystywanie JavaServer Pages

Najbardziej podstawową funkcją JSP jest umożliwienie bezpośredniego umieszczenia kodu serwletu w statycznym pliku HTML[1]. Każdy blok kodu serwletu (nazywany skryptletem) jest ograniczany otwierającym znacznikiem <% i zamykającym %>. Wykorzystywanie skryptletu ułatwia kilka predefiniowanych zmiennych. Sześć najpopularniejszych to:

HttpServletRequest request

Żądanie serwletu.

HttpServletResponse response

Odpowiedź serwletu.

javax.servlet.jsp.JspWriter out

Urządzenie wyświetlające, stosowane podobnie jak PrintWriter, posiadające jednak inną charakterystykę buforowania.

HttpSession session

Sesja użytkownika.

ServletContext application

Aplikacja WWW.

javax.servlet.jsp.PageContext pageContext

Obiekt wykorzystywany przede wszystkim do rozdzielania implementacji serwera, ale często wykorzystywany bezpośrednio do współdzielenia zmiennych pomiędzy stronami JSP i wspomagającymi elementami i znacznikami.

Można dostrzec, że klasy JSP umieszczone są w pakiecie javax.servlet.jsp.

Przykład 18.1 przedstawia prostą stronę JSP wyświetlającą spersonalizowane „Witaj” przy pomocy predefiniowanych zmiennych request i out. Jeżeli posiada się serwer obsługujący JavaServer Pages i pragnie się przetestować tę stronę, należy umieścić plik w podkatalogu katalogu macierzystego dokumentów serwera i zapamiętać ją z rozszerzeniem .jsp. Zakładając, że strona została zapamiętana jako witaj1.jsp, dostęp do niej można uzyskać pod URL-em http://serwer:port/witaj1.jsp lub, jeżeli plik zostanie umieszczony w ścieżce kontekstowej jsp, URL będzie wynosił http://serwer:port/jsp/witaj1.jsp.

Przykład 18.1.

Powitanie przy pomocy JSP

<HTML>

<HEAD><TITLE>Witaj</TITLE></HEAD>

<BODY>

<H1>

<%

if (request.getParameter("nazwa") == null) {

   out.println("Witaj świecie");

}

else {

  out.println("Witaj, " + request.getParameter("nazwa"));

}

%>

</H1>

</BODY></HTML>

Przykładowy wynik uruchomienia powyższego programu przedstawiony jest na rysunku 18.1.

Rysunek 18.1.

Powitanie przy pomocy JavaServer Pages

Zasady działania

Jak działa JSP? Poza obszarem widoczności serwer automatycznie tworzy, kompiluje, ładuje i uruchamia specjalny serwlet tworzący zawartość strony, jak przedstawiono na rysunku 18.2. Można myśleć o tym specjalnym serwlecie jak o serwlecie roboczym, działającym w tle. Statyczne części strony HTML są tworzone przez serwlet roboczy przy pomocy ekwiwalentów wywołań wyj.println(), podczas gdy części dynamiczne są dołączane bezpośrednio. Na przykład, serwlet przedstawiony w przykładzie 18.2 mógłby być serwletem roboczym dla witaj1.jsp działającym na serwerze Tomcat[2].

Rysunek 18.2.

Generowanie stron JavaServer Pages

 

Przykład 18.2.

Generowany automatycznie serwlet roboczy dla witaj1.jsp

import javax.servlet.*;

import javax.servlet.http.*;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.beans.*;

import java.io.*;

import java.util.*;

import org.apache.jasper.runtime.*;

import org.apache.jasper.*;

 

 

public class _0002fwitaj_00031_0002ejspwitaj1_jsp_0 extends HttpJspBase {

 

 

    static {

    }

    public _0002fwitaj_00031_0002ejspwitaj1_jsp_0( ) {

    }

 

    private static boolean _jspx_inited = false;

 

    public final void _jspx_init() throws JasperException {

    }

 

    public void _jspService(HttpServletRequest request, HttpServletResponse  response)

        throws IOException, ServletException {

 

        JspFactory _jspxFactory = null;

        PageContext pageContext = null;

        HttpSession session = null;

        ServletContext application = null;

        ServletConfig config = null;

        JspWriter out = null;

        Object page = this;

        String  _value = null;

        try {

 

            if (_jspx_inited == false) {

                _jspx_init();

                _jspx_inited = true;

            }

            _jspxFactory = JspFactory.getDefaultFactory();

            response.setContentType("text/html;charset=ISO-8859-1");

            pageContext = _jspxFactory.getPageContext(this, request, response,

               "", true, 8192, true);

 

            application = pageContext.getServletContext();

            config = pageContext.getServletConfig();

            session = pageContext.getSession();

            out = pageContext.getOut();

 

            // HTML // begin [file="C:\\ witaj1.jsp";from=(0,0);to=(4,0)]

                out.write("<HTML>\r\n<HEAD><TITLE>Witaj</TITLE></HEAD>\r\n<BODY>\r\n<H1>\r\n");

            // end

            // begin [file="C:\\ witaj1.jsp";from=(4,2);to=(11,0)]

               

                if (request.getParameter("nazwa") == null) {

                   out.println("Witaj œwiecie");

                }

                else {

                  out.println("Witaj, " + request.getParameter("nazwa"));

                }

            // end

            // HTML // begin [file="C:\\ witaj1.jsp";from=(11,2);to=(14,0)]

                out.write("\r\n</H1>\r\n</BODY></HTML>\r\n");

            // end

 

        } catch (Exception ex) {

            if (out != null && out.getBufferSize() != 0)

                out.clearBuffer();

            if (pageContext != null) pageContext.handlePageException(ex);

        } finally {

            if (out != null) out.flush();

            if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);

        }

    }

}

Kiedy wyświetla się stronę JSP po raz pierwszy można zauważyć, że jej wywołanie zabiera pewną ilość czasu. Jest to czas potrzebny serwerowi na stworzenie i skompilowanie serwletu roboczego, co zostało nazwane karą pierwszej osoby. Następne żądania powinny następować ze zwykłą szybkością, ponieważ serwlet może ponownie wykorzystać serwlet w pamięci. Jedynym wyjątkiem jest zmiana pliku .jsp, co serwer rozpoznaje podczas wykonywania następnego żądania tej strony, po czym rekompiluje serwlet działający w tle. Jeżeli kiedykolwiek wystąpi błąd kompilacji, można spodziewać się, że serwer zakomunikuje go w pewien sposób, zazwyczaj poprzez stronę zwracaną klientowi i/lub dziennik zdarzeń serwera.

Wyrażenia i deklaracje

Oprócz skryptletów, JavaServer Pages pozwala na umieszczanie kodu na stronie przy pomocy wyrażeń i deklaracji. Wyrażenie JSP rozpoczyna się znacznikiem <%=, a kończy %>. Każde wyrażenie Javy pomiędzy tymi dwoma znacznikami jest oceniane, jego wynik konwertowany do łańcucha String, a tekst dołączany bezpośrednio do strony. Technika ta eliminuje nieporządek wywołania wyj.println(). Na przykład, <%= buu => dołącza wartość zmiennej buu.

Deklaracja rozpoczyna się od <%!, a kończy na %>. Pomiędzy tymi znacznikami można umieścić dowolny kod serwletu, który powinien pozostać poza metodą usługową serwletu. Zadeklarować można zmienne statyczne lub egzemplarzowe, albo też zdefiniować nowe metody. Przykład 18-3 przedstawia stronę JSP, która wykorzystuje deklarację do zdefiniowania metody pobierzNazwa() oraz wyrażenie ją wyświetlające. Komentarz na początku pliku pokazuje, że komentarze JSP oznaczane są znacznikami <%-- i --%>.

Przykład 18.3.

Powitanie przy pomocy deklaracji JSP

<%-- witaj2.jsp --%>

<HTML>

<HEAD><TITLE>Witaj</TITLE></HEAD>

<BODY>

<H1>

Witaj, <%= pobierzNazwa(request) %>

</H1>

</BODY>

</HTML>

 

<%!

private static final String DOMYSLNA_NAZWA = "świecie";

 

private String pobierzNazwa(HttpServletRequest zad) {

  String nazwa = zad.getParameter("nazwa");

  if (nazwa == null)

    return DOMYSLNA_NAZWA;

  else

    return nazwa;

}

%>

Powyższy kod JSP zachowuje się identycznie jak witaj1.jsp.

Specjalne metody jspInit() i jspDestroy() mogą zostać zaimplementowane wewnątrz deklaracji. Są one wywoływane przez metody init() i destroy() serwletu działającego w tle i dają stronie JSP możliwość zadeklarowania kodu, który powinien zostać wykonany podczas inicjacji i niszczenia. Strona JSP nie może omijać standardowych metod init() i destroy(), ponieważ metody te są ostatecznie deklarowane przez serwlet roboczy.

Instrukcje

Instrukcja JSP pozwala stronie JSP na kontrolowanie pewnych aspektów jej serwletu roboczego. Instrukcje mogą zostać wykorzystane do nakazania serwletowi roboczemu ustawienia jego typu zawartości, importowania pakietu, kontroli buforowania wyświetlania i zarządzania sesją, rozszerzania różnych superklas oraz specjalnej obsługi błędów. Instrukcja może nawet określać wykorzystanie języka skryptowego innego niż Java.

Składnia instrukcji musi zawierać jej nazwę oraz parę nazwa-wartość atrybutu, a całość musi być zwarta pomiędzy znacznikami <%@ i %>. Cudzysłowy zamykające wartość atrybutu są obowiązkowe:

<%@ nazwaInstrukcji nazwaAtrybutu="wartoscAtrybutu" %>

Instrukcja page pozwala JSP na kontrolowanie generowanego serwletu poprzez ustawienie specjalnych atrybutów wymienionych poniżej:

contentType

Określa typ zawartości generowanej strony. Na przykład:

<%@ page contentType="text/plain" %>

Domyślnym typem zawartości jest text/plain; charset=8859_1.

import

Określa listę klas i pakietów, które tworzony serwlet powinien importować. Większa ilość klas może zostać określona w formie listy rozdzielonej przecinkami. Na przykład:

<%@ page import="java.io.*,java.util.Hashtable" %>

Domyślna, ukryta i zawsze dostępna lista klas to java.lang.*,javax.servlet.*,javax.servlet.http.*,javax.servlet.jsp.*.

buffer

Określa minimalną wymaganą wielkość bufora odpowiedzi w kilobajtach, podobnie do metody serwletu setBufferSize(). Wartość powinna zostać zapisana w formie ##kb. Specjalna wartość none wskazuje, że zawartość powinna zostać przekazana bezpośrednio do odpowiedniego PrintWriter w ServletResponse (który może, ale nie musi przekazać zawartość klientowi). Na przykład:

<%@ page buffer="12kb" %>

Domyślna wartość wynosi 8kb.

autoFlush

Określa, czy bufor powinien być opróżniany, kiedy jest pełny, czy zamiast tego powinien zostać wywołany wyjątek IOException. Wartość true wskazuje na opróżnianie, false na wyjątek. Na przykład:

<%@ page autoFlush="true" %>

Wartość domyślna wynosi true.

session

Wskazuje, że strona pragnie posiadać dostęp do sesji użytkownika. Wartość true umieszcza w zakresie zmienną session i może ustawić cookie klienta zarządzające sesją. Na przykład:

...

Zgłoś jeśli naruszono regulamin