Skip to content

8. Biblioteka tagów JSTL

8.0.1. Wprowadzenie

Rozważmy widok [erreurs.jsp], który wyświetla listę błędów:

Image

Istnieje kilka sposobów napisania takiej strony. W tym miejscu skupiamy się wyłącznie na części dotyczącej wyświetlania błędów. Pierwszym rozwiązaniem jest użycie kodu Java, tak jak to zrobiono:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ page import="java.util.ArrayList" %>

<%
// pobieramy dane z modelu
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs"); 
  String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>

<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Les erreurs suivantes se sont produites</h2>
    <ul>
        <%
          for(int i=0;i<erreurs.size();i++){
            out.println("<li>" + (String) erreurs.get(i) + "</li>\n");
        }//for
      %>
    </ul>
    <br>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      <%= lienRetourFormulaire %>
    </a>
  </body>
</html>

Strona JSP pobiera listę błędów z zapytania (wiersz 8) i wyświetla ją za pomocą pętli Java (wiersze 19–23). Strona łączy kod HTML z kodem Java, co może stanowić problem, jeśli stroną ma zajmować się grafik, który zazwyczaj nie rozumie kodu Java. Aby uniknąć takiego mieszania, stosuje się biblioteki tagów, które zapewniają nowe możliwości dla stron JSP. Dzięki bibliotece tagów JSTL (Java Standard Tag Library) powyższy fragment kodu wygląda następująco:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Les erreurs suivantes se sont produites</h2>
    <ul>
            <c:forEach var="erreur" items="${erreurs}">
                <li>${erreur}</li>
            </c:forEach>
    </ul>
    <br>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      ${lienRetourFormulaire}
    </a>
  </body>
</html>

Znacznik (wiersz 4)

<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

wskazuje na wykorzystanie biblioteki tagów, której definicja znajduje się w pliku [/WEB-INF/c.tld]. Tagi te będą używane w kodzie strony z prefiksem „c” (prefix="c"). Można użyć dowolnego prefiksu. W tym przypadku „c” oznacza [core]. Prefiksy pozwalają na korzystanie z bibliotek tagów, które mogą mieć te same nazwy dla niektórych tagów. Zastosowanie prefiksu eliminuje tę niejednoznaczność. Nowa strona nie zawiera już kodu Java w dwóch miejscach, w których wcześniej się on znajdował:

  • pobieranie szablonu strony [erreurs, lienRetourFormulaire] (usunięta część)
  • wyświetlanie listy błędów (wiersze 13–15)

Pętla wyświetlająca błędy została zastąpiona następującym kodem:


            <c:forEach var="erreur" items="${erreurs}">
                <li>${erreur}</li>
            </c:forEach>
  • tag <forEach> służy do wyznaczenia pętli
  • Notacja ${zmienna} służy do zapisania wartości zmiennej

Tag <forEach> ma tutaj dwa atrybuty:

  • items="${erreurs}" wskazuje zbiór obiektów, nad którym należy przeprowadzić iterację. W tym przypadku zbiorem tym jest obiekt „erreurs”. Gdzie go można znaleźć? Strona JSP wyszukuje atrybut o nazwie „erreurs” kolejno i w następującej kolejności w:
    • obiekcie [request], który reprezentuje żądanie przesłane przez kontroler: request.getAttribute("erreurs")
    • obiekcie [session], który reprezentuje sesję klienta: session.getAttribute („błędy”)
    • obiekt [application], który reprezentuje kontekst aplikacji internetowej: application.getAttribute („błędy”)

Kolekcja określona przez atrybut „items” może przybierać różne formy: tableau, ArrayList, obiekt implementujący interfejs List, ...

  • var="błąd" służy do nadania nazwy bieżącemu elementowi przetwarzanej kolekcji. Pętla <forEach> zostanie wykonana kolejno dla każdego elementu kolekcji items. Wewnątrz pętli bieżący element przetwarzanej kolekcji będzie zatem oznaczony tutaj jako błąd.

Notacja ${erreur} wstawia wartość zmiennej „erreur” do tekstu. Zmienna ta niekoniecznie musi być ciągiem znaków. JSTL wykorzystuje metodę erreur.toString() do wstawienia wartości zmiennej „erreur”. Zamiast zapisu ${erreur} można również użyć tagu <c:out value="${erreur}"/>.

Wracając do naszego przykładu wyświetlania błędów:

  • kontroler umieści w żądaniu przekazywanym do strony JSP obiekt ArrayList zawierający komunikaty o błędach, a więc obiekt ArrayList zawierający obiekty String: request.setAttribute("błędy", błędy), gdzie „błędy” to ArrayList;
  • z powodu atrybutu items="${błędy}" strona JSP szuka atrybutu o nazwie błędy, kolejno w zapytaniu, sesji i aplikacji. Znajdzie go w żądaniu: request.getAttribute("błędy”) zwróci ArrayList umieszczony w żądaniu przez kontroler;
  • zmienna erreur o atrybucie var="erreur" będzie zatem wskazywać na bieżący element ArrayList, a więc na obiekt String. Metoda erreur.toString() wstawi wartość tego String, w tym przypadku komunikat o błędzie, do strumienia HTML na stronie.

Obiekty w kolekcji przetwarzanej przez tag <forEach> mogą być bardziej złożone niż zwykłe ciągi znaków. Weźmy na przykład stronę JSP, która wyświetla listę artykułów:

1
2
3
4
5
6
7
            <c:forEach var="article" items="${listarticles}">
                <tr>
                    <td><c:out value="${article.nom}"/></td>
                    <td><c:out value="${article.prix}"/></td>
                    <td><a href="<c:url value="?action=infos&id=${article.id}"/>">Infos</a></td>
                </tr>
     </c:forEach>

gdzie [listarticles] jest obiektem typu ArrayList zawierającym obiekty typu [Article], które, jak zakładamy, są obiektami typu Javabean z polami [id, nom, prix, stockActuel, stockMinimum], przy czym każde z tych pól posiada swoje metody get i set. Obiekt [listarticles] został umieszczony w żądaniu przez kontroler. Poprzednia strona JSP pobierze go z atrybutu items tagu forEach. Obiekt bieżący „article” (var="article") odnosi się zatem do obiektu typu [Article]. Rozważmy tag z linii 3:

<c:out value="${article.nom}"/>

Co oznacza ${article.nom}? W rzeczywistości może to oznaczać różne rzeczy, w zależności od charakteru obiektu „article”. Aby uzyskać wartość article.nom, strona JSP spróbuje wykonać dwie czynności:

  1. article.getNom() – należy zwrócić uwagę na pisownię getNom w celu pobrania pola „nazwa” (standard JavaBean)
  2. article.get("nazwa")

Obiekt [article] może zatem być beanem z polem „nom” lub słownikiem z kluczem „nom”.

Nie ma żadnych ograniczeń dotyczących hierarchii przetwarzanego obiektu. Tak więc tag

<c:out value="${individu.enfants[1].nom}"/>

umożliwia przetwarzanie obiektu [individu] o następującym typie:

class Individu{
    private String nom;
    private String prénom;
    private Individu[] enfants;
     // metody standardu JavaBean
    public String getNom(){ return nom;}
    public String getPrénom(){ return prénom;}
    public Individu getEnfants(int i){ return enfants[i];}
}

Aby uzyskać wartość ${individu.enfants[1].nom}, strona JSP wypróbuje różne metody, w tym tę, która zakończy się powodzeniem:

individu.getEnfants(1).getNom(), gdzie „individu” oznacza obiekt typu Individu.

8.0.2. Zainstaluj i zapoznaj się z biblioteką JSTL

Powyższe wyjaśnienia wystarczą dla aplikacji, która nas interesuje, ale biblioteka znaczników JSTL oferuje inne znaczniki niż te przedstawione. Aby je poznać, można zainstalować samouczek dołączony do pakietu biblioteki.

Będziemy korzystać z implementacji JSTL 1.1 projektu [Jakarta Taglibs] dostępnej pod adresem URL [http://jakarta.apache.org/taglibs/] (maj 2006):

Pobrany plik ZIP zawiera następujące elementy:

Image

Oba pliki z rozszerzeniem .war to archiwa aplikacji internetowych:

  • standard-doc: dokumentacja dotycząca tagów JSTL
  • standard-examples: przykłady zastosowania znaczników

Wdrożymy tę ostatnią aplikację w serwerze Tomcat. Uruchamiamy go za pomocą odpowiedniej opcji z menu [Démarrer], następnie wpisujemy adres URL [http://localhost:8080] i klikamy link [Tomcat Manager]:

Image

Pojawi się strona uwierzytelniania. Logujemy się jako manager / manager lub admin / admin, tak jak pokazano w punkcie 2.3.3.

Image

Pojawia się strona zawierająca listę aplikacji obecnie wdrożonych w Tomcat:

Image

Możemy dodać nową aplikację, korzystając z formularzy znajdujących się na dole strony:

Image

Korzystamy z przycisku [Parcourir], aby wskazać plik .war do wdrożenia.

Image

Na zrzucie ekranu tego nie widać, ale wybraliśmy plik [standard-examples.war] z pobranej dystrybucji JSTL. Przycisk [Deploy] zapisuje i wdraża tę aplikację w Tomcat.

Image

Aplikacja [/standard-examples] została pomyślnie wdrożona. Uruchamiamy ją:

Image

Zachęcamy czytelnika do skorzystania z różnych linków dostępnych na tej stronie, jeśli szuka przykładów zastosowania tagów JSTL.

Aplikację [standard-doc] można wdrożyć w ten sam sposób na podstawie pliku [standard-doc.war]. Zapewnia ona dostęp do dość technicznych informacji na temat biblioteki JSTL. Dla początkujących jest ona mniej interesująca.

8.0.3. Korzystanie z JSTL w aplikacji internetowej

W przykładach dostarczonych wraz z biblioteką JSTL 1.2 strony JSP zawierają na początku pliku następujący tag:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

Z tym tagiem zetknęliśmy się już w punkcie 8.1.1 i podaliśmy jego krótkie wyjaśnienie:

  • [uri]: URI (Uniform Resource Identifier), w którym znajduje się definicja znaczników używanych na stronie. Ten tag URI zostanie wykorzystany przez serwer WWW, gdy strona JSP zostanie przekształcona w kod Java, aby stała się serwletem. Jest on również wykorzystywany przez narzędzia do tworzenia stron internetowych w celu sprawdzenia poprawności składni tagów użytych na stronie lub w celu zapewnienia podpowiedzi podczas wpisywania. Gdy zaczynamy wpisywać tag, narzędzie znające bibliotekę może wówczas zaproponować użytkownikowi możliwe atrybuty dla tego tagu.
  • [prefix]: prefiks identyfikujący te tagi na stronie

Adres URI [http://java.sun.com/jsp/jstl/core] nie jest dostępny, jeśli nie ma połączenia z publiczną siecią internetową. W takim przypadku plik definicji tagów można umieścić lokalnie. Wiele takich plików znajduje się w dystrybucji JSTL 1.2 w folderze [tld] (Tag Language Definition):

Image

JSTL to w rzeczywistości zbiór bibliotek znaczników. Będziemy korzystać wyłącznie z biblioteki [c.tld], zwanej biblioteką „core”. Umieścimy powyższy plik [c.tld] w folderze [WEB-INF] naszych aplikacji:

Image

i umieścimy na naszych stronach następujący tag JSP, aby zadeklarować korzystanie z biblioteki „core”:

<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

Chociaż korzystanie z bibliotek tagów pozwala nam uniknąć umieszczania kodu Java na stronach JSP, tagi te są oczywiście przekształcane na kod Java podczas kompilacji strony JSP do serwletu Java. Wykorzystują one klasy zdefiniowane w dwóch plikach [jstl.jar, standard.jar], które znajdują się w folderze [lib] dystrybucji JSTL:

Image

Oba te archiwa znajdują się w folderze [WEB-INF/lib] naszych aplikacji:

Image

Mamy teraz podstawy, aby zająć się kolejną wersją naszej przykładowej aplikacji.