Laborator 05

Realizarea de aplicații web folosind JavaServer Pages

Obiective

  • descrierea funcționalității pe care o pune la dispoziție tehnologia JavaServer Pages și a avantajelor pe care le oferă în comparație cu alte tehnologii similare;
  • înţelegerea mecanismului prin care este generat răspunsul la o cerere pentru o pagină Internet solicitată din browser, în cazul folosirii de pagini JSP;
  • integrarea unei aplicații web ce folosește Java Servlets / JavaServer Pages în contextul serverului Apache Tomcat;
  • implementarea operațiilor corespunzătoare ciclului de viață a unei pagini JSP;
  • proiectarea unei aplicații web ce folosește Java Servlets / JavaServer Pages potrivit modelului arhitectural adecvat specificațiilor funcționale;
  • folosirea elementelor componente din structura unei pagini JSP (directive, acțiuni, scripleți, expresii, declarații, obiecte implicite) pentru implementarea unor aspecte de logica aplicației ce nu pot fi delegate către Java Servlets;
  • utilizarea unor biblioteci de etichete (predefinite - JSTL sau definite de utilizator) / API-uri (JavaMail / Java Activation Framework) / EL (Expression Language) pentru dezvoltarea unor funcționalități complexe;

Cuvinte Cheie

JavaServer Pages, web application, html, xml, svg, wml, markup, Java Beans, Apache Tomcat 8.x, JSP life cycle, parse exception, jasper exception, client-server model, N-tier model, model-view-controller, directive, action, scriplet, expression, declaration, implicit objects, cookie, session, filter, file upload, resource invocation, email managing, expression language, instant evaluation, lazy evaluation, JavaServer Faces, JSTL, custom tags

Materiale Ajutătoare

TODO

Tehnologia JavaServer Pages - aspecte generale

JavaServer Pages este o tehnologie pentru realizarea de aplicații Internet generate dinamic şi bazate pe HTML, XML sau alte tipuri de documente. A fost lansată pe piaţă de compania Sun Microsystems în anul 1999 ca răspuns la tehnologiile PHP şi ASP, demonstrând faptul că Java este un limbaj de programare suficient de robust pentru a răspunde la provocările web-ului.

Dacă tehnologia JavaServer Pages este comparabilă cu PHP (cu excepţia eficienţei), mai ales de când limbajul a fost dezvoltat în direcţia orientării pe obiecte, în cazul celorlalte tehnologii, JSP prezintă o serie de avantaje. Faţă de ASP .NET, avantajul tehnologiei JSP rezultă din faptul că aceasta este construită peste limbajul de programare Java, mai puternic şi mai uşor de utilizat decât limbajele Microsoft, dispunând de o portabilitate mai mare atât în privinţa sistemelor de operare cât şi a serverelor de aplicaţii. JavaScript este util în generarea de cod HTML dinamic la nivelul clientului dar nu şi la nivelul serverului, mai ales când vine vorba de accesarea de resurse existente pe acesta. De asemenea, SSI (Server Side Includes) a fost proiectat pentru incluziuni destul de simple, nu pentru programe cu funcţionalităţi complexe. Utilizarea JSP este recomandată şi faţă de folosirea exclusivă a Java Servlets întrucât codul devine mult mai uşor de întreţinut, realizându-se totodată o delimitare netă între logica aplicaţiei şi nivelul de prezentare.

Tehnologia JavaServer Pages e parte integrantă Java Enterprise Edition implementând de regulă intefaţa cu utilizatorul dintr-o aplicaţie web Java.

O pagină JSP este un document text care cuprinde două tipuri de date: statice care pot fi descrise în orice format (HTML, XML, SVG, WML) – denumite şi elemente de adnotare (eng. markup) şi dinamice, care pot fi directive JSP şi scripleţi, adică blocuri de cod sursă Java (de obicei cuprinse între adnotările <% şi %>) folosite pentru implementarea unor funcţionalităţi complexe, cum ar fi, de exemplu, comunicaţia cu o bază de date, reţinerea preferinţelor utilizatorilor, accesarea componentelor Java Beans, transferul controlului între pagini şi partajarea informaţiei între cereri, răspunsuri şi pagini.

Funcţionalitatea pe care o pune la dispoziţie tehnologia JSP este aceeaşi cu a aplicaţiilor implementate folosind CGI (Common Gateway Interface), distingându-se de acestea prin performanţă îmbunătăţită (posibilitatea integrării de elemente dinamice în pagina HTML în loc să se folosească fişiere separate), compilarea înainte de plasarea în contextul serverului, posibilitatea accesării tuturor funcţionalităţilor oferite de interfeţele de programare Java (JDBC, JNDI, JAXP, EJB), utilizarea unui model care implică delegarea logicii aplicaţiei către Java Servlets.

În cazul CGI/Perl este necesar ca serverul să încarce un interpretor şi un script de fiecare dată când o pagină este solicitată în browser.

Avantajele utilizării JavaServer Pages includ:

  • separarea logicii aplicaţiei de prezentare (întreţinerea este mai uşoară atât din partea programatorilor, cât şi a dezvoltatorilor web); logica aplicaţiei este folosită pentru a genera conţinutul dinamic şi poate fi realizată prin componente Java Beans, în timp ce interfaţa cu utilizatorul este formată prin etichete JSP;
  • portabilitate (asigurată de limbajul de programare Java – aplicaţia web poate fi utilizată pe mai multe platforme cu arhitectură diferită fără a fi necesară modificarea lor);
  • conţinutul dinamic care poate fi generat;
  • se bazează pe tehnologia Java Servlets, astfel încât preia şi avantajele pe care le oferă aceasta; tehnologia JavaServer Pages reprezintă o abstractizare de nivel înalt a Java Servlets; totodată, în pagina JSP poate fi reutilizat codul care a fost dezvoltat într-un Java Servlet.

Deşi din punctul de vedere al programatorului un Java Servlet reprezintă o clasă Java (unde generarea elementelor de adnotare se face prin apelarea unor metode) iar o pagină JSP se aseamănă mai mult cu un document (unde conţinutul static este separat de conţinutul dinamic – generat de componente Java Beans sau etichete JSP), tehnologiile sunt echivalente. O pagină JSP este transformată într-un Java Servlet (care este compilat) responsabil de comunicaţia cu clientul şi de toate celelalte prelucrări. Modificările realizate asupra unei pagini JSP sunt detectate în mod automat, astfel încât atât procesul de transformare într-un Java Servlet cât şi procesul de compilare corespunzător sunt reluate atunci când se face o cerere pentru aceasta.

Atunci când 1) un client transmite (din browser) o cerere HTTP către server pentru o pagină .jsp, 2) aceasta este transmisă mai departe motorului JSP care încarcă de pe disc resursa care a fost indicată prin intermediul URL-ului. Dacă pe server nu există un Java Servlet corespunzător celei mai recente versiuni a paginii respective, 3) acesta este generat (prin instrucţiuni de tip println ce includ etichetele respective şi convertirea elementelor JSP în cod Java care implementează comportamentul dinamic al paginii) şi 4) apoi compilat într-o clasă executabilă. Acest cod, căruia i se pasează cererea originală 5) este rulat de motorul Java Servlet producând un rezultat în format HTML care este transmis serverului ca răspuns HTTP, acesta 6) fiind pasat clientului care îl afişază în browser, ca şi când ar fi conţinut static.

Integrarea JavaServer Pages cu serverul Apache Tomcat 8.x

În cazul unei aplicaţii web folosind tehnologia JSP, aceasta va fi plasată în directorul webapps.

Paginile .jsp se vor găsi în rădăcina directorului unde a fost dezvoltată aplicaţia web. Pagina care va fi afişată automat atunci când se solicită adresa: http://<server_IP>:<server_port>/<application_directory>/ este index.jsp sau cea precizată prin elementul <welcome-file> din secţiunea <welcome-file-list> a fişierului de configurare web.xml. Acesta va fi plasat în directorul WEB-INF, specificându-se diferiţi parametrii ai aplicaţiei web (inclusiv despre clasele Java Servlet ce implementează logica aplicaţiei). De asemenea, în condiţiile în care sunt folosite metode din clase Java, acestea vor fi plasate într-un director WEB-INF/classes. Este recomandat ca acestea să fie modularizate pe pachete pentru ca referirea lor să se poată realiza cu uşurinţă. Dacă se folosesc biblioteci speciale (în arhive .jar), acestea trebuie incluse în WEB-INF/lib. Astfel de biblioteci speciale pot fi “driver”-ul de conectare la baza de date precum şi biblioteca pentru accesarea funcţionalităţilor oferite de JSTL (JavaServer Pages Standard Tag Library). Deşi sursele aplicaţiei se pot găsi în orice fişier, este recomandat ca acestea să se găsească tot aici, într-un subdirector denumit src sau sources, astfel încât să poată fi identificat cu uşurinţă, iar procesul de compilare al surselor şi de transfer al claselor (realizat înainte de operaţia de configurare – eng. deploy a aplicaţiei web) să nu implice un efort deosebit.

Spre diferenţă de Java Servlets, nu este necesară realizarea configurării aplicaţiei web atunci când sunt realizate modificări asupra paginilor JSP, întrucât acestea sunt detectate automat, determinând generarea unor Java Servlets corespunzătoare atunci când paginile sunt accesate de către client. Repornirea serverului Apache Tomcat va fi necesară doar în cazul operării unor modificări pentru clasele Java ce sunt utilizate de aplicaţie, fiind necesară reîncărcarea lor (după ce compilarea lor este realizată de către programator).

Clasele Java Servlet generate pentru fiecare aplicaţie pot fi vizualizate în %CATALINA_HOME%\work\Catalina\<server_IP>\<application_directory>\org\apache\jsp.

Corespondentul unei pagini page.jsp va fi un Java Servlet page_jsp.java. Tot aici vor fi plasate şi clasele obţinute prin compilarea acestor Java Servlets. Atât operaţia de transformare din pagină JSP în Java Servlet cât şi compilarea claselor Java Servlet generate este realizată automat de către serverul Apache Tomcat.

Datorită faptului că o cerere pentru o pagină JSP implică (în unele situaţii) transformarea într-un Java Servlet precum şi compilarea acestuia, vizualizarea acesteia se va face după o perioadă mai mare decât în situaţia când aceste prelucrări nu mai trebuie realizate. De asemenea, trebuie avută în vedere situaţia în care o astfel de operaţie eşuează, astfel încât în browser sunt afişate excepţiile generate în loc de conţinutul paginii solicitate.

Versiunea Apache Tomcat 8.0.28 suportă specificaţia JSP 2.3 şi EL 3.0.

Ciclul de viață al unei pagini JSP

O pagină JSP tratează cererile asemenea unui servlet. Acesta este motivul pentru care ciclul de viaţă (ca de altfel şi multe alte capabilităţi) al paginilor JSP (în special aspectele dinamice) este asemănător cu cel al tehnologiei Java Servlet.

În plus faţă de etapele caracteristice Java Servlets (creare, iniţializare, gestiune cereri şi răspunsuri, distrugere), mai există şi etapa de compilare. Atunci când o cerere este asociată unei pagini JSP, aceasta este tratată de un servlet special care verifică dacă servlet-ul asociat paginii JSP este mai vechi decât pagina în cauză, situaţie în care îl generează şi îl compilează. Astfel, un avantaj pe care îl au paginile JSP faţă de Java Servlets este că procesul de compilare este realizat automat.

Odată ce pagina JSP a fost transformată şi compilată, servlet-ul corespunzător va urma ciclul de viaţă corespunzător (încărcarea claselor, instanţierea lor, apelul metodei init() pentru iniţializarea resurselor (partajate) şi încărcarea unor fişiere de configurare, execuţia (interacţiunea cu clientul şi realizarea procesărilor prin metoda service()), precum şi apelul metodei destroy() dacă servlet-ul nu mai este necesar). Metodele (generate) se vor numi, în acest caz, _jspInit(), _jspService(), _jspDestroy(). Metodele jspInit() şi jspDestroy() (apelate o singură dată în ciclul de viaţă al unei pagini JSP) pot fi suprascrise ca declaraţii JSP (cuprinse între <%! şi %>). Nu se recomandă însă suprascrierea metodei _jspService() întrucât aceasta este generată în mod automat prin transformarea elementelor JSP în codul Java corespunzător, respectiv prin apelul metodei println() (a obiectului PrintWriter asociat) pentru generarea etichetelor.

public void _jspInit() {
  // ...
}
 
public void _jspDestroy() {
  // ...
}
 
public void _jspService (final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException {
  // ...
}

Toate aceste metode fac parte din interfaţa javax.servlet.HttpJspPage.

În cadrul procesului de compilare, motorul JSP verifică dacă este necesar să compileze pagina respectivă (în situaţia în care aceasta nu a fost niciodată compilată, sau eticheta de timp a servlet-ului corespunzător nu corespunde celei mai recente modificări), acestă operaţie fiind precedată de transformarea paginii, ce include şi parsarea acesteia.

Atât procesul de transformare şi cât şi procesul de compilare pot genera erori care sunt scoase în evidenţă doar atunci când pagina este accesată pentru prima dată:

  • dacă eroarea apare în timpul transformării, serverul va întoarce excepţia ParseException iar clasa servlet va fi incompletă, astfel că ultima linie incompletă va fi un indicator către elementul JSP incorect;
  • dacă eroarea se produce atunci când pagina JSP este compilată (dacă avem o eroare de sintaxă în scriptlet), serverul va întoarce excepţia JasperException precum şi un mesaj care include numele servlet-ului asociat paginii JSP şi linia la care s-a constatat eroarea.

Atunci când se execută o pagină JSP pot apărea excepţii, acestea trebuind tratate separat, în cadrul unei pagini dedicate unei astfel de acţiuni:

<%@ page errorPage="errorpage.jsp" %>

Pentru ca excepţia (într-un obiect de tip javax.servlet.jsp.JspException) să fie disponibilă în cadrul paginii de eroare pentru a o trata, trebuie specificată, la începutul paginii de eroare, directiva:

<%@ page isErrorPage="true|false" %>

În etapa de iniţializare, care se execută o singură dată (după crearea servletului asociat paginii JSP), este apelată metoda _jspInit() unde se realizează conexiunea la baza de date, sunt încărcate diferite resurse şi se fac alte operaţii ce ţin de configurarea aplicaţiei web. În general, aici sunt iniţializate obiectele pentru accesarea funcţionalităţilor puse la dispoziţie de diferite biblioteci (frecvent, Java Server Pages Standard Tag Library), însă programatorul are posibilitatea de a realiza propriile operaţii, prin suprascrierea metodei jspInit() care va fi inclusă în cadrul acestei funcţii.

Etapa de execuţie constă în generarea unui răspuns pentru fiecare cerere prin apelul metodei _jspService(). Aceasta va trata fiecare dintre metodele HTTP prin care clientul comunică cu serverul (GET, POST, PUT, DELETE, OPTIONS, TRACE).

În etapa de distrugere, corespunzătoare procesului de înlăturare a paginii JSP din container, este apelată metoda _jspDestroy() unde sunt eliberate resursele utilizate de aplicaţie, astfel încât acestea să fie procesate de modulul de gestiune a memoriei. În situaţia în care se doreşte eliberarea manuală a acelor resurse care au fost iniţializate (conexiunea la baza de date, diverse fişiere de configurare), poate fi suprascrisă metoda jspDestroy(), conţinutul ei fiind copiat în cuprinsul funcţiei generate.

Arhitectura unei aplicații Internet folosind JavaServer Pages

Combinarea de cod Java cu etichete HTML oferă posibilitatea realizării de pagini cu conţinut dinamic, însă în cazul aplicaţiilor cu funcţionalitate complexă, procesul de întreţinere poate fi dificil, problema provenind în special din faptul că partea de logică a aplicaţiei (care este dezvoltată de programatori – implicând algoritmi şi interacţiune cu baza de date) nu este separată de partea de prezentare (realizată de regulă de dezvoltatori web – concentrându-se mai ales pe elemente de grafică). Arhitectura aplicaţiei JSP va reflecta raportul dintre aceste aspecte.

În modelul 1, logica aplicaţiei este implementată în clase Java (componente Java Beans) şi poate fi apelată din partea de prezentare realizată prin pagini JSP. Această soluţie este adecvată pentru cazul în care aplicaţia nu este foarte complexă, o problemă fiind constituită de faptul că toată comunicaţia cu clientul trebuie realizată din pagina JSP. O astfel de abordare se mai numeşte client-server, are avantajul simplităţii şi dezavantajul lipsei de scalabilitate.

În modelul 2 (denumit şi abordare pe N-niveluri datorită separării arhitecturii serverului pe mai multe niveluri), se respectă şablonul de proiectare Model View Controller unde servlet-ul se ocupă de cererea de la client, implementează logica aplicaţiei, realizând totodată şi instanţierea componentelor Java Beans. Pagina JSP obţine date de la componentele Java Beans şi transmite un răspuns către client, prelucrările fiind realizate în mod transparent. Acest tip de abordare e adoptat atunci când aplicaţia este mai complexă, caracterizându-se prin uşurinţa de întreţinere şi eficienţă.

Aşadar, în cadrul unei pagini JSP se utilizează o combinaţie între etichete HTML (sau XML) şi blocuri de cod sursă Java pentru generarea de elemente dinamice. Fiecare pagină JSP este compilată într-un servlet, acesta primind cererea şi transmiţând mai departe răspunsul.

O pagină JSP poate conţine etichete de prezentare (în limbajul HTML), etichete JSP standard şi etichete definite de utilizator.

JSP foloseşte ca etichete standard:

  • directive;
  • acţiuni;
  • scripleţi:
    • expresii;
    • declaraţii.

De asemenea, pot fi folosite comentarii care pot fi:

  • comentarii JSP: acestea sunt ingorate de motorul JSP;
    <%-- comentariu; --%>
  • comentarii HTML: acestea sunt ignorate de browser;
    <!-- comentariu -->

Directive

O directivă este o instrucţiune care indică informaţii generale despre pagina respectivă. Aceasta afectează întreaga structură a clasei servlet. Directiva oferă container-ului diverse informaţii cu privire la modul în care va gestiona anumite aspecte ale procesării paginii JSP.

<%@ directive attribute="value" %>

Directivele pot avea un număr variabil de perechi atribut-valoare, acestea fiind separate prin virgulă. Spaţiile dintre <%@ şi numele directivei, respectiv dintre ultima pereche atribut-valoare şi %> sunt opţionale. Există trei tipuri de directive:

  • <%@ page ... %> – defineşte atribute specifice paginii JSP, cum ar fi limbajul de programare pentru scripturi, pagina corespunzătoare erorilor şi cerinţe legate de stocarea temporară;
  • <%@ include ... %> – include un fişier în cadrul etapei de transformare a paginii JSP în servletul corespunzător;
  • <%@ taglib ... %> – defineşte o bibliotecă de etichete, conţinând acţiuni definite de utilizator, care vor fi utilizate în cadrul paginii.

Directiva page

Directiva page este utilizată pentru a oferi containerului informaţii despre pagina JSP curentă. Cu toate că această directivă poate fi plasată oriunde în cadrul paginii, se recomandă ca ea să fie inclusă la început.

Sintaxa acestei directive poate lua următoarele forme:

<%@ page attribute="value" %>
<jsp:directive.page attribute="value" />

Atributele suportate de directiva page sunt:

autoFlush controlează comportamentul buffer-ului asociat servletului în cazul în care se umple (conţinutul său va fi golit automat – valoarea true (implicită) sau se generează o eroare – valoarea false); se foloseşte de regulă în asociere cu atributul buffer:
<%@ page buffer="8kb" autoFlush="true" %>
<%@ page autoFlush="false" %>
buffer specifică un model pentru fluxul de ieşire: valoarea none indică faptul că răspunsul va fi transmis imediat clientului; alte valori specifică dimensiunea maximă (în octeţi) a buffer-ului, răspunsul fiind construit în această zonă tampon înainte de a fi transmis clientului
<%@ page buffer="none" %>
<%@ page buffer="8kb" %>
contentType specifică schema de codificare a caracterelor pentru pagina JSP şi pentru răspunsul generat
<%@ page contentType="text/html" %>
<%@ page contentType="text/xml" %>
<%@ page contentType="application/msword" %>
<%@ page contentType="text/html:charset=ISO-8859-1" %>
errorPage defineşte un URL către pagina care raportează excepţiile Java netratate, generate la rulare
<%@ page errorPage="errorpage.jsp"%>
isErrorPage specifică dacă pagina JSP curentă este indicată de proprietatea errorPage a altei pagini JSP
<%@ page isErrorPage="false" %>
<%@ page isErrorPage="true" %>
extends specifică o superclasă pe care servlet-ul generat trebuie să o extindă
<%@ page extends="myPackage.MyClass" %>
import indică o listă de pachete sau de clase Java care vor fi utilizate în pagina JSP; în mod implicit, sunt importate automat java.lang.*, javax.servlet.*, javax.servlet.jsp.*, javax.servlet.http.*; dacă se doreşte importarea mai multor pachete sau clase (inclusiv definite de utilizator), acestea vor fi separate prin virgulă:
<%@ page import="java.sql.*, java.util.*, java.io.*" %>
info defineşte un şir de caractere care poate fi accesat prin metoda getServletInfo() a servlet-ului asociat
<%@ page info="Some info on my JSP Page" %>
isELIgnored specifică dacă expresiile EL (Expression Languge) din pagina JSP de forma ${…} vor fi evaluate (valoarea true, implicită) sau vor fi tratate ca text static
<%@ page isELIgnored="true" %>
<%@ page isELIgnored="false" %>
isScriptingEnabled determină dacă script-urile (scripleţi, expresii non-EL şi declaraţii) sunt permise pentru a fi utilizate (valoarea true – implicită) sau nu (valoarea false)
<%@ page isScriptingEnabled="true" %>
<%@ page isScriptingEnabled="false" %>
isThreadSafe defineşte modelul firului de execuţie pentru servlet-ul generat; implicit, paginile JSP sunt socotite ca fiind sigure (valoarea true) pentru a fi folosite într-un context concurent, iar în caz contrar (valoarea false), container-ul se asigură ca pagina să fie accesată de un singur client la un moment dat
<%@ page isThreadSafe="true" %>
<%@ page isThreadSafe="false" %>
language defineşte limbajul de programare utilizat în pagina JSP
<%@ page language="java" %>
<%@ page language="javascript" %>
session specifică dacă pagina JSP participă (valoarea true) sau nu (valoarea false) la sesiuni HTTP, adică dacă poate accesa sau nu obiectul implicit session şi metodele asociate acestuia
<%@ page session="true" %>
<%@ page session="false" %>

Directiva include

Directiva include este folosită pentru a include resursa specificată în fişierul curent, în cadrul etapei de transformare a paginii JSP în servlet. Practic, se concatenează conţinutul acestor fişiere externe, la locaţia unde a fost specificată (oriunde în pagina JSP):

<%@ include file="myJSPPage.jsp" %>
<jsp:directive.include file="myJSPPage.jsp" />

Se consideră că resursa specificată este indicată prin calea sa relativă, astfel încât atunci când ea lipseşte, se consideră că fişierul se găseşte în acelaşi director cu pagina JSP din care este invocat.

O astfel de funcţionalitate este folosită mai ales pentru includerea de resurse comune pentru toate paginile Internet cum ar fi: header, footer sau meniuri ale aplicaţiei web.

Directiva taglib

Directiva taglib permite definirea de către utilizator a unor etichete JSP care implementează o anumită funcţionalitate, acestea fiind grupate în cadrul unor biblioteci. Se specifică pentru fiecare set de etichete locaţia la care se află biblioteca respectivă (atributul uri), identificând un mecanism (atributul prefix) prin care acestea vor fi identificate în cadrul paginii JSP:

<%@ taglib uri="uri" prefix="prefixOfTag" %>
<jsp:directive.taglib uri="uri" prefix="prefixOfTag" />

Pot fi folosite biblioteci standard (care implementează controlul fluxului într-un program, care pun la dispoziţie mecanisme pentru gestiunea informaţiilor dintr-o bază de date sau care implementează diferite metode uzitate mai frecvent în cadrul oricărei aplicaţii) sau se pot crea biblioteci definite de utilizator:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="my" uri="http://www.mysite.com/mylibrary" %>

Utilizarea unei astfel de etichete se face cu <prefixName:tagName …> unde prefixName este valoarea specificată pentru atributul prefix de la definirea bibliotecii respective, iar tagName numele unei etichete implementate.

Acțiuni

O acţiune este un marcaj care specifică comportamentul motorului Java Servlets de la nivelul serverului web, în momentul compilării marcajele fiind înlocuite cu codul sursă Java corespunzător acţiunii.

Sintaxa unei acţiuni este:

<jsp:actionName attribute="value" />

Atributele comune tututor tipurilor de acţiuni sunt:

  • id: identifică în mod unic acţiunea respectivă permiţând ca aceasta să poată fi referită în cadrul paginii JSP; dacă acţiunea este folosită pentru crearea unei instanţe a unui obiect, prin intermediul identificatorului aceasta poate fi utilizată pe tot parcursul obiectului implicit PageContext;
  • scope: defineşte ciclul de viaţă al acţiunii, adică vizibilitatea elementului concretizată în posibilitatea de utilizare a identificatorului acestuia; valorile pe care le poate sunt: page, request, session şi application.

O acţiune este de fapt o funcţie predefinită, tipurile de acţiuni implementate de API-ul JSP fiind:

<jsp:attribute> defineşte atributul unui element XML definit dinamic
<jsp:body> defineşte corpul unui element XML definit dinamic
<jsp:element> defineşte elemente XML în mod dinamic
Prin acţiunile <jsp:attribute>, <jsp:body> şi <jsp:element> elementele XML pot fi generate în momentul rulării, ca răspuns la o cerere şi nu atunci când sunt compilate sursele.
<jsp:element name="xmlElement">
  <jsp:attribute name="xmlAttribute">
     Attribute Value
  </jsp:attribute>
  <jsp:body>
    Body for XML element
  </jsp:body>
</jsp:element>

<xmlElement xmlAttribute="Attribute Value">
 Body for XML element 
</xmlElement>
<jsp:useBean> găsirea sau instanţierea unei componente Java Bean; se caută dacă este vizibil vreun obiect având identificatorul specificat şi în cazul în care acesta nu este găsit, se încearcă instanţierea clasei indicate; ulterior, se pot folosi acţiunile setProperty şi getProperty pentru a stabili şi pentru a obţine proprietăţile componentei JavaBean

Atributele asociate acţiunii useBean sunt:
class – desemnează numele componentei Java Bean, incluzând şi pachetul în care se găseşte aceasta;
type – indică tipul variabilei ce va reda obiectul în cauză
beanName – specifică numele componentei Java Bean, aşa cum este indicat de metoda instantiate() a clasei java.beans.Beans.
<jsp:useBean id="myObject" class="myPackage.myClass" />
<jsp:getProperty> obţinerea valorii proprietăţii unei componente pe care o converteşte apoi la tipul şir de caractere şi apoi o integrează în fluxul de ieşire

Atributele obligatorii asociate acţiunii getProperty sunt:
name – desemnează componenta Java Bean a cărei proprietate va fi stabilită; trebuie să aibă aceeaşi valoare cu a identificatorului precizat în acţiunea useBean;
property – indică proprietatea care se doreşte a fi stabilită;
<jsp:useBean id="myObject" class="myPackage.myClass" />
...
<jsp:getProperty name="myObject" property="myProperty"/>
<jsp:setProperty> stabilirea valorii proprietăţii unei componente Java Bean; anterior utilizării acestei proprietăţi, componenta Java Bean referită trebuie să fi fost definită; poate fi utilizată în cadrul acţiunii useBean (situaţie în care se execută numai dacă a fost instanţiat un obiect nou) sau independent de ea (caz în care se execută atât atunci când a fost găsit un element cu numele respectiv atunci când a fost instanţiat un obiect nou)

Atributele asociate acţiunii setProperty sunt:
name – desemnează componenta Java Bean a cărei proprietate va fi stabilită; trebuie să aibă aceeaşi valoare cu a identificatorului precizat în acţiunea useBean;
property – indică proprietatea care se doreşte a fi stabilită; valoarea specifică faptul că parametrii cererii ale căror nume se potrivesc cu numele proprietăţilor componentei Java Beans vor fi transmişi către metodele setter respective;
value – specifică valoarea care se doreşte asignată proprietăţii în cauză; dacă valoarea parametrului e null sau parametrul nu există, acţiunea este ignorată;
param – numele parametrului cererii a cărei valoare trebuie să o primească proprietatea; nu se poate folosi concomitent cu value (dar cei doi parametrii pot fi omişi);
<jsp:useBean id="myObject" class="myPackage.myClass">
  <jsp:setProperty name="myObject" property="myProperty" value="myValue" ... />
</jsp:useBean>
<jsp:useBean id="myObject" class="myPackage.myClass" />
...
<jsp:setProperty name="myObject" property="myProperty" value="myValue" ... />
<jsp:forward> pagina JSP curentă îşi încheie activitatea, cererea fiind transmisă către o altă resursă (pagină statică, pagină JSP sau un Java Servlet)

Atributul asociat acţiunii forward este page, prin care se indică un URL relativ al resursei spre care se doreşte a se realiza redirectarea.
<jsp:forward page="myJSPPage.jsp" />
<jsp:include> includerea resursei specificate în momentul când pagina JSP este solicitată (spre diferenţă de directiva cu acelaşi nume, în care includerea avea loc în cadrul procesului de transformare în servlet-ul asociat)

Atributele asociate acţiunii include sunt:
page – un URL (relativ) spre pagina ce se doreşte inclusă;
flush – determină dacă buffer-ul resursei va fi golit înainte de operaţia de includere.
<jsp:include page="myJSPPage.jsp" flush="true" />
<jsp:plugin> generarea codului specific browser-ului (o etichetă <OBJECT> sau <EMBED>) pentru o componentă Java (applet sau clasă Java Bean); dacă plugin-ul necesar nu este prezent, acesta este descărcat şi apoi se poate executa componenta Java; parametrii sunt transmişi prin acţiunea <jsp:param>, în caz de producere a unei erori, se poate specifica un şir de caractere care să fie afişat prin acţiunea <jsp:fallback>
<jsp:plugin type="applet" codebase="mydir" code="MyClass.class" width="100" height="100">
  <jsp:param name="paramname" value="paramvalue" />
  <jsp:fallback>
    Unable to load Java Plugin
  </jsp:fallback>
</jsp:plugin>
<jsp:text> transcrierea unui text folosind un anumit format în pagini şi documente JSP; corpul acţiunii nu poate conţine alte elemente în afară de text şi expresii EL
<jsp:text>My text template</jsp:text>

Scripleți

Un scriplet conţine cod sursă Java (declaraţii de variabile şi metode, expresii) care va fi plasat în metoda de tip service() ce se va genera în servlet-ul paginii JSP respective.

<% Java code fragment %>
<jsp:scriptlet>
  Java code fragment
</jsp:scriptlet>

Acest cod va fi executat pe server atunci când se realizează o cerere pentru pagina JSP care conţine scriplet-ul, iar rezultatul va fi plasat în răspunsul care este transmis clientului.

De regulă, utilizarea scripleţilor este de evitat în paginile JSP întrucât separarea dintre logica aplicaţiei şi prezentare nu mai este atât de evidentă, codul fiind şi mai dificil de întreţinut. Recursul la această tehnologie se face numai pentru a beneficia de facilităţile pe care le pune la dispoziţie limbajul de programare Java şi numai în situaţia în care un comportament similar nu poate fi obţinut prin folosirea EL (Expression Language) împreună cu metodele din bibliotecile JavaServer Pages Standard Tag Library.

Expresii

O expresie este un scriplet, cuprins între <%= şi %>, evaluat în momentul în care este rulat servlet-ul şi convertit la tipul String, fiind inserat în pagina JSP acolo unde este apelat, putând fi inclusă oriunde, fie că se găseşte sau nu în cadrul unei etichete HTML. Ea poate conţine orice expresie care este validă conform specificaţiei Java, însă nu este încheiată prin ;, ca de obicei.

<%= expression %>
<jsp:expression>
  expression
</jsp:expression>

Declarații

O declaraţie permite precizarea de variabile sau de metode, similar cu modul în care s-ar face într-o clasă, domeniul de vizibilitate fiind pe tot parcursul paginii respective. În servlet-ul corespunzător paginii JSP, declaraţiile vor fi incluse astfel încât să poată fi accesate din toate metodele acesteia.

<%! declaration; [declaration; ]+ %>
<jsp:declaration>
  declaration;
  [declaration; ]+
</jsp:declaration>

Obiecte Implicite

În JSP pot fi referite obiecte implicite, disponibile la nivelul fiecărei pagini, putând fi utilizate fără a fi declarate în prealabil. Obiectele implicite mai sunt numite şi variabile predefinite.

Obiect Implicit Tip Descriere
request subclasă a javax.servlet.ServletRequest cererea care a invocat pagina JSP
response subclasă a javax.servlet.ServletResponse răspunsul pe care îl generează pagina JSP
out javax.servlet.jsp.JspWriter obiect care scrie în fluxul de ieşire
session javax.servlet.http.HttpSession obiect sesiune asociat cererii care a invocat pagina JSP
application javax.servlet.ServletContext context pagină JSP
config javax.servlet.ServletConfig informaţii de configurare referitoare la servlet
pageContext javax.servlet.jsp.PageContext contextul paginii JSP
page java.lang.Object referinţă către pagina JSP prin care poate fi accesat servlet-ul asociat
exception java.lang.Throwable acces la detalii cu privire la eroare, în paginile de tratare a excepţiei

Astfel de obiecte vor fi disponibile doar în cadrul metodei _jspService(), astfel încât referirea acestora în cadrul unei declaraţii JSP nu are sens.

Este important ca programatorii să cunoască denumirile acestor obiecte implicite precum şi domeniul lor de vizibilitate, astfel încât să le poată accesa funcţionalitatea în acelaşi mod în care ar fi făcut-o în cadrul clasei Java Servlet corespunzătoare, în care acesteau erau declarate fie ca parametrii ai metodelor respective, fie se putea obţine o instanţă a lor pornind de la obiectele cerere şi răspuns. Prin acestea, tehnologiile Java Servlet şi JavaServer Pages sunt echivalente, oferind aceeaşi funcţionalitate şi aceeaşi uşurinţă în utilizare.

Obiectul implicit request

Un obiect request este creat de fiecare dată când un client solicită o pagină JSP, acesta oferind metode spre a obţine informaţii din antetele HTTP (Accept, Accept-Charset, Accept-Encoding, Accept-Language, Authorization, Cache-Control, Connection, Content-Length, Cookie, Host, If-Modified-Since, If-Unmodified-Since, Referer, User-Agent). Fiind derivat din javax.servlet.http.HttpServletRequest, metodele pe care le pune la dispoziţia programatorilor acest obiect sunt aceleaşi ca în cazul utilizării ca parametru al metodei service() din cadrul Java Servlets.

Astfel, cele mai frecvent folosite metode sunt:

  • Object getAttribute(String) – întoarce valoarea obiectului identificat prin numele său (transmis ca parametru) – convertit la Object sau null dacă obiectul solicitat nu există;
  • Enumeration getAttributeNames() – întoarce o enumerare conţinând numele tuturor atributelor disponibile în cadrul cererii;
  • String getAuthType() – întoarce numele mecanismului de autentificare utilizat pentru securizarea servlet-ului sau null dacă nu se foloseşte un astfel de mecanism;
  • String getCharacterEncoding() – întoarce denumirea schemei de codificare utilizată pentru corpul cererii;
  • int getContentLength() – întoarce dimensiunea (în octeţi) a corpului cererii disponibilă în fluxul de intrare, sau -1 dacă această valoare nu e cunoscută;
  • String getContentType() – întoarce tipul MIME al corpului cererii sau null dacă tipul nu este cunoscut;
  • String getContextPath() – întoarce porţiunea din URI-ul cererii care indică contextul acesteia;
  • Cookie[] getCookies() – întoarce toate obiectele Cookie care au fost transmise de client împreună cu cererea sa;
  • String getHeader(String) – întoarce valoarea antetului specificat din cadrul cererii sub formă de şir de caractere;
  • Enumeration getHeaderNames() – întoarce o enumerare ce cuprinde numele tuturor antetelor conţinute de cerere;
  • int getIntHeader(String) – întoarce valoarea antetului specificat din cadrul cererii sub formă de întreg;
  • ServletInputStream getInputStream() – întoarce corpul cererii (ca date binare) folosind un ServletInputStream;
  • Locale getLocale() – întoarce localizarea preferată a conţinutului, în funcţie de valoarea conţinută de antetul Accept-Language;
  • String getMethod() – întoarce numele metodei HTTP prin care a fost transmisă cererea (GET, POST, PUT, OPTIONS, TRACE, DELETE);
  • String getParameter(String) – întoarce valoarea parametrului specificat (prin nume) în cadrul cererii ca şir de caractere sau null dacă nu există;
  • Enumeration getParameterNames() – întoarce o enumerare incluzând denumirile tuturor parametrilor din cadrul cererii;
  • String[] getParameterValues(String) – întoarce un vector de obiecte de tip şir de caractere conţinând toate valoarile pe care le deţine parametrul identificat (prin nume) în cadrul cererii sau null dacă nu există;
  • String getPathInfo() – întoarce informaţii suplimentare referitoare la cale asociate cu URL-ul transmis împreună cu cererea;
  • String getProtocol() – întoarce numele şi versiunea protocolului prin care a fost transmisă cererea;
  • String getQueryString() – întoarce un şir de caractere reprezentând interogarea cuprinsă în URL după cale;
  • String getRemoteAddr() – întoarce adresa IP (Internet Protocol) a clientului care a transmis cererea;
  • String getRemoteHost() – întoarce numele complet al maşinii de pe care clientul a transmis cererea;
  • String getRemoteUser() – întoarce numele utilizatorului autentificat care a transmis cererea sau null dacă utilizatorul nu este autentificat;
  • String getRequestURI() – întoarce partea din URL-ul asociat cererii începând de la numele protocolului până la şirul ce reprezintă interogarea din cadrul cererii HTTP;
  • String getRequestedSessionId() – întoarce identificatorul sesiunii specificat de client în cerere;
  • int getServerPort() – întoarce portul pe care a fost primită cererea;
  • String getServletPath() – întoarce partea din URL-ul asociat cererii care invocă pagina JSP;
  • HttpSession getSession([boolean]) – întoarce sesiunea asociată cererii sau, dacă aceasta nu există (iar parametrul metodei, în caz că este utilizat, are valoarea true), asociază cererii o sesiune nouă;
  • boolean isSecure() – indică dacă cererea a fost transmisă folosind un canal sigur (cum este HTTPS).

O listă cu antetele HTTP transmise prin intermediul cererii poate fi obţinută astfel:

...
<table>
  <tr><th>Header Name</th><th>Header Value</th></tr>
  <%
    Enumeration headers = request.getHeaderNames();
    while (headers.hasMoreElements()) {
      String headerName = (String)headers.nextElement();
      String headerValue = request.getHeader(headerName);
  %>
  <tr><td><%= headerName %></td><td><%= headerValue %></td></tr>
  <%
    }
  %>
</table>
...

Obiectul implicit response

Un obiect response este de asemenea creat de fiecare dată de către server, conţinând:

  • starea (numele protocolului și versiunea acestuia, codul reprezentând starea și un mesaj de dimensiuni mici care reprezintă o descriere a stării);
  • antetele HTTP (Allow, Cache-Control, Connection, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-Type, Expires, Last-Modified, Location, Refresh, Retry-After, Set-Cookie);
  • documentul reprezentând pagina Internet care va fi afişată în browser.

Fiind derivat din javax.servlet.http.HttpServletResponse, metodele pe care le pune la dispoziţia programatorilor acest obiect sunt aceleaşi ca în cazul utilizării ca parametru al metodei service() din cadrul Java Servlets.

Astfel, cele mai frecvent folosite metode sunt:

  • void addCookie(Cookie) – adaugă la răspuns obiectul Cookie specificat;
  • void addDateHeader(String, long) – adaugă la răspuns un antet reprezentând o dată calendaristică, având numele şi valoarea specificate ca parametrii ai metodei;
  • void addHeader(String, String) – adaugă la răspuns un antet având numele şi valoarea (şir de caractere) specificate ca parametrii ai metodei;
  • void addIntHeader(String, int) – adaugă la răspuns un antet având numele şi valoarea (număr întreg) specificate ca parametrii ai metodei;
  • boolean containsHeader(String) – verifică dacă un antet (indicat prin nume, dat ca parametru) a fost specificat în cadrul răspunsului;
  • String encodeRedirectURL(String) – codifică URL-ul specificat ca parametru pentru a fi utilizat de metoda sendRedirect sau dacă nu este necesară codificarea, îl lasă neschimbat;
  • String encodeURL(String) – codifică URL-ul specificat ca parametru (incluzând identificatorul sesiunii în cadrul său) sau dacă nu este necesară codificarea, îl lasă neschimbat;
  • void flushBuffer() – forţează afişarea conţinutului zonei de memorie tampon în browser;
  • boolean isCommitted() – verifică dacă răspunsul a fost transmis către client;
  • void reset() – elimină toate informaţiile din zona de memorie tampon, inclusiv coduri de statut şi antete;
  • void resetBuffer()– elimină conţinutul zonei de memorie tampon, menţinând însă codurile de statut şi antetele intacte;
  • void sendError(int[, String]) – transmite un răspuns către client reprezentând o eroare indicată prin codul său (şi eventual printr-un mesaj) eliminând şi conţinutul zonei de memorie tampon;
  • void sendRedirect(String) – transmite clientului un răspuns temporar de redirectare către o locaţie indicată prin URL-ul dat ca parametru;
  • void setBufferSize(int) – stabileşte dimensiunea preferată (în octeţi) pentru zona de memorie ce reţine conţinutul răspunsului;
  • void setCharacterEncoding(String) – stabileşte mecanismul de codificare a caracterelor (setul de caractere MIME) corespunzând răspunsul transmis către client;
  • void setContentLength(int) – stabileşte dimensiunea conţinutului transmis către client ca răspuns (pentru protocolul HTTP se stabilește valoarea pe care o are antetul Content-Length);
  • void setContentType(String) – stabileşte tipul de conţinut corespunzător răspunsului transmis către client, dacă această operaţie nu s-a produs deja;
  • void setDateHeader(String, long) – stabileşte un antet reprezentând o dată calendaristică având numele şi valoarea specificate ca parametrii ai metodei;
  • void setHeader(String, String) – stabileşte un antet cu numele şi valoarea (şir de caractere) specificate ca parametrii ai metodei;
  • void setIntHeader(String, int) – stabileşte un antet cu numele şi valoarea (număr întreg) specificate ca parametrii ai metodei;
  • void setLocale(Locale) – stabileşte localizarea răspunsului, dacă acesta nu a fost transmis către client;
  • void setStatus(int) – stabileşte codul de stare pentru răspuns.

Stabilirea unor valori corespunzătoare antetelor HTTP din răspuns poate fi realizat astfel:

...
<%
  response.setDateHeader("Last-Modified",System.currentTimeMillis());
  response.setHeader("Content-Type","text/html");
  response.setIntHeader("Refresh", 60);
%>
...

În exemplu, se stabileşte valoarea antetului Last-Modified ca fiind momentul curent, tipul conţinutului pe care îl are transmis către client (indicat de antetul Content-Type) ca fiind un document HTML, forţând reîncărcarea paginii în mod automat (prin antetul Refresh) la fiecare 60 de secunde.

Obiectul implicit out

Obiectul out este echivalentul obiectului PrintWriter din Java Servlets, fiind utilizat la afişarea conţinutului dinamic în cadrul paginii JSP, atunci când aceasta nu se poate face prin intermediul unor etichete HTML (eventual combinate cu expresii JSP).

Spre diferenţă de obiectul PrintWriter, un obiect JspWriter va genera excepţii de tipul java.io.IOException. De asemenea, pune la dispoziţia utilizatorilor metode suplimentare pentru gestiunea zonei de memorie tampon.

Iniţial, obiectul este instanţiat diferit în funcţie de activarea mecanismului de utilizare a unei zone de memorie tampon (aşa cum este specificat de atributul buffered al directivei page). Metodele print şi println pot fi utilizate spre a afişa conţinutul unor obiecte cu tipurile boolean, char, String, int, long, float, double, Object şi altele. De asemenea, metoda flush() este folosită pentru a transmite conţinutul zonei de memorie tampon către client, golind conţinutul fluxului de ieşire.

Obiectul implicit session

Obiectul session este creat în mod automat (nu mai este necesară iniţializarea sau obţinerea dintr-un obiect de tip request prin metoda getSession()) pentru fiecare client ce accesează pagina în cauză. Dezactivarea acestui tip de comportament poate fi realizată doar prin intermediul atributului cu acelaşi nume din directiva page.

Metodele pe care le pune la dispoziţie acest obiect sunt cele specificate de interfaţa javax.servlet.http.HttpSession:

  • Object getAttribute(String) – întoarce obiectul care este asociat numelui transmis ca parametru al metodei în cadrul sesiunii sau null dacă nu există nici un obiect asociat;
  • Enumeration getAtrributeNames() – întoarce o enumerare ce conţine denumirile tuturor obiectelor asociate sesiunii;
  • long getCreationTime() – întoarce momentul la care a fost creată sesiunea, exprimată în milisecunde raportate la data 1 ianuarie 1970 (GMT);
  • String getId() – întoarce un şir de caractere care identifică în mod unic sesiunea;
  • long getLastAccessedTime() – întoarce momentul la care clientul a transmis ultima dată o cerere asociată sesiunii, exprimată în milisecunde raportate la data 1 ianuarie 1970 (GMT);
  • int getMaxInactiveInterval() – întoarce perioada de timp maximă, exprimată în secunde, în care containerul servletului va menţine sesiunea, între diferite accesări provenite de la clienţi;
  • void invalidate() – invalidează sesiunea, eliminând orice asociere a unui obiect la aceasta;
  • boolean isNew() – stabileşte dacă clientul nu are cunoştinţă de sesiune sau dacă alege să nu participe la aceasta;
  • void removeAttribute(String) – elimină asocierea obiectului identificat prin numele transmis ca parametru al metodei la sesiune;
  • void setAttribute(String, Object) – asociază la sesiune un obiect ale cărui nume şi valoare sunt specificate ca parametrii ai metodei;
  • void setMaxInactiveInterval(int) – stabileşte perioada de timp maximă, exprimată în secunde, care se poate scurge între diferite accesări provenite de la clienţi până când sesiunea va fi invalidată de containerul servletului; valoarea poate fi specificată şi în fişierul de configurare web.xml:
    <session-config>
      <session-timeout>60</session-timeout>
    </session-config>

    Această valoare va suprascrie valoarea implicită specificată de serverul Apache Tomcat 8.x, care este de 30 de minute. În fişierul de configurare web.xml timpul de expirare va fi specificat, spre diferenţă de metoda setMaxInactiveInterval() nu în secunde, ci în minute.

În afară de sesiuni, pentru gestiunea comunicaţiei dintre client şi server, pot fi utilizate cookie-uri, fişiere text reţinute pe maşina client (dacă aceasta permite stocarea lor) şi citite de server pentru a identifica în mod unic conexiunea respectivă. Acestea sunt transmise de regulă prin antete HTTP, câmpul Set-Cookie reţinând perechi de tipul cheie-valoare pentru atributele name, expires, path şi domain. De fiecare dată când clientul va accesa o pagină care corespunde cu valorile reţinute de atributele path şi domain, în cazul în care nu a fost depăşită perioada specificată de atributul expires, cookie-ul va fi inclus în antetele HTTP transmise către server.

Metodele pe care le pune la dispoziţie clasa Cookie sunt:

  • String getComment() – întoarce comentariul care descrie scopul obiectului cookie sau null dacă nu există nici un comentariu asociat;
  • String getDomain() – returnează domeniul pentru care se aplică obiectul cookie;
  • int getMaxAge() – pune la dispoziţie durata de viaţă (exprimată în secunde) pentru obiectul cookie; valoarea -1 exprimă faptul că obiectul cookie va persista până când se va părăsi browserul;
  • String getName() – obţine denumirea obiectului cookie; danumirea unui obiect cookie nu mai poate fi modificată după crearea sa;
  • String getPath() – reflectă calea pentru care se aplică obiectul cookie;
  • String getValue() – redă valoarea asociată obiectului cookie;
  • void setComment(String) – fixează un comentariu care indică scopul obiectului cookie, acesta fiind util în situaţia în care browserul îl afişează utilizatorului pentru a lua o decizie în privinţa sa;
  • void setDomain(String) – indică domeniul pentru care se aplică obiectul cookie;
  • void setMaxAge(int) – stabileşte timpul (exprimat în secunde) care ar trebui să se scurgă înainte de expirarea obiectului cookie; în cazul în care atributul nu este precizat, obiectul cookie va exista doar pe parcursul sesiunii curente;
  • void setPath(String) – setează calea pentru care se aplică obiectul cookie; dacă acest atribut nu este specificat, obiectul cookie este transmis pentru toate URL-urile care se găsesc în acelaşi director sau subdirector cu pagina curentă;
  • void setSecure(boolean) – determină dacă obiectul cookie ar trebui transmis numai prin legături criptate;
  • void setValue(String) – precizează valoarea asociată cu obiectul cookie.

Utilizarea unui obiect Cookie presupune crearea sa, precizarea duratei (maxime) de viaţă şi transmiterea sa în cadrul obiectului response la client prin metoda addCookie().

Crearea unui obiect de tip Cookie implică specificarea unei denumiri şi a valorii asociate. Nici denumirea şi nici valoarea asociată nu trebuie să conţină în cadrul lor caracterele [, ], (, ), =, ,, , /, ?, @, :, ;.

Totodată, ştergerea presupune stabilirea duratei (maxime) de viaţă nule înainte de a fi inclus în antetele HTTP către browserul ce se ocupă cu reţinerea sa.

Obiectul implicit application

Obiectul application este de fapt un wrapper pentru obiectul ServletContext al servletului asociat paginii JSP, fiind o reprezentare a acesteia pe parcursul întregului său ciclu de viaţă, fiind iniţializat în metoda _jspInit() şi distrus în metoda _jspDestroy(). Este folosit împreună cu metodele getAttribute(String) şi setAttribute(String, Object) atunci când se doreşte ca proprietăţile respective să aibă un domeniu de vizibilitate corespunzător întregii aplicaţii, adică tuturor paginilor care o alcătuiesc. O funcţionalitate ce se pretează folosirii acestui obiect este determinarea numărului de accesări al aplicaţiei respective. Într-o astfel de situaţie, pentru a se evita situaţia pierderii datelor în cazul repornirii aplicaţiei (serverului web care o găzduieşte), trebuie asigurată şi persistenţa acestora prin stocarea lor într-o bază de date.

Obiectul implicit config

Obiectul config este şi el un wrapper pentru obiectul ServletConfig, permiţând programatorilor să acceseze parametrii de iniţializare ai motorului Java Servlet sau JSP, obţinuţi prin metodele getInitParameter(String), respectiv getInitParameterNames(). Numele servletului asociat, aşa cum este specificat prin elementul <servlet-name> din fişierul de configurare web.xml, poate fi accesat prin metoda getServletName().

Obiectum implicit pageContext

Obiectul pageContext este folosit ca o reprezentare a întregii pagini JSP, având scopul de a accesa informaţia cu privire la aceasta, evitând majoritatea detaliilor cu privire la implementare. Acest obiect reţine referinţe către obiectele request şi response, iar obiectele config, session şi out pot fi obţinute prin atribute ale sale. De asemenea, el conţine şi informaţii cu privire la directivele transmise paginii JSP. În cadrul său sunt definite mai multe câmpuri, printre care şi domeniile de vizibilitate PAGE_SCOPE, REQUEST_SCOPE, SESSION_SCOPE, APPLICATION_SCOPE. Implementează mai multe metode, majoritatea fiind moştenite din clasa javax.servlet.jsp.JspContext. Se pot realiza operaţii pe atribute (stabilire, obţinere sau ştergere) de fiecare dată specificându-se şi domeniul său de vizibilitate.

Obiectul implicit page

Obiectul page este o referinţă către instanţa paginii JSP curente, în fapt un sinonim pentru obiectul this.

Obiectul implicit exception

Obiectul exception este un wrapper ce conţine excepţia generată de către pagina anterioară, fiind folosit pentru a construi un răspuns adecvat la eroarea în cauză. Acesta este disponibil numai în paginile JSP de eroare, indicate prin atributul errorPage al directivei page spre a fi invocate în momentul în care se produc anumite erori.

O excepţie poate fi:

  • verificată (o eroare de utilizator care nu poate fi prevăzută de programator, generată în momentul compilării);
  • generată la rulare (ignorată la momentul compilării, dar care ar fi putut fi evitată prin anumite mecanisme de prevenţie);
  • eroare, în privinţa căreia nu se poate face mare lucru, depăşind posibilităţile de intervenţie atât din partea utilizatorului cât şi din partea programatorului.

Fiind un obiect de tip java.lang.Throwable, pentru un astfel de obiect pot fi apelate metodele:

  • String getMessage() – oferă un mesaj detaliat cu privire la excepţia care s-a produs; acest mesaj detaliat cu privire la excepţia care s-a produs poate fi iniţializat în constructorul obiectului Throwable.
  • Throwable getCause() – întoarce cauza excepţiei;
  • String toString() – întoarce numele clasei concatenat cu mesajul detaliat referitor la excepţia care s-a produs;
  • void printStackTrace() – afişează rezultatul metodei toString() împreună cu stiva de erori la fluxul de ieşire pentru erori System.err;
  • StackTraceElement[] getStackTrace() – întoarce un vector conţinând fiecare element al stivei de erori; elementul de pe poziţia 0 reprezintă vârful stivei de erori, iar ultimul element reprezintă baza stivei de erori (metoda de la apelul căreia a pornit eroarea);
  • Throwable filllnStackTrace() – completează stiva de erori a obiectului Throwable cu stiva de erori curentă.

Aceste metode pot fi obţinute şi prin intermediul obiectului pageContext care dispune de atributele exception (prin intermediul căruia poate fi vizualizată şi stiva de erori – atributul stackTrace) şi errorData (ce oferă acces la calea relativă a paginii JSP care a generat eroarea – atributul URI şi codul de statut corespunzător excepţiei – atributul statusCode).

Alternativ, în cadrul unui scriplet se poate folosi un bloc try { … } catch, tratarea erorii realizându-se în cadrul aceleiaşi pagini JSP. Totuşi, o astfel de abordare trebuie evitată, recurgându-se la ea numai în situaţia în care se vrea ca recuperarea din eroare să se realizeze cât mai rapid.

Filtre

Filtrele sunt folosite pentru a intercepta cererile de la un client înainte ca acestea să acceseze anumite resurse sau pentru a gestiona răspunsurile generate de server înainte ca acestea să fie transmise înapoi. Funcţionalitatea unui filtru trebuie specificată în metoda doFilter(), care va fi suprascrisă de către orice clasă ce implementează interfaţa javax.servlet.Filter:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, javax.servlet.ServletException

Pot fi implementate filtre pentru autentificare, filtre pentru compresia datelor, filtre de criptare filtre care declanşează evenimente de acces a unor resurse, filtre de conversie a imaginilor, filtre pentru jurnalizare şi auditare, lanţuri de filtre MIME-TYPE, filtre pentru parsare şi filtre XSLT care transformă conţinutul XML.

În afară de această metodă, mai trebuie implementate şi metodele init() şi destroy().

Asocierea dintre un filtru şi un Java Servlet sau pagină JSP precum şi ordinea execuţiei acestora este determinată din fişierul de configurare web.xml în care elementul <filter> indică numele filtrului, clasa asociată precum şi parametrii folosiţi la iniţializarea acestuia, iar elementul <filter-mapping> specifică asocierile (şi ordinea) dintre un filtru şi clasele Java Servlet respectiv paginile JSP. Ordinea în care sunt executate filtrele pentru un Java Servlet respectiv pagină JSP este aceeaşi cu cea în care acestea sunt mapate în fişierul de configurare web.xml. Dacă se doreşte ca un filtru să fie asociat la mai multe resurse, se poate folosi masca /* în cadrul elementului <url-pattern>.

Încărcarea unui fișier pe server

Încărcarea unui fişier pe server (la locaţia specificată de parametrul file-upload din fişierul de configurare web.xml) se face prin intermediul unui formular care specifică ca tip de criptare (enctype) multipart/form-data în care controlul pentru intrare (input) este de tip (type) file:

<context-param>
  <param-name>file-upload</param-name>
  <param-value>
    My Upload Location
  </param-value>
</context-param>
<form action="myJSPPage.jsp" method="POST" enctype="multipart/form-data">
  <input type="file" name="file" size="100" />
  <br />
  <input type="submit" value="Upload File" />
</form>

Pentru procesarea în cadrul paginii JSP a încărcării fişierului pe server, poate fi folosită biblioteca commons-fileupload dezvoltată de Apache ce oferă posibilitatea încărcării mai multor fişiere simultan, implementând metode pentru obţinerea diferitelor proprietăţi ale resursei respective (cale absolută, denumire, dimensiune) precum şi funcţionalităţi precum citirea din memorie şi scrierea pe disc.

Invocarea altor resurse

Frecvent, invocarea altor resurse se referă la redirectare, realizată atunci când documentul s-a mutat la o altă adresă sau atunci când se doreşte echilibrarea încărcării. În acest sens se foloseşte metoda sendRedirect() apelată pe obiectul response(), care primeşte ca parametru URL-ul resursei către care se doreşte a se realiza redirectarea. Alternativ, acest comportament se poate obţine prin stabilirea unor valori pentru antetele HTTP:

response.setIntHeader("Status", response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", myLocation);

Operații cu obiecte de tip dată calendaristică

În cadrul aplicaţiilor web, se lucrează destul de des cu obiecte de tipul dată calendaristică, integrarea lor în cadrul tehnologiei Java Servlets sau JSP făcându-se prin obiecte de tip java.util.Date, ce pot fi create fie prin intermediul unui constructor vid (caz în care obiectul va conţine data curentă) sau al unui constructor ce primeşte un parametru de tip long, ce indică durata, exprimată în milisecunde, care s-a scurs de la 1 ianuarie 1970 (GMT). Operaţiile pe care le suportă un astfel de obiect sunt after(Date), before(Date), clone(), compareTo(Date[|Object]), equals(Object), getTime(), hasCode(), setTime(long), toString(). Formatarea unui astfel de obiect se poate realiza folosind clasa SimpleDateFormat în care anumite caractere codifică atributele obiectului Date.

Funcționalitate de tip poștă electronică

De asemenea, se întâlneşte frecvent necesitatea de a transmite mesaje folosind poşta electronică, o astfel de funcţionalitate putând fi integrată prin API-ul JavaMail şi framework-ul Java Activation Framework (JAF).

Un obiect Session necesar construirii unui mesaj ce poate fi transmis prin poşta electronică va fi construit dintr-o serie de proprietăţi între care obligatorie este mail.smtp.host. În situaţia în care serverul de poştă electronică necesită autentificare, vor fi precizate şi atributele mail.user / mail.password. Obiectul reprezentând mesajul propriu-zis va avea tipul MimeMessage, precizarea câmpurilor corespunzătoare (From:, To:, Subject: şi Text:) realizându-se prin metodele:

  • void setFrom(InternetAddress) – parametrul metodei construindu-se pornind de la adresa de poştă electronică a destinatarului;
  • void addRecipients(Message.RecipientType, Address[]), unde
    • tipul poate avea valorile:
      • Message.RecipientType.TO;
      • Message.RecipientType.CC (CarbonCopy);
      • Message.RecipientType.BCC (Blind Carbon Copy).
    • vectorul de adrese se creează folosind constructorul InternetAddress căruia i se transmite ca parametru adresa de poştă electronică a expeditorului.
  • void setSubject(String) – se stabileşte subiectul mesajului;
  • void setText(String) – se precizează corpul mesajului;
  • void setContent(String, String) – se precizează corpul mesajului, având atât conţinutul, cât şi formatul precizate ca parametri; în acest mod se pot transmite documente care au alt format în afară de plain-text, de exemplu HTML / XML. În acest caz, dimensiunea pe care o poate avea corpul mesajului nu este limitată decât de serverul de poştă electronică.

Transmiterea propriu-zisă a mesajului se face prin metoda statică send() definită în clasa Transport, aceasta generând o excepţie MessagingException dacă mesajul nu a putut fi transmis din diverse motive.

De asemenea, pot fi incluse ataşamente prin construirea unui obiect MimeMultiPart la care se adaugă (folosind metoda addBodyPart()) fragmente ale ataşamentului respectiv, de tipul MimeBodyPart. Un astfel de obiect suportă metodele setText(String) pentru a indica o corpul mesajului, respectiv setDataHandler(DataHandler) şi setFileName(String) pentru a specifica fişierul care conţine ataşamentul. Indicarea conţinutului ca fiind un obiect de tipul MimeMultiPart se face tot prin metoda setContent().

Un obiect de tip DataHandler se obţine dintr-un obiect FileDataSource, care la rândul său este construit pornind de la denumirea fişierului în cauză, la care se adaugă şi calea către el, relativă sau absolută. În situaţia în care nu se specifică nici o cale, fişierul va fi căutat în acelaşi director în care este plasată clasa Java Servlet sau pagina JSP care încearcă transmiterea sa prin intermediul poştei electronice.

Informaţiile cu privire la destinatar, expeditor, subiect şi conţinut pot fi incluse într-un formular, apoi preluate din obiectul request astfel încât transmiterea mesajului să se facă pe baza acestora.

<%@ page import="javax.mail.*", "javax.mail.internet.*", "javax.activation.*" %>
...
<%
  Properties properties = System.getProperties();
  properties.setProperty("mail.smtp.host","localhost");
  properties.setProperty("mail.user",myUser);
  properties.setProperty("mail.password",myPassword);
  Session mailSession = Session.getDefaultInstance(properties);
  try {
    MimeMessage mailMimeMessage = new MimeMessage(maiSession);
    mailMimeMessage.setFrom(new InternetAddress(from));
    mailMimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
    mailMimeMessage.setSubject("My Subject");
    Multipart mailMultipart = new MimeMultipart();
    BodyPart mailBodyPart;
    mailBodyPart = new MimeBodyPart();
    mailBodyPart.setText("My Mail Body");
    mailMultipart.addBodyPart(mailBodyPart);
    mailBodyPart = new MimeBodyPart();
    String filename = "myFileName.myExtension";
    mailBodyPart.setDataHandler(new DataHandler(new FileDataSource(filename)));
    mailBodyPart.setFileName(filename);
    mailMultiPart.addBodyPart(mailBodyPart);
    mailMimeMessage.setContent(mailMultiPart);
    Transport.send(mailMimeMessage);
  } catch (MessagingException exception) {
    System.out.println("An exception has occurred: "+exception.getMessage();
    if (Constants.DEBUG) {
      exception.printStackTrace();
    }
  }
%>

Utilizarea EL (Expression Language) în pagini JSP

EL (Expression Language) pune la dispoziţia utilizatorilor un mecanism prin care nivelul de prezentare poate comunica cu nivelul de logică al aplicaţiei (mai ales componente Java Beans), implementând operaţii aritmetice şi logice folosind tipuri de date întregi, reale, şiruri de caractere, valori adevărat / fals şi null.

Tehnologia Java Server Pages foloseşte Expression Language pentru:

  • evaluarea imediată şi leneşă a expresiilor prin realizarea de operaţii aritmetice şi logice în mod dinamic;
  • posibilitatea de a stabili şi de a obţine informaţii (având structuri de date variate), în special proprietăţi ale componentelor Java Beans, pe baza interacţiunii cu utilizatorul;
  • folosirea de obiecte implicite;
  • abilitatea de a invoca metode (publice şi statice).

În Expression Language pot fi folosite următoarele tipuri de expresii:

  • expresii cu evaluare imediată (a căror valoare este stabilită instant de către tehnologia împreună cu care este utilizată, în cazul de faţă Java Server Pages) şi expresii cu evaluare leneşă (a căror valoare poate fi evaluată ulterior de către tehnologia împreună cu care este utilizată);
  • expresii valoare (ce referă date) şi expresii metodă (ce invocă metode);
  • expresii rvalue (care pot doar să citească date dintr-un obiect extern) şi expresii lvalue (care pot atât să citească cât şi să scrie date din / într-un obiect extern).

Expresiile cu evaluare imediată, desemnate prin sintaxa ${expression}, sunt calculate înainte ca pagina Internet să fie afişată. Aceste expresii pot fi folosite numai ca valori ale unei etichete care acceptă expresii evaluate în momentul rulării şi sunt întotdeauna expresii de tip rvalue.

<input type="submit" name="${inputName}" value="${inputValue}">

Pentru expresiile cu evaluare leneşă, pentru care se foloseşte sintaxa #{expression}, valoarea poate fi determinată mai târziu, prin mecanisme ce ţin de tehnologia împreună cu care e folosită Expression Language, pe parcursul ciclului de viaţă al paginii Internet. Aceste expresii pot fi expresii valoare utilizate atât pentru a citi cât şi pentru a scrie informaţii dar şi expresii metodă.

<table><tr><td>#{inputName}</td><td>#{inputValue}</td></tr></table>
De regulă, expresiile cu evaluare leneşă sunt folosite mai des împreună cu JavaServer Faces pentru că această tehnologie are un ciclu de viaţă împărţit în mai multe faze, astfel încât determinarea valorii unei expresii nu se poate realiza decât la un anumit moment, după tratarea evenimentelor cu privire la componente şi validarea datelor.

Expresiile de tip valoare pot fi clasificate în expresii rvalue şi lvalue după cum dispun sau nu de posibilitatea de a scrie informaţii. Expresiile cu evaluare imediată sunt întotdeauna expresii rvalue, în timp ce expresiile cu evaluare leneşă sunt de regulă expresii lvalue.

Expresia ${entitybean.attribute} obţine valoarea unui atribut din cadrul unei componente Java Bean, evaluându-l instant şi transmiţând mai departe rezultatul obţinut.

Expresia #{entitybean.attribute} poate avea acelaşi comportament ca expresia de mai sus, însă eticheta în cadrul căreia este folosită poate decide evaluarea sa la un moment de timp ulterior. Mai mult, atunci când pagina Internet este solicitată, expresia va fi de tipul rvalue (obţinând valoarea atributului), în timp ce în cadrul etapei postback ea poate fi de tipul lvalue (putând stabili valoarea atributului).

Toate expresiile pot referi următoarele tipuri de obiecte, împreună cu atributele lor: componente Java Beans, colecţii, structuri de date Java de tip enumerare, obiecte implicite. Pentru a le utiliza, se foloseşte o expresie în care variabila este reprezentată de denumirea obiectului:

${myObject}
#{myObject}
În cazul structurilor de date Java de tip enumerare, elementele pot fi referite folosind tipul String. Pentru tipul de dată public enum EnumType {attribute1, atrribute2, …, attributen}, dacă este întâlnit un şir de caractere având valoarea ${“atrributek”}, acesta va fi convertit automat la tipul EnumType.atrributek.

Container-ul paginii Internet evaluează variabila ce apare în expresie căutându-i valoarea ce este oferită de PageContext.findAttribute(“myObject”), domeniile de vizibilitate investigate fiind page, request, session şi application. Dacă obiectul nu este găsit, se returnează o valoare null. Pot fi utilizare motoare EL particularizate pentru a se modifica modul în care sunt evaluate expresiile.

Pentru a referi proprietăţile unei componente Java Bean sau a instanţei unei enumerări, elementele unei colecţii sau atributele unui obiect implicit pot fi folosite notaţiile . sau [], care sunt echivalente. Pentru şirurile de caractere se pot folosi atât apostroafe, cât şi ghilimele.

Următoarele expresii sunt echivalente:

${myObject.myAttribute}
${myObject['myAttribute']}
${myObject["myAttribute"]}

Expresii similare pot fi formate şi pentru asigurarea evaluării leneşe.

De asemenea, pot fi folosite şi combinaţii ale operatorilor . şi [] în cadrul aceleiaşi expresii.

În cazul componentelor JavaBeans, un atribut myAttribute poate fi referit în cadrul unei expresii EL doar în situaţia în care este implementată o metodă getter de acces la acesta, având numele getMyAttribute().

Pentru accesarea elementelor unui vector sau al unei liste, trebuie folosite valori literale (fără apostroafe sau ghilimele) ce pot fi convertite la un întreg sau notaţia [] ce primeşte de asemenea un întreg, în timp ce pentru un obiect de tip Map accesarea implică folosirea unei chei de tip şir de caractere:

// array or list: firstComponent can be narrowed to 0
${myObject.myAttribute[0]}
${myObject.myAttribute[firstComponent]}
// map
${myObject.myAttribute["firstComponent"]}

În Expression Language pot fi folosite următoarele tipuri de date:

  • Boolean: poate avea valorile true sau false;
  • numere întregi, numere reale: utilizate la fel ca în Java;
  • String (şir de caractere), referite cu apostroafe sau ghilimele, \ fiind folosit pe post de caracter escape (\“, ' → \', \\\);
  • null.

Expresiile de tip valoare pot fi utilizate în text static sau în etichete (standard sau definite de utilizator) care acceptă o expresie. Unele etichete acceptă doar expresii de tip rvalue în timp ce alte expresii pot accepta şi expresii de tip lvalue.

Valoarea unei expresii în text static este evaluată şi ulterior inclusă în pagina Internet:

<my:tag>my text1 ${expression} my text2</my:tag>

Atributul valoare al unei etichete poate fi iniţializat folosind o expresie rvalue sau lvalue astfel:

  • folosind o singură expresie; expresiile sunt evaluate şi rezultatul convertit la tipul atributului respectiv:
    <my:tag value="${expression}" />
    <my:tag value="#{expression}" />
  • folosind una sau mai multe expresii, separate sau înconjurate de text; se numesc expresii compuse şi sunt evaluate de la stânga la dreapta, fiecare expresie fiind convertită la tipul String şi concatenată cu alte texte, şirul de caractere rezultat fiind convertit la tipul atributului respectiv:
    <my:tag value="my text1 ${expression1} my text2 ${expression2}" />
    <my:tag value="my text1 #{expression1} my text2 #{expression2}" />

    În EL 3.0 operatorul + e folosit pentru concatenarea şirurilor de caractere.

  • folosind doar text; se numesc expresii literale şi valoarea String a atributului este converită la tipul atributului respectiv
    <my:tag value="my text" />

Toate expresiile utilizate pentru a stabili valori sunt evaluate în contextul unui tip de date aşteptat. Dacă rezultatul obţinut în urma evaluării expresiei nu corespunde exact tipului de date aşteptat, se va realiza o conversie de tip.

Expresiile de tip metodă permit invocarea unei metode implementate în cadrul unei componente Java Bean, care întoarce un rezultat. De regulă, acestea sunt folosite pentru a realiza anumite procesări asociate cu controlul din contextul căruia sunt apelate, fiind invocate în momentul în care este generat un eveniment în cadrul acelui control. Întrucât o metodă poate fi invocată pe parcursul diferitelor etape ale ciclului de viaţă, expresiile de tip metodă trebuie să fie întotdeauna cu evaluare leneşă.

<my:tag id="myTagId" action="#{myObject.myValue}" />
<my:tag id="myTagId" action="#{myObject['myValue']}" />

Expresiile de tip metodă trebuie folosite întotdeauna numai în cadrul unei etichete, fie folosind o singură expresie care este evaluată şi transmisă modulului de gestiune a etichetei, putând fi invocată mai târziu sau folosind doar text. La execuţia metodei asociată expresiei în cauză, se întoarce un rezultat de tip String care este convertit la tipul aşteptat, aşa cum este definit de descriptorul bibliotecii de etichete.

Expresiile de tip metodă pot fi utilizate pentru a invoca funcţii care primesc un set de parametrii (0 sau mai mulţi, separaţi prin virgulă). Se pot folosi atât operatorul . cât şi [], comportamentul acestora fiind similar:

myObject["myMethod"](myparameters)
myObject.myMethod(myParameters)

În Expression Language pot fi folosite şi expresii lambda, acestea fiind expresii de tip valoare ce primesc parametrii. Utilizarea acestora este comparabilă cu cazul limbajului de programare Java, cu excepţia faptului că şi corpul expresiei lambda este tot o expresie EL. O expresie lambda foloseşte operatorul , identificatorii din stânga expresiei fiind parametrii lambda, în dreapta expresiei aflându-se o expresie EL. De obicei, se folosesc parantezele () pentru a include parametrii lambda, acestea putând fi omise dacă există un singur parametru.

O expresie lambda are un comportament asemănător cu al unei funcţii, aceasta putând fi apelată imediat sau valoarea ei poate fi asociată unei variabile ce va fi utilizată ulterior pentru invocarea metodei respective primind parametrii care vor fi disponibili la momentul respectiv.

O expresie lambda poate fi transmisă ca argument al unei metode, fiind executată în cadrul metodei respective sau poate fi inclusă la rândul ei, în altă expresie lamda.

() -> null
(x,y) -> (x+y)/2
((x,y) -> Math.sqrt(x*y))(4,9)
distance = (x1,y1,x2,y2) -> Math.sqrt(Math.sqr(x1-x2)+Math.sqr(y1-y2));
distance(1,1,2,2)

O expresie literală este evaluată la textul expresiei, care are tipul String, fiind utilizată atunci când este necesară folosirea sintaxei rezervate ${} sau #{}. Dacă se doreşte folosirea şirului de caractere ${expression} se pot folosi alternativele ${'${'}expression sau \${expression} (idem şi pentru expresii #{}). O expresie literală nu foloseşte delimitatorii ${} sau #{}.

Expresiile literale pot fi cu evaluare imediată sau cu evaluare leneşă şi pot fi atât expresii de tip valoare cât şi expresii de tip metodă. Momentul la care este evaluată o expresie depinde de contextul în care aceasta este utilizată.

În EL sunt suportate operaţii pe colecţii cum ar fi:

  • mulţimi
    {1, 2, ..., n}
  • liste – acestea pot conţine elemente având tipuri diferite
    {1, two, "3", ...}
  • obiecte de tip map
    {"one":1, "two":2, ..., "n":n}

Prin Expression Language, se permite crearea dinamică a acestora, exploatarea lor implicând utilizarea unor obiecte de tip flux, respectiv benzi de asamblare (eng. pipeline). Astfel, metodele vor fi apelate pe fluxul de elemente obţinut din colecţia respectivă folosind metoda stream(). Întrucât unele metode întorc tot un flux de elemente, acestea pot fi înlănţuite împreună în cadrul unei benzi de asamblare . Operaţiile realizate pe fluxul de elemente nu modifică colecţia originală.

Metoda stream() obţine un obiect Stream pornind de la un obiect java.util.Collection sau un vector Java.
O bandă de asamblare constă dintr-o sursă (obiect de tip Stream), orice număr de operaţii intermediare care întorc un flux (spre exemplu, filter() şi map()) şi o operaţie terminală care nu întoarce un flux (spre exemplu, toList()).
collection.stream().filter(a->a.attribute1=='value1')
                   .map(a->a.attribute2)
                   .sorted()
                   .toList()

Operaţiile suportate de fluxul de elemente sunt: allMatch(), anyMatch(), average(), count(), distinct(), filter(), findFirst(), flatMap(), forEach(), iterator(), limit(), map(), max(), min(), noneMatch(), peek(), reduce(), sorted(), substream(), sum(), toArray(), toList().

În afară de operatorii . şi [], Expression Language pune la dispoziţia programatorilor şi alţi operatori, ce pot fi folosiţi doar în expresii de tip rvalue:

Categorie Operator Operator Precedenţă Observaţii
. [] 1
() folosit pentru a schimba precedenţa operatorilor
aritmetici - (unar) 2
logici not ! 2
empty empty 2 utilizat pentru a verifica dacă o valoare este null sau vidă
aritmetici * / div % mod 3
+ - (binar) 4
concatenare şiruri de caractere += 5
relaţionali <> < <= > >= lt le gt ge 6 comparaţia se poate face cu alte valori sau literali
== != eq ne 7
logici && and 8
|| or 9
condiţionali ? : 10 X ? Y : Z
lambda 11
atribuire = 12
; 13

În Expression Language există şi termeni rezervaţi, care nu pot fi utilizaţi ca identificatori: and, or, not, eq, ne, lt, gt, le, ge, true, false, null, instanceof, empty, div, mod.

Există posibilitatea ca expresiile EL să nu fie evaluate în cazul în care atributul isELIgnored al directivei page are valoarea true (implicit, valoarea sa este false, deci în mod obişnuit, expresiile EL vor fi evaluate într-o pagină JSP).

Utilizarea JSTL (JavaServer Pages Standard Tag Library) pentru implementarea unor funcţionalităţi complexe

JSTL (JavaServer Pages Standard Tag Library) este o colecţie de etichete JSP, care implementează funcţionalitatea de bază specifică pentru numeroase aplicaţii JSP.

Etichetele JSTL pot fi clasificate, în funcţie de comportamentul pe care îl oferă utilizatorilor în mai multe grupuri:

  1. etichete JSTL de bază;
  2. etichete JSTL pentru formatare;
  3. etichete JSTL destinate gestiunii informaţiilor dintr-o bază de date SQL;
  4. etichete JSTL pentru gestiunea documentelor XML;
  5. funcţii JSTL.

Pentru ca aceste funcţionalităţi să fie accesibile în pagina JSP a unei aplicaţii web, biblioteca JSTL trebuie plasată în directorul WEB-INF\lib corespunzător acesteia.

Etichete JSTL de bază

Etichetele JSTL de bază sunt cele mai frecvent utilizate, implementând funcţionalitate legată de controlul fluxului.

Pentru a putea referi aceste etichete, trebuie specificată locaţia de unde acestea pot fi încărcate.

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

Cele mai frecvent utilizate etichete JSTL de bază sunt:

<c:out> evaluează valoarea unei expresii pe care o afişează
Atributele asociate etichetei sunt:
value (obligatoriu) – informaţia care trebuie evaluată;
default – informaţie asociată în cazul în care evaluarea eşuează;
escapeXml – utilizată pentru a ignora caractere XML speciale.
<c:out value="${myObject.myAttribute}" />
<c:set> asociază rezultatul evaluării unei expresii la o variabilă, disponibilă pentru un anumit domeniu de vizibilitate.

Atributele asociate etichetei sunt:
value – informaţia care trebuie evaluată şi asociată obiectului;
target – denumirea obiectului a cărui proprietate trebuie stabilită;
property – proprietate a obiectului target a cărui valoare va fi stabilită la valoarea indicată (trebuie specificat dacă se foloseşte target);
var – denumirea variabilei care va stoca informaţia;
scope – scopul variabilei care va stoca informaţia.
<c:set value="${expression}" target="myObject" property="myAttribute" scope="page" />
<c:set value="${expression}" var="myVariabile" scope="application" />
<c:remove> disociază o variabilă de contextul unui anumit domeniu de vizibilitate

Atributele asociate etichetei sunt:
var (obligatoriu) – denumirea variabilei care va fi eliminată;
scope – scopul variabilei care va fi eliminată.
<c:remove var="myVariable" scope="application" />
<c:catch> gestionează orice obiect de tip Throwable întâlnit în corpul său, eventual expunându-l utilizatorului

Atributul asociat etichetei este var ce indică denumirea variabilei care va stoca excepţia generată, în cazul în care va fi produsă de instrucţiunile din corpul său
<c:catch var="${exception}"> 
  <% some expression(s) that may potentially throw an error %>
</c:catch>
<c:out value="exception: ${exception.message}" />
<c:if> etichetă de tip condiţional, al cărui corp este evaluat în cazul când condiţia asociată este îndeplinită

Atributele asociate etichetei sunt:
test (obligatoriu) – condiţia care se doreşte a fi evaluată;
var – denumirea variabilei care va stoca rezultatul condiţiei;
scope – scopul variabilei care va stoca rezultatul condiţiei.
<c:if test="${expression}" />
  <% do some operations %>
</c:if>
<c:choose> etichetă de tip condiţional, indicând condiţii ce se exclud mutual, specificate prin <when> şi <otherwise>; funcţionează ca instrucţiunea switch din Java, permiţând alegerea dintre mai multe alternative: ramurile case sunt specificate prin <when> în timp ce ramura default este specificată prin <otherwise>.

Eticheta nu are atribute.
<c:choose>
  <c:when test="${expression1}"><% do some operations %></c:when>
  <c:when test="${expression2}"><% do some operations %></c:when>
  ...
  <c:when test="${expressionn}"> 
    <% do some operations %>
  </c:when>
  <c:otherwise><% do some other operations %></c:otherwise>
</c:choose />
<c:when> subetichetă a <choose>, al cărui corp este evaluat în cazul când condiţia asociată este îndeplinită
Atributul asociat etichetei este test ce indică condiţia care se doreşte a fi evaluată.
<c:otherwise> subetichetă a <choose>, ce urmează uneia sau mai multor etichete <when>, determinând evaluarea corpului său, dacă nici una dintre condiţiile care o preced nu este îndeplinită.

Eticheta nu are atribute.
<c:import> primeşte un URL relativ sau absolut şi expune conţinutul său întregii pagini, unui şir de caractere specificat în atributul var sau unui obiect Reader specificat în atributul varReader.
Atributele asociate etichetei sunt:
url (obligatoriu) – URL-ul ce trebuie obţinut şi inclus în pagină;
context – caracterul / urmat de numele aplicaţiei web;
charEncoding – setul de caractere utilizat pentru datele preluate;
var – denumirea variabilei utilizată pentru a stoca textul preluat;
scope – domeniul de vizibilitate al variabilei utilizată pentru a stoca textul preluat;
varReader – denumirea unei variabile alternative pentru a expune conţinutul sub forma unui obiect java.io.Reader;
<c:import var="myVariabile" url="http://www.mysite.com" />
<c:forEach> etichetă de tip iteraţie, acceptând mai multe tipuri de colecţii, suportând parcurgerea submulţimilor; este o alternativă pentru instrucţiunile de iterare for, while şi do-while din cadrul Java, care pot fi utilizate în cadrul unui scriplet

Atributele asociate etichetei sunt:
items – informaţia (colecţia) pe care se realizează iteraţia;
begin – elementul colecţiei de la care se începe iteraţia;
end – elementul colecţiei la care se termină iteraţia;
step – pasul cu care se parcurg elementele colecţiei;
var – denumirea variabilei care expune elementul curent;
varStatus – denumirea variabilei care expune statutul iteraţiei;
<c:forEach var="myVariabile" items="${myCollection}">
  <c:out value="${myVariabile}" /><br />
</c:forEach>
<c:forTokens> iterează asupra unor particule, separate prin delimitatori

Suportă aceleaşi atribute ca şi <foreach>, la care se adaugă delim, care indică caracterele utilizate ca delimitatori
<c:forTokens var="myVariabile" items="${myString}" delim=",">
  <c:out value="${myVariabile}" /><br />
</c:forTokens>
<c:param> adaugă un parametru la URL-ul specificat în cadrul unei etichete <import>, realizând şi codificarea acestuia

Atributele asociate etichetei sunt:
name – denumirea parametrului care va fi inclus în URL;
value – valoarea parametrului care va fi inclus în URL;
<c:import var="myVariabile" url="http://www.mysite.com">
  <c:param name="param1Name" value="param1Value" />
  <c:param name="param2Name" value="param2Value" />
  ...
  <c:param name="paramnName" value="paramnValue" />
</c:import>
<c:redirect> redirectează controlul la un alt URL, realizând suprascrierea sa în browser; suportă URL-uri relative la context şi eticheta <param>

Atributele asociate etichetei sunt:
url (obligatoriu) – URL-ul la care se realizează redirectarea controlului;
context – caracterul / urmat de numele aplicaţiei web.
<c:redirect url="http://www.mysite.com">
<c:url> creează un URL cu parametrii de interogare opţionali, stocând valoarea acestuia într-o variabilă şi realizând rescrierea URL-ului dacă este necesar; este o alternativă la invocarea metodei response.encodeURL(), suportând şi eticheta <param>

Atributele asociate etichetei sunt:
value (obligatoriu) – URL-ul de bază;
context – caracterul / urmat de numele aplicaţiei web;
var – denumirea variabilei ce reţine URL-ul procesat;
scope – domeniul de vizibilitate al variabilei ce reţine URL-ul procesat;
<c:url value="http://www.mysite.com" />

Etichete JSTL pentru formatare

Etichetele JSTL pentru formatare sunt utilizate pentru a formata şi afişa text, informaţii cu privire la dată calendaristică şi timp, numere precum şi site-uri Internet într-un format localizat.

Pentru a putea referi aceste etichete, trebuie specificată locaţia de unde acestea pot fi încărcate.

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

Cele mai frecvent utilizate etichete JSTL pentru formatare sunt:

<fmt:formatNumber> utilizat pentru redarea unei valori numerice cu o anumită precizie sau format

Atributele asociate etichetei sunt:
value (obligatoriu) – valoarea numerică ce se doreşte afişată;
type – poate lua valorile NUMBER, CURRENCY, PERCENT;
pattern – modelul de formatare pentru valoarea numerică ce se doreşte afişată; se folosesc codurile:
o 0 – reprezintă o cifră;
o E – reprezintă o formă exponenţială;
o # – reprezintă o cifră; se afişează 0 dacă lipseşte;
o . – separator pentru valorile zecimale;
o , – separator pentru grupurile reprezentând miile;
o ; – separator pentru formate;
o - – prefix pentru valori negative;
o % – afişează procentajul;
o ? – afişează miimile;
o * – înlocuit de simbolul valutei curente;
o X – indică faptul că orice alt caracter poate fi folosit ca prefix sau sufix;
o ' – utilizat pentru a cita caractere speciale în prefix sau sufix.
currencyCode – codul valutei (pentru tipul CURRENCY), preluat din localizarea curentă;
currencySymbol – simbolul valutei (pentru tipul CURRENCY), preluat din localizarea curentă;
groupingUsed – dacă se folosesc grupuri de numere; se foloseşte pentru a introduce , între grupurile care reprezintă miile;
maxIntegerDigits – numărul maxim de cifre întregi care pot fi afişate; dacă valoarea este depăşită, atunci rezultatul se trunchează;
minIntegerDigits – numărul minim de cifre întregi care pot fi afişate;
maxFractionDigits – numărul maxim de zecimale care pot fi afişate; dacă valoarea este depăşită, atunci rezultatul se rotunjeşte;
minFractionDigits – numărul minim de zecimale care pot fi afişate;
var – denumirea variabilei care reţine valoarea formatată;
scope – domeniul de vizibilitate al variabilei care reţine valoarea formatată.
<fmt:parseNumber> parsează reprezentarea sub formă de şir de caractere pentru o valoare numerică, o valută sau un procentaj

Atributele asociate etichetei sunt:
value – valoarea numerică ce se doreşte a fi parsată;
type – poate lua valorile NUMBER, CURRENCY, PERCENT;
parseLocale – localizarea folosită la parsarea numărului;
integerOnly – indică parsarea de valori întregi sau reale;
pattern – modelul de parsare;
timeZone – zona de timp a datei calendaristice parsate;
var – denumirea variabilei care reţine valoarea parsată;
scope – domeniul de vizibilitate al variabilei care reţine valoarea parsată.
<fmt:formatDate> utilizat pentru formatarea unei date calendaristice / timp folosind stilurile şi modelele oferite

Atributele asociate etichetei sunt:
value (obligatoriu) – data calendaristică de afişat;
type – poate lua valorile DATE, TIME, BOTH;
dateSytle – poate lua valorile FULL, LONG, MEDIUM, SHORT, DEFAULT;
timeStyle – poate lua valorile FULL, LONG, MEDIUM, SHORT, DEFAULT;
pattern – modelul de formatare pentru valoarea de tip dată calendaristică / timp ce se doreşte afişată; se folosesc codurile:
o G – era;
o y – anul;
o M – luna;
o d – ziua din lună;
o h – ora (format 12 ore);
o H – ora (format 24 ore);
o m – minutul;
o s – secunda;
o S – milisecunda;
o E – ziua din săptămână;
o D – ziua din an;
o F – ziua din săptămână în cadrul lunii;
o w – săptămâna din an;
o W – săptămâna din lună;
o a – indicatorul AM / PM;
o k – ora (format 12 ore);
o K – ora (format 24 ore);
o z – zona de timp;
o ' – caracter escape pentru informaţii de tip text;
o – utilizat pentru citări;
timeZone – zona de timp a datei calendaristice afişate;
var – denumirea variabilei care reţine valoarea formatată;
scope – domeniul de vizibilitate al variabilei care reţine valoarea formatată.
<fmt:parseDate> parsează reprezentarea sub formă de şir de caractere pentru o valoare de tip dată calendaristică / timp

Are aceleaşi atribute ca <formatDate> la care se adaugă parseLocale, indicând localizarea care trebuie utilizată atunci când se parsează informaţia de tip dată calendaristică.
<fmt:bundle> încarcă o resursă ce urmează să fie utilizată în corpul său, de eticheta <message>

Atributele asociate etichetei sunt:
basename (obligatoriu) – specifică numele de bază pentru resursa care se doreşte a fi încărcată;
prefix – valoarea care va preceda fiecare denumire de cheie în subeticheta <message>.
<fmt:bundle basename="myBaseName">
  <fmt:message key="myPrefix.myKey" />
</fmt:bundle>
echivalent cu
<fmt:bundle basename="myBaseName" prefix="myPrefix">
  <fmt:message key="myKey" />
</fmt:bundle>
<fmt:setLocale> stochează localizarea dată în variabila de configurare referitoare la localizare

Atributele asociate etichetei sunt:
value (obligatoriu) – specifică un cod format din două părţi indicând codul de limbă (ISO-639) şi codul de ţară (ISO-3166);
variant – variantă specifică browser-ului;
scope – domeniul de vizibilitate al variabilei de configurare referitoare la localizare.
<fmt:setBundle> încarcă o resursă pe care o stochează într-o variabilă având un domeniu de vizibilitate, respectiv în variabila de configurare referitoare la resurse

Atributele asociate etichetei sunt:
basename (obligatoriu) – specifică numele de bază pentru familia de resurse pentru a fi expusă ca o variabilă având un anumit domeniu de vizibilitate, respectiv ca o variabilă de configurare;
var – denumirea variabilei care reţine valoarea resursei;
scope – domeniul de vizibilitate al variabilei care reţine valoarea resursei.
<fmt:timeZone> specifică zona de timp pentru orice tip de acţiune vizând formatarea sau parsarea din corpul său.

Atributul asociat etichetei este value ce indică zona de timp care va fi aplicată corpului său.
<fmt:setTimeZone> stochează zona de timp dată în variabila de configurare referitoare la zona de timp

Atributele asociate etichetei sunt:
value (obligatoriu) – zona de timp care va fi expusă ca o variabilă având un anumit domeniu de vizibilitate, respectiv ca o variabilă de configurare;
var – denumirea variabilei care reţine zona de timp;
scope – domeniul de vizibilitate al variabilei care reţine zona de timp.
<fmt:message> afişează un mesaj folosind un format localizat

Atributele asociate etichetei sunt:
key – cheia mesajului care se doreşte a fi obţinut;
bundle – identificatorul resursei care se doreşte a fi folosit;
var – denumirea variabilei care reţine valoarea mesajului localizat;
scope – domeniul de vizibilitate al variabilei care reţine valoarea mesajului localizat.
<fmt:requestEncoding> stabileşte mecanismul de configurare al caracterelor pentru cerere
Atributul asociat etichetei este key prin care se indică mecanismul de configurare al caracterelor care va fi aplicat la decodificarea parametrilor din obiectul request.

Etichete JSTL pentru gestiunea informațiilor dintr-o bază de date

Etichetele JSTL pentru gestiunea informaţiilor într-o bază de date SQL oferă funcţionalitatea pentru interacţiunea cu baze de date relaţionale ca Oracle, MySQL sau Microsoft SQL Server.

Pentru a putea referi aceste etichete, trebuie specificată locaţia de unde acestea pot fi încărcate.

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

Cele mai frecvent utilizate etichete JSTL pentru gestiunea informaţiilor dintr-o bază de date sunt:

<sql:setDataSource> creează un obiect DataSource adecvat numai operaţiilor de prototipare

Atributele asociate etichetei sunt:
driver – numele clasei corespunzătoare “driver”-ului JDBC care trebuie înregistrată;
urlURL-ul pentru realizarea conexiunii la baza de date;
user – numele de utilizator folosit în mecanismul de autentificare pentru baza de date;
password – parola folosită în mecanismul de autentificare pentru baza de date;
dataSource – baza de date pregătită anterior;
var – denumirea variabilei care va reprezenta baza de date;
scope – domeniul de vizibilitate al variabile care va reprezenta baza de date.
<sql:setDataSource var="connection" url="${dataBaseConnection}" 
                   user="${dataBaseUser}" password="${dataBasePassword}" />
<sql:query> execută interogarea SQL de tip SELECT definită în cadrul corpului folosind atributul sql, reţinând rezultatul într-o variabilă având un anumit domeniu de vizibilitate

Atributele asociate etichetei sunt:
sql – comanda SQL care va fi executată (ar trebui să întoarcă un obiect de tip ResultSet);
dataSource – conexiunea la baza de date care va fi utilizată (suprascrie valoarea implicită);
maxRows – numărul maxim de rezultate care vor fi stocate în cadrul variabilei;
startRow – numărul înregistrării (din cadrul rezultatului) de la care va începe stocarea;
var – denumirea variabilei care va reține rezultatul;
scope – domeniul de vizibilitate al variabilei care va reține rezultatul.
<sql:query sql="${myQuery}" var="result" />
<sql:update> execută instrucţiunea SQL de actualizare a informaţiilor (de tip INSERT, UPDATE, DELETE) – care nu întoarce date, definită în cadrul corpului folosind atributul sql

Atributele asociate etichetei sunt:
sql – comanda SQL care va fi executată (ar trebui să NU întoarcă un obiect de tip ResultSet);
dataSource – conexiunea la baza de date care va fi utilizată (suprascrie valoarea implicită);
var – denumirea variabilei care va stoca numărul de înregistrări afectate de instrucţiune;
scope – domeniul de vizibilitate al variabilei care va stoca numărul de înregistrări afectate de instrucţiune.
<sql:update dataSource="${connection}" var="count">
  <%-- some INSERT, UPDATE or DELETE query -->
</sql:update>
<sql:param> stabileşte valoarea unui parametru al unei instrucţiuni SQL, fiind folosit de obicei împreună cu etichetele <query> sau <update>

Atributul asociat etichetei este value prin care se indică valoarea care se doreşte a fi asociată parametrului.
<sql:query dataSource="${connection}" var="result">
  SELECT FROM table WHERE attribute = ?
  <sql:param value="${missingTableAttributeValue}" />
</sql:query>
<sql:update dataSource="${connection}" var="count">
  <%-- some INSERT, UPDATE or DELETE query with one or more 
     missing attribute values -->
  <sql:param value="${missingTableAttributeValue}" />
</sql:update>
<sql:dateParam> stabileşte valoarea unui parametru al unei instrucţiuni SQL având tipul java.util.Date

Atributele asociate etichetei sunt:
value – valoarea parametrului având tipul java.util.Date, care trebuie stocat;
type – poate avea valorile DATE (doar date caledaristice), TIME (doar timp) sau TIMESTAMP (dată calendaristică şi timp).
Utilizarea sa este similară cu a etichete <param>.
<sql:transaction> oferă elemente care realizează acţiuni folosind un obiect Connection partajat, executate în cadrul unei tranzacţii; grupează interogări exprimate de etichetele <query> şi <update> într-o tranzacţie, asigurând că efectul acestora este fie unitar asupra bazei de date, menţinându-se starea sa iniţială în cazul producerii unei erori.

Atributele asociate etichetei sunt:
dataSource – conexiunea la baza de date care va fi utilizată (suprascrie valoarea implicită);
isolation – poate avea valorile READ_COMMITED, READ_UNCOMMMITTED, REPEATABLE_READ sau SERIALIZABLE.
<sql:transaction dataSource="${connection}">
  <sql:update var="count1">
    <%-- some INSERT queries -->
  </sql:update>
  <sql:update var="count2">
    <%-- some UPDATE queries -->
  </sql:update>
  <sql:update var="count3">
    <%-- some DELETE queries -->
  </sql:update>
</sql:transaction>

Etichete JSTL pentru gestiunea documentelor XML

Etichetele JSTL pentru gestiunea documentelor XML oferă posibilitatea de a manipula acest tip de resurse, implementând operaţii precum parsarea şi transformarea acestora precum şi controlul fluxului bazat pe expresii XPath.

Pentru a putea referi aceste etichete, trebuie specificată locaţia de unde acestea pot fi încărcate.

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

Cele mai frecvent utilizate etichete JSTL pentru gestiunea documentelor XML sunt:

<x:out> evaluează valoarea unei expresii XPath pe care o afişează

Atributele asociate etichetei sunt:
select (obligatoriu) – expresia XPath care trebuie evaluată, adeseori folosind variabile XPath;
escapeXml – indică dacă caracterele speciale XML ar trebui ignorate
<x:parse> utilizat pentru a parsa date XML specificate fie prin intermediul unui atribut, fie în corpul etichetei

Atributele asociate etichetei sunt:
var – variabila care conţine datele XML parsate;
xml – textul documentului care se doreşte a fi parsat (de tip String sau Reader);
systemIdURI-ul identificatorului de sistem pentru a parsa documentul;
filter – filtrul ce trebuie aplicat documentului sursă;
doc – documentul XML ce se doreşte a fi parsat;
scope – domeniul de vizibilitate al variabilei specificate de atributul var;
varDom – variabila care conţine datele XML parsate;
scopeDom – domeniul de vizibilitate al variabilei specificate de atributul varDom.
<x:parse xml="${myXmlDocument}" var="variable" />
<x:out select="$variable/root/element[index]/attribute" />
<x:set> atribuie unei variabile valoarea unei expresii XPath; în funcţie de tipul rezultat la evaluarea expresiei XPath, vor fi create obiecte având tipul java.lang.Boolean, java.lang.String, java.lang.Number.

Atributele asociate etichetei sunt:
var (obligatoriu) – variabila care va reţine valoarea expresiei XPath;
select – expresia XPath care se doreşte evaluată;
scope – domeniul de vizibilitate al variabilei specificate de atributul var.
<x:parse xml="${myXmlDocument}" var="variable1" />
<x:set var="variable2" select="$variable1/root/element" />
<x:if> evaluează o condiţie ce are forma unei expresii XPath şi dacă aceasta se verifică se procesează corpul etichetei

Atributele asociate etichetei sunt:
select (obligatoriu) – expresia XPath exprimând condiţia ce se doreşte evaluată;
var – variabila care va reţine rezultatul evaluării condiţiei;
scope – domeniul de vizibilitate al variabilei specificate de atributul var.
<x:parse xml="${myXmlDocument}" var="variable" />
<x:if select="$variable/root/element[index]/attribute != 0" />
  The attribute of the element at index is not null!
</x:if>
<x:forEach> iterează asupra nodurilor unui document XML

Atributele asociate etichetei sunt:
select (obligatoriu) – expresia XPath care va fi evaluată;
var – denumirea variabilei care va reţine valoarea elementului curent pentru fiecare iteraţie;
begin – indexul de început pentru iteraţie;
end – indexul de sfârşit pentru iteraţie;
step – valoarea cu care va fi incrementat indexul pe parcursul incrementării colecţiei;
varStatus – denumirea variabilei în care se va reţine statutul iteraţiei
<x:parse xml="${myXmlDocument}" var="variable" />
<x:forEach select="$variable/root/element/attribute" var="item" />
  <x:out select="$item" />
</x:forEach>
<x:choose> etichetă de tip condiţional care stabileşte un context pentru operaţii condiţionale care se exclud mutual, marcate prin <when> şi <otherwise>

Eticheta nu are atribute.
<x:parse xml="${myXmlDocument}" var="variable" />
<x:choose>
  <x:when select="$variable//element/attribute eq value1">
    Attribute has value 1!
  </x:when>
  <x:when select="$variable//element/attribute eq value2">
    Attribute has value 2!
  </x:when>
  ...
  <x:when select="$variable//element/attribute eq valuen">
    Attribute has value n!
  </x:when>
  <x:otherwise>
    Attribute has unknown value!
  </x:otherwise>
</x:choose>
<x:when> subetichetă a etichetei <choose> al cărei corp este inclus dacă se verifică condiţia asociată.

Eticheta are un singur atribut, select, care conţine condiţia ce se doreşte a fi evaluată.
<x:otherwise> subetichetă a etichetei <choose> ce urmează uneia sau mai multor etichete <when>, determinând evaluarea corpului său, dacă nici una dintre condiţiile care o preced nu este îndeplinită.

Eticheta nu are atribute.
<x:transform> se aplică la transformare XSL a unui document XML

Atributele asociate etichetei sunt:
doc – documentul XML sursă pentru transformarea XSLT;
docSystemIdURI-ul documentului XML original;
xslt (obligatoriu) – foaia de stil XSLT care conţine instrucţiunile pentru transformare;
xsltSystemIdURI-ul documentului XSLT original;
result – obiectul rezultat care va accepta rezultatul transformării;
var – denumirea variabilei în care se va reţine rezultatul transformării
scope – domeniul de vizibilitate ce va expune rezultatul transformării.
<x:parse xml="${myXmlDocument}" var="variable" />
<c:import url="http://www.mysite.com/document.xsl" var="xslt" />
<x:transform doc="${variable}" xslt="${xslt}" />
<x:param> utilizat împreună cu eticheta de transformare pentru a stabili un parametru în foaia de stil XSLT

Atributele asociate etichetei sunt:
name – denumirea parametrului XSLT ce se doreşte a fi stabilit;
value – valoarea parametrului XSLT ce se doreşte a fi stabilit.
<x:transform doc="${variable}" xslt="${xslt}" />
  <x:param name="attributeName" value="attributeValue" />
</x:transform>

Funcții JSTL

Expresion Language permite folosirea de funcţii în cadrul expresiilor, acestea trebuind să fie definite în cadrul unor biblioteci de etichete predefinite, apelul său făcându-se folosind sintaxa:

${ns:function(param1, param2, ..., paramn)}

JSTL include un număr de funcţii standard, dintre care numeroase implică manipularea şirurilor de caractere. Pentru a putea referi aceste etichete, trebuie specificată locaţia de unde acestea pot fi încărcate.

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

Lista de funcţii standard JSTL este redată în continuare:

fn:contains() verifică dacă şirul de caractere conţine un alt subşir; primeşte doi parametrii de tip java.lang.String având semnificaţia şirului de caractere, respectiv a subşirului; rezultatul întors este de tip boolean.
<c:set var="variable" value="${fn:contains(stringToBeSearched, substringToSearch)}" />
fn:containsIgnoreCase() verifică dacă şirul de caractere conţine un alt subşir, ignorând capitalizarea; primeşte doi parametrii de tip java.lang.String având semnificaţia şirului de caractere, respectiv a subşirului; rezultatul întors este de tip boolean.
<c:set var="variable" value="${fn:containsIgnoreCase(stringToBeSearched, substringToSearch)}" />
fn:endsWith() verifică dacă şirul de caractere are un anumit sufix; primeşte doi parametrii de tip java.lang.String având semnificaţia şirului de caractere, respectiv a sufixului; rezultatul întors este de tip boolean.
<c:set var="variable" value="${fn:endsWith(stringToBeSearched, sufix)}" />
fn:escapeXml() transformă caracterele care ar putea fi interpretate ca adnotări XML la valoarea corespunzătoare; primeşte un parametru de tip java.lang.String având semnificaţia şirului de caractere care se doreşte a fi transformat; rezultatul întors este de tip java.lang.String.
<c:set var="variable" value="${fn:escapeXml(stringToBeXmlEscaped)}" />
fn:indexOf() întoarce prima apariţie a unui subşir specificat în cadrul şirului de caractere; primeşte doi parametrii de tip java.lang.String având semnificaţia şirului de caractere în care se realizează căutarea, respectiv a şirului care este căutat; rezultatul întors este de tip int (dacă şirul nu este găsit se întoarce valoarea -1)
<c:set var="variable" value="${fn:indexOf(stringToBeSearched, substringToSearch)}" />
fn:join() concatenează toate elementele unui vector într-un singur şir de caractere; primeşte doi parametrii, unul de tip java.lang.String[] conţinând elementele vectorului şi unul de tip java.lang.String, reprezentând separatorul; întoarce un rezultat de tip java.lang.String
<c:set var="variable" value="${fn:join(arrayToBeJoined, separator)}" />
fn:length() întoarce numărul de elemente al colecţiei sau dimensiunea şirului de caractere; primeşte un parametru de tip java.lang.Object (de tip colecţie sau şir de caractere); întoarce un rezultat de tip int.
<c:set var="variable1" value="${fn:length(myList)}" />
<c:set var="variable2" value="${fn:length(myString)}" />
fn:replace() întoarce un şir de caractere obţinut prin înlocuirea unei secvenţe din cadrul său cu o altă secvenţă; primeşte trei parametrii de tip java.lang.String, reprezentând şirul de caractere în care se realizează înlocuirea, secvenţa care se doreşte înlocuită şi valoarea cu care aceasta este înlocuită; întoarce un rezultat de tip boolean
<c:set var="variable" value="${fn:length(myString, sequenceToReplace, sequenceToReplaceWith)}" />
fn:split() împarte şirul de caractere într-un vector de subşiruri primeşte doi parametrii de tip java.lang.String, reprezentând şirul de caractere care va fi împărţit, respectiv delimitatorii pe baza cărora se va realiza această operaţie; întoarce un rezultat de tip java.lang.String[].
<c:set var="variable" value="${fn:split(myString, delimiter)}" />
fn:startsWith() verifică dacă şirul de caractere are un anumit prefix; primeşte doi parametrii de tip java.lang.String având semnificaţia şirului de caractere, respectiv a prefixului; rezultatul întors este de tip boolean.
<c:set var="variable" value="${fn:startsWith(stringToBeSearched, prefix)}" />
fn:substring() întoarce un subşir al şirului de caractere; primeşte un parametru de tip java.lang.String reprezentând şirul din care se determină subşirul şi doi parametrii de tip int reprezentând poziţiile de început şi de sfârşit; rezultatul întors este de tip java.lang.String.
<c:set var="variable" value="${fn:substring(myString, startIndex, endIndex)}" />
fn:substringAfter() întoarce un subşir al şirului de caractere ce succede unei anumite secvenţe; primeşte doi parametrii de tip java.lang.String având semnificaţia şirului de caractere din care se determină subşirul, respectiv secvenţa după care urmează subşirul respectiv; rezultatul întors este de tip java.lang.String.
<c:set var="variable" value="${fn:substringAfter(myString, subSequence)}" />
fn:substringBefore() întoarce un subşir al şirului de caractere ce precede o anumită secvenţă; primeşte doi parametrii de tip java.lang.String având semnificaţia şirului de caractere din care se determină subşirul, respectiv secvenţa înainte de care se găseşte subşirul respectiv; rezultatul întors este de tip java.lang.String.
<c:set var="variable" value="${fn:substringBefore(myString, subSequence)}" />
fn:toLowerCase() transformă toate caracterele şirului în minuscule; primeşte un caracter de tip java.lang.String reprezentând şirul de caractere ce se doreşte a fi transformat; rezultatul întors este de tip java.lang.String
<c:set var="variable" value="${fn:toLowerCase(myString)}" />
fn:toUpperCase() transformă toate caracterele şirului în majuscule; primeşte un caracter de tip java.lang.String reprezentând şirul de caractere ce se doreşte a fi transformat; rezultatul întors este de tip java.lang.String
<c:set var="variable" value="${fn:toUpperCase(myString)}" />
fn:trim() elimină spaţiile care se găsesc la începutul şi sfârşitul şirului de caractere; primeşte un caracter de tip java.lang.String reprezentând şirul de caractere care se doreşte a fi transformat; rezultatul întors este de tip java.lang.String
<c:set var="variable" value="${fn:trim(myString)}" />

Etichete definite de utilizator

În JavaServer Pages pot fi implementate etichete definite de utilizator, care în momentul transformării servlet-ului corespunzător sunt convertite în operaţiile specificate de clasa care îi este asociată, pentru ca atunci când se accesează pagina respectivă, acestea să fie executate. O clasă care defineşte funcţionalitatea unei anumite etichete trebuie să fie derivată din javax.servlet.jsp.tagtext.SimpleTagSupport, implementând metoda doTag(). Aceasta poate accesa obiectele din cadrul paginii JSP prin intermediul metodei getJSPContext(). De asemenea, în cazul în care în corpul etichetei se specifică anumită valoare, aceasta poate fi obţinută într-un obiect de tip StringWriter prin metoda getJspBody().invoke().

CustomTag.java
import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
 
public class CustomTag extends SimpleTagSupport {
 
  private String customAttribute;
  public void setCustomAttribute(String customAttribute) {
    this. customAttribute = customAttribute;
  }
  public String getCustomAttribute() {
    return customAttribute;
  }
 
  StringWriter stringWriter = new StringWriter();
  public void doTag() throws JspException, IOException {
    if (customAttribute != null) {
      // process tag attribute
      getJspContext().getOut().println(customAttribute);
    } else {
      // get the content from the tag body
      getJspBody().invoke(stringWriter);
      // process tag body’s content
      getJspContext().getOut().println(stringWriter.toString());
    }
  }
 
}

Clasa asociată etichetei definite de utilizator va trebui plasată la o locaţie vizibilă prin variabila de mediu CLASSPATH.

Asocierea dintre etichetă şi clasa asociată se face într-un fişier custom.tld care va fi plasat în webapps/root/WEB-INF al serverului web Apache Tomcat 8.x. Astfel, se va specifica numele etichetei (aşa cum va fi specificat în pagina JSP – elementul <name>, denumirea clasei care îi implementează funcţionalitatea (elementul <tag-class>) precum şi tipul de conţinut al corpului etichetei (elementul <body-content>, având ca valori posibile empty, dacă trebuie să fie vid, scriptless dacă este acceptat numai text static, expresii EL sau alte etichete şi tagdependent în cazul în care conţinutul este scris în alt limbaj, fiind interpretat de implementarea etichetei). De asemenea, pentru fiecare atribut trebuie indicate proprietăţile name (identificator unic al atributului în cadrul etichetei), required (care distinge între atributele obligatorii şi cele opţionale), rtexprvalue (care stabileşte validitatea valorii unei expresii definită în momentul rulării pentru atributul etichetei), type (care specifică tipul Java al atributului respectiv, implicit fiind java.lang.String), description şi fragment (care indică dacă valoarea asociată atributului va fi tratată ca un JspFragment).

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>A short description of my custom tag</short-name>
  <tag>
    <name>CustomTag</name>
    <tag-class>mypackage.CustomTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
      <name>customAttribute</name>
      <required>true</true>
      <type>java.lang.Integer</type>
      <fragment>false</fragment>
    </attribute>
  </tag>
</taglib>

Pentru a putea fi folosită în cadrul unei pagini JSP, eticheta definită de utilizator trebuie declarată în acelaşi mod în care se procedează şi cu etichetele standard JSTL:

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

În momentul în care este utilizată, eticheta va avea numele definit în fişierul custom.tld, fiind prefixată cu denumirea indicată la declararea ei, precizând valori pentru toate atributele care au proprietatea required:

...
<customPrefix:CustomTag customAttribute="0">
  Some custom tag body
</customPrefix:CustomTag>
...

Potrivit implementării clasei asociate etichetei, efectul utilizării sale va fi afişarea valorii atributului specificat, în situaţia în care nu se decide realizarea altor tipuri de procesări asupra ei.

Se pot defini mai multe biblioteci de etichete definite de utilizator, grupate în funcţie de tipul de funcţionalitate pe care o pun la dispoziţia programatorilor, fiecare dintre acestea regăsindu-se într-un alt fişier şi utilizându-se un prefix diferit.

Activitate de Laborator

Structura aplicației web BookStore

Se doreşte implementarea unei interfeţe grafice cu utilizatorul (dezvoltată sub forma unei aplicaţii web, folosind serverul Apache Tomcat 8.x) pentru gestiunea informaţiilor reţinute într-o bază de date, aceasta urmând a fi utilizată de un sistem ERP destinat unei librării care comercializează doar cărţi.

Sistemul informatic va putea fi accesat de:

  • un utilizator tip administrator, care va manipula – prin intermediul aplicaţiei – informaţiile din baza de date; acesta are la dispoziție operații de adăugare, editare și ștergere pentru oricare dintre tabele;
  • un utilizator tip client, care va formula o comandă după ce şi-a specificat un anumit coş de cumpărături ca urmare a consultării catalogului de produse; pe baza comenzii va fi emisă o factură (invoice_header), caracterizată printr-un număr de identificare (identification_number), data la care a fost emisă (issue_date), stare (state) și identificatorul utilizatorului către care va fi transmisă (user_id); aceasta conține la rândul ei mai multe înregistrări, corespunzătoare cărților care au fost cumpărate (invoice_line), definite de factura corespunzătoare (invoice_header_id), identificatorul formatului de prezentare al cărții (book_presentation_id) și cantitatea (quantity).

Pentru fiecare funcționalitate există o pagină dedicată, gestionată de câte o clasă Java Servlet și de o pagină .jsp: pagina de autentificare (LoginServlet / login.jsp) de unde, în funcţie de rolul utilizatorului se trece la pagina de tip administrator (AdministratorServlet / administrator.jsp) respectiv pagina de tip client (ClientServlet / client.jsp). Pentru fiecare pagină, cererea primită din navigator este preluată de clasa servlet corespunzătoare, unde sunt realizate procesările ce țin de logica aplicației, inclusiv accesarea informațiilor din baza de date. Prezentarea informațiilor astfel obținute este delegată către pagina .jsp, către care se transferă contextul. Datele care se doresc a fi vizualizate sunt transmise dinspre servlet către pagina JSP sub formă de atribute. În acest mod se construiește răspunsul care va fi trimis către navigator.

Structura aplicaţiei BookStore

Atributele care sunt transmise între clasele servlet și paginile .jsp sunt:

  1. LoginServlet → login.jsp
    • Constants.ERROR_ATTRIBUTE - furnizează informații cu privire la rezultatul operației de autentificare a unui utilizator în cadrul aplicației web (succes, eșec);
  2. AdministratorServlet → administrator.jsp
    • Constants.DISPLAY - identificatorul utilizatorului autentificat în cadrul aplicației web (format din prenume și nume);
    • Constants.DATABASE_STRUCTURE - structura bazei de date, formată din lista tuturor tabelelor;
    • Constants.CURRENT_TABLE - denumirea tabelei vizualizată la un moment dat de timp;
    • Constants.ATTRIBUTES - structura tabelei vizualizată la un moment dat de timp, conținând lista tuturor atributelor;
    • Constants.IDENTIFIER - denumirea identificatorului în lista de atribute;
    • Constants.IDENTIFIER_INDEX - poziția identificatorului în lista de atribute;
    • Constants.IDENTIFIER_NEXT_VALUE - valoarea identificatorului unei înregistrări pentru adăugare;
    • Constants.TABLE_CONTENT - conținutul tabelei vizualizate la un moment dat de timp, conținând lista tuturor înregistrărilor, pentru fiecare înregistrare fiind reținute valorile tuturor atributelor;
    • Constants.IDENTIFIER_VALUE_OF_RECORD_TO_BE_UPDATED - valoarea identificatorului unei înregistrări selectate pentru modificare sau ștergere, în situația în care aceasta a fost selectată;
  3. ClientServlet → client.jsp
    • Constants.DISPLAY - identificatorul utilizatorului autentificat în cadrul aplicației web (format din prenume și nume);
    • Constants.BOOKS - lista cărților care vor fi vizualizate, împreună cu toate atributele, în funcție de criteriile de filtrare care au fost precizate;
    • Constants.ERROR_MESSAGE - mesaj de eroare legat de procesarea coșului de cumpărături;
    • Constants.SHOPPING_CART - conținutul coșului de cumpărături (identificatorul formatului de prezentare și cantitatea solicitată);
    • Constants.FORMATS_FILTER - lista cu criteriile de sortare în funcție de formatul de prezentare;
    • Constants.LANGUAGES_FILTER - lista cu criteriile de sortare în funcție de limbă;
    • Constants.CATEGORIES_FILTER - lista cu criteriile de sortare în funcție de categorie;
    • Constants.CURRENT_RECORDS_PER_PAGE - numărul maxim de înregistrări care poate fi vizualizat pe o pagină la un moment dat;
    • Constants.CURRENT_PAGE - pagina vizualizată la un moment dat;
    • Constants.FILTER_CHANGE - indică dacă informațiile au fost reîncărcate din baza de date datorită modificării criteriilor de filtrare;
    • Constants.FORMATS_LIST - lista cu toate formatele de prezentare disponibile;
    • Constants.LANGUAGES_LIST - lista cu toate limbile disponibile;
    • Constants.CATEGORIES_LIST - lista cu toate categoriile disponibile.

Pagina de tip autentificare din cadrul aplicaţiei BookStore

Pagina de tip administrator din cadrul aplicaţiei BookStore

Pagina de tip client din cadrul aplicaţiei BookStore

0. Să se cloneze în directorul de pe discul local conținutul depozitului la distanță de la https://www.github.com/aipi2015/Laborator05. În urma acestei operații, directorul Laborator05 va trebui să conțină subdirectorul labtasks, fișierele README.md și LICENSE.

student@aipi2015:~$ git clone https://www.github.com/aipi2015/Laborator05.git

1. Să se ruleze, folosind MySQL Workbench (sau alt utilitar similar), scriptul Laborator05l.sql, localizat în directorul scripts. Acesta instalează baza de date bookstore.

În cazul în care baza de date bookstore este deja instalată, nu mai este necesar să se ruleze acest script.
Această operație poate dura o perioadă de timp îndelungată, în funcție de configurațiile mașinilor pe care se lucrează.

2. În cazul Unix, daţi drepturi de execuţie tuturor fişierelor .sh din directorul bin al serverului Apache Tomcat, întrucât acestea sunt apelate la rândul lor de startup.sh, respectiv shutdown.sh.

student@aipi2015:~/apache-tomcat-8.0.28$ cd bin
student@aipi2015:~/apache-tomcat-8.0.28/bin$ sudo chmod +x *.sh

3. Modificați în interfața Constants din pachetul ro.pub.cs.aipi.lab05.general informațiile necesare obținerii drepturilor de acces la baza de date (nume de utilizator, parola).

4. Să se configureze mediile integrate de dezvoltare astfel încât acestea să fie interfațate cu serverul web Apache Tomcat 8.x. Mai multe informații cu privire la modul în care poate fi realizată interfațarea dintre aceste componente pot fi găsite la serverul Apache Tomcat.

Eclipse

Să se creeze o referinţă către serverul HTTP Apache Tomcat care să fie adăugată la proiectul 04-BookStore-JavaServlets.

Să se deschidă proiectul folosind opţiunea FileImportGeneralExisting Project into Workspace...

Se accesează opţiunea Run as…Run On Server din meniul contextual al aplicaţiei 04-BookStore-JavaServlets (right-click), bifându-se opţiunea Always use this server when running this project.

NetBeans

Să se creeze o referinţă către serverul HTTP Apache Tomcat care să fie adăugată la proiectul 05-BookStore-JSP.

Se accesează opţiunea Deploy din meniul contextual al proiectului (accesat cu right-click).

Alternativ, se poate porni serverul Apache Tomcat și dezvolta aplicația web în contextul său și prin opțiunea Run (F6), care va lansa și browser-ul implicit în care va fi prezentată pagina principală a aplicației web.

În fișierul catalina.properties din directorul conf al serverului web Apache Tomcat 8.x, suprascrieți proprietatea org.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING astfel încât să se folosească o politică permisivă în privința caracterelor imbricate (aceasta va avea valoarea false). O astfel de configurație este necesară pentru a putea fi accesate atribute ale contextului paginii JSP din cadrul unor scripleți.

# other properties
org.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING=false

Eclipse

Fișierul catalina.properties poate fi editat din mediul integrat de dezvoltare, în cazul în care sunt preluate informațiile din configurația de rulare specifică spațiului de lucru curent. În acest sens, în secțiunea Properties asociată serverului Apache Tomcat 8.x (accesibilă prin intermediul meniului contextual, din panoul Servers), atributul Location trebuie să refere metadatele din cadrul spațiului de lucru curent (având valoarea [workspace metadata]). În situația în care este precizată o altă valoare, se accesează butonul Switch Location.

În panoul Project Explorer, în secțiunea Servers, se editează fișierul catalina.properties corespunzător configurației de server Apache Tomcat 8.x pe care este rulată aplicația web.

NetBeans

Fișierul catalina.properties va fi editat manual, după ce se identifică locația la care este instalată instanța serverului Apache Tomcat 8.x pe care este rulată aplicația web. Aceasta poate fi determinată din secțiunea Servers corespunzătoare, în panoul Connection, fiind referită prin atributul Catalina Base.

5. Să se testeze aplicaţia prin accesarea adresei http://localhost:8080/05-BookStore-JSP/.

Se poate consulta script-ul Laborator05l.sql există exemple de utilizatori care pot fi folosite pentru accesarea paginilor de administrator, respectiv de client.

  • administrator: mary.smith / -
  • client: linda.williams / -

6. Să se acceseze pagina de tip administrator şi să se testeze funcţionalităţile implementate în cadrul acesteia (adăugare, editare, ştergere).

7. Să se acceseze pagina de tip client. Să se implementeze funcționalitatea corespunzătoare filtrării în funcție de limbile în care sunt disponibile cărțile din librărie. Un utilizator poate adăuga o valoare din lista de limbi disponibile. Filtrarea se face în funcție de limbile selectate, pentru acele formate de prezentare a cărții care conțin cel puțin una dintre aceste valori. În situația în care nu s-a specificat nici o valoare, sunt incluse toate volumele comercializate. Un utilizator poate șterge una sau mai multe dintre limbile selectate anterior.

<spoiler|Indicații de Rezolvare> În pagina client.jsp (accesibilă în directorul WebContent din proiectul Eclipse, respectiv în directorul web din proiectul NetBeans), se afișează lista cu limbile în funcție de care se realizează filtrarea, pentru fiecare dintre acestea atașându-se un buton pentru eliminarea valorii respective.

Se iterează pe lista cu filtre în funcție de limbi (atributul languagesFilter, transmis din ClientServlet), iar pentru fiecare element:

  • se afișează șirul de caractere conținând limba;
  • se afișează un element de tip <input>, având atributul type cu valoarea image și denumirea delete_language: _{language_name} (valori reținutr de constantele DELETE_BUTTON_NAME și LANGUAGE din interfața Constants). Resursa grafică se regăsește în directorul images, în subdirectorul user_interface, având denumirea delete.png (se recomandă să se forțeze dimensiunea acesteia la 16×16, prin specificarea atributelor width și height).

Elementele vor fi incluse ca linii în cadrul unui tabel (<tr><td>…</td></tr>).

Iterația pe elementele unei liste în cadrul unei pagini JSP se face folosind eticheta <c:forEach>, obiectul care se dorește a fi parcurs fiind referit prin atributul items.

Valoarea unei constante din cadrul interfeței ro.pub.cs.aipi.lab05.general.Constants poate fi obținută prin evaluarea unei expresii, încadrată între elementele <%= … %>.

În clasa ClientServlet din pachetul ro.pub.cs.aipi.lab05.servlets, se tratează acțiunile corespunzătoare evenimentelor de tip apăsare a butoanelor de tip insert, respectiv delete corespunzătoare filtrului în funcție de limba în care a fost selectată cartea.

  • pentru parametrii având denumirea de tipul insert_language: (valori conținute de constantele INSERT_BUTTON_NAME, respectiv LANGUAGE din interfața Constants), se obține denumirea limbii (ca valoare atașată parametrului, prin invocarea metodei request.getParameter(parameter)), se verifică dacă aceasta nu este conținută în lista de limbi în funcție de care se face filtrarea și, în caz afirmativ, este adăugată la listă, marcându-se faptul că lista de filtre a fost modificată (parametrul filterChange de tip boolean);
  • pentru parametrii având denumirea de tipul delete_language: _{language_name} (valori conținute de constantele DELETE_BUTTON_NAME, respectiv LANGUAGE din interfața Constants), se obține denumirea limbii (prin parsarea denumirii parametrului), se verifică dacă aceasta este conținută în lista de limbi în funcție de care se face filtrarea și, în caz afirmativ, este ștearsă din listă, marcându-se faptul că lista de filtre a fost modificată (parametrul filterChange de tip boolean).
Se poate utiliza ca model implementarea corespunzătoare filtrării în funcție de formatul de prezentare a cărții.

</spoiler>

8. În pachetul ro.pub.cs.aipi.lab05.servlets, în clasa ClientServlet să se completeze metoda doPost() pentru a crea conţinutul coşului de cumpărături, ţinând cont de situaţia în care pentru un produs deja existent să se poate actualiza cantitatea, astfel: dacă un produs există deja în coşul de cumpărături, cantitatea respectivă va fi suprascrisă, iar dacă aceasta este 0, produsul va fi şters din coşul de cumpărături.

<spoiler|Indicații de Rezolvare> În cazul în care se apasă un buton atașat unui câmp text pentru precizarea unei cantități pentru un anumit format de prezentare a unei cărți, este necesar să se realizeze următoarele operații:

  • se determină identificatorul formatului de prezentare a cărții și cantitatea corespunzătoare:

a) butonul are denumirea insert_shoppingcart_{book_presentation_id} unde book_presentation_id reprezintă identificatorul formatului de prezentare a cărții (de exemplu, insert_shoppingcart_1 pentru formatul de identificare a cărții cu identificatorul 1); prin parsarea denumirii acestui parametru se obține identificatorul formatului de prezentare a cărții:

if (parameter.startsWith(Constants.INSERT_BUTTON_NAME.toLowerCase() + "_" + Utilities.removeSpaces(Constants.SHOPPING_CART.toLowerCase()) + "_") && parameter.endsWith(".x")) {
  String bookPresentationId = parameter.substring(parameter.lastIndexOf("_") + 1, parameter.indexOf(".x"));
}
Pentru un element de tip <input> având atributul type cu valoarea submit, se transmit ca parametrii coordonatele la care se găsește mouse-ul în momentul în care se produce evenimentul de tip apăsare, acestea având aceeași denumire, sufixată de .x, respectiv .y. Este important ca un singur parametru să fie procesat, în acest caz.

b) câmpul text ce conține cantitatea corespunzătoare are denumirea copies_shoppingcart_{book_presentation_id} unde book_presentation_id reprezintă identificatorul formatului de prezentare a cărții (de exemplu, copies_shoppingcart_1 pentru formatul de identificare a cărții cu identificatorul 1); valoarea corespunzătoare acestui parametru reprezintă cantitatea solicitată:

if (parameter.startsWith(Constants.INSERT_BUTTON_NAME.toLowerCase() + "_" + Utilities.removeSpaces(Constants.SHOPPING_CART.toLowerCase()) + "_") && parameter.endsWith(".x")) {
  String quantity = request.getParameter(Constants.COPIES.toLowerCase() + "_" + Utilities.removeSpaces(Constants.SHOPPING_CART.toLowerCase()) + "_" + bookPresentationId);
}
Vor fi transmiși un număr de parametrii egal cu numărul de câmpuri text afișate în cadrul paginii Internet, însă va fi luat în considerare doar cel asociat butonului care a fost apăsat, chiar dacă pot fi introduse valori și în cadrul acestora. Obținerea valorii transmise prin intermediul unui parametru se realizează prin apelul request.getParameter(parameter).
  • se iterează asupra conținutului coșului de cumpărături (obiectul shoppingCart, transmis prin intermediul sesiunii, este de tipul List<Record> unde ca atribut se reţine identificatorul formatului de prezentare a cărţii, iar ca valoare cantitatea):
    • dacă se identifică un element având același identificator al formatului de prezentare a cărții:
      • în situația în care cantitatea este nenulă, aceasta este modificată;
      • în situația în care cantitatea este nulă, aceasta este ștearsă;
    • dacă nu se identifică un element având același identificator al formatului de prezentare a cărții, acesta este adăugată.
Obiectul shoppingCart astfel modificat trebuie să fie transmis prin intermediul sesiunii pentru a fi persistent, având în vedere faptul că protocolul HTTP nu reține și starea.
session.setAttribute(Utilities.removeSpaces(Constants.SHOPPING_CART.toLowerCase()), shoppingCart);

</spoiler>

9. În pagina client.jsp, să se implementeze funcționalitatea necesară pentru a se vizualiza coţinutul coşului de cumpărături. Se va afişa numărul de exemplare comandate, titlul cărţii, formatul de prezentare și limba, precum şi suma pentru fiecare produs în parte, respectiv preţul total pentru întregul coş de cumpărături.

<spoiler|Indicații de Rezolvare> Se verifică dacă lista corespunzătoare coșului de cumpărături, accesibilă în atributul shoppingCart, conține sau nu elemente. În acest scop se va folosi un element <c:choose>:

  • în cazul în care lista nu este vidă (condiția de verificare este <c:when test=“${not empty shoppingCart}”>), se afișează conținutul coșului de cumpărături;
  • în cazul în care lista este vidă (condiția de verificare este <c:otherwise>), se afișează mesajul conținut de constanta EMPTY_CART, definită în interfața Constants.
<c:choose>
  <c:when test="${not empty shoppingCart}">
    <%-- display shopping cart content --%>
  </c:when>
  <c:otherwise>
    <%-- display Constants.EMPTY_CART message --%>
  </c:otherwise>
</c:choose>

Se iterează asupra conținutului coșului de cumpărături (obiectul shoppingCart), determinându-se, pentru fiecare element, identificatorul formatului de prezentare (atributul) și cantitatea (valoarea). Pentru a crea un atribut și pentru a-l inițializa cu o anumită valoare, se poate folosi eticheta <c:set>.

<c:forEach var="shoppingCartContent" items="${shoppingCart}">
  <c:set var="bookPresentationIdentifier" value="${shoppingCartContent.attribute}" />
  <c:set var="quantity" value="${shoppingCartContent.value}" />
  <%-- do other processing --%>
</c:forEach>

Prețul unitar pentru un format de prezentare poate fi obținut apelând metoda getPrice() din clasa BookPresentationManager, ce primește ca argument identificatorul formatului de prezentare respectiv.

Informațiile cu privire la un format de prezentare (titlul, formatul de prezentare și limba) pot fi obținute apelând metoda getInformation() din clasa BookPresentationManager, ce primește ca argument identificatorul formatului de prezentare respectiv. Acesta întoarce o listă de obiecte de tip șir de caractere.

Instanțierea unui obiect de tipul BookPresentationManager, necesar pentru invocarea metodelor ce furnizează informațiile ce se doresc a fi afișate, se face prin intermediul acțiunii <jsp:useBean>.

<jsp:useBean id="bookPresentationManager" class="ro.pub.cs.aipi.lab05.businesslogic.BookPresentationManager" />

Apelul metodelor getPrice(), respectiv getInformation() va fi realizată în cadrul unei expresii (scriplet), din care trebuie accesată valoarea atributului bookPresentationIdentifier definit în contextul paginii JSP. În acest scop, va fi utilizată metoda getAttribute() a obiectului implicit pageContext (de tipul PageContext).

<c:set var="currentBookPrice" scope="request" value="<%= bookPresentationManager.getPrice(Long.parseLong(pageContext.getAttribute("bookPresentationIdentifier").toString())) %>" />
<c:set var="currentBookInformation" scope="request" value="<%= bookPresentationManager.getInformation(Long.parseLong(pageContext.getAttribute("bookPresentationIdentifier").toString())) %>" />  

Este necesar să se calculeze și prețul total al coșului de cumpărături, într-un atribut al paginii JSP, prin însumarea tuturor valorilor corespunzătoare volumelor care se doresc a fi achiziționate.

Prezentarea se va face în cadrul unui tabel (element de tip <table>), datele corespunzătoare unui obiect din coșul de cumpărături fiind incluse pe o linie a acestuia (<tr><td>…</td></tr>). </spoiler>

10. În pagina client.jsp, să se adauge două butoane prin care se poate anula, respectiv finaliza o comandă, în condițiile în care există produse în coșul de cumpărături.

<spoiler|Indicații de Rezolvare> Resursele grafice pentru butoane se regăsesc în directorul images, în subdirectorul user_interface, având denumirile:

  • remove_from_shopping_cart.png;
  • shopping_cart_accept.png;

Butoanele vor fi incluse în cadrul unui element de tip <input>, având atributul type cu valoarea image și denumirile cancelcommand, respectiv completecommand (valori conținute de constantele CANCEL_COMMAND și COMPLETE_COMMAND din interfața Constants, pentru care se elimină spațiile și se folosesc numai minuscule). Pentru a se obține aceste valori, vor fi utilizate funcțiile fn:toLowerCase(), respectiv fn:replace(), după ce s-au obținut valorile corespunzătoare constantelor definite în interfața Constants. Locațiile la care se găsesc resursele ce vor fi afișate vor fi precizate în cadrul atributului src. </spoiler>

11. În pachetul ro.pub.cs.aipi.lab04.servlets, în clasa ClientServlet, metoda doPost(), să se implementeze operaţiile de anulare, respectiv finalizare a unei comenzi.

<spoiler|Indicații de Rezolvare> În cazul anulării unei comenzi, se şterge conţinutul obiectului shoppingCart.

În cazul finalizării unei comenzi, trebuie realizate următoarele operaţii:

  • se adaugă o înregistrare în tabela invoice_header; se va folosi metoda create() din cadrul clasei InvoiceHeaderManager pentru care trebuie precizate valorile ce vor fi adăugate, aceasta furnizând identificatorul înregistrării din tabelă:
    • numărul de identificare (câmpul identification_number) va fi generat aleator folosind metoda Utilities.generateIdentificationNumber(), care primește ca parametri numărul de caractere de tip literă (3), respectiv cifră (6);
    • data de emitere (câmpul issue_date) - ziua curentă - va fi obținută folosind metoda now() din clasa LocalDate;
    • starea (câmpul state) are valoarea issued reținut de constanta STATE_ISSUED din interfața Constants;
    • identificatorul utilizatorului (câmpul user_id) va fi determinat pe baza denumirii (stocate în obiectul display) - concatenarea dintre prenumele şi numele reţinute în tabela user - prin apelul metodei getIdentifier() din clasa UserManager;
  • se iterează asupra conținutului coșului de cumpărături (obiectul shoppingCart):
    • se obține identificatorul formatului de prezentare a cărții (atributul), cantitatea (valoarea) și stocul corespunzător, așa cum este reținut în tabela book_presentation (prin apelul metodei getStockpile()) din clasa BookPresentationManager);
    • se compară numărul de exemplare din coşul de cumpărături cu stocul existent şi în situația în care comanda poate fi satisfăcută, se actualizează stocul (se apelează metoda update() din clasa BookPresentationManager care primește ca parametri atât atributul cât și valoarea care trebuie să fie modificate); se adaugă o înregistrare în tabela invoice_line; se va folosi metoda create() din cadrul clasei InvoiceLineManager pentru care trebuie precizate valorile ce vor fi adăugate:
      • identificatorul facturii (câmpul invoice_header_id), determinat anterior;
      • identificatorul formatului de prezentare a cărții (câmpul book_presentation_id);
      • cantitatea (câmpul quantity);
    • altfel, se adaugă un mesaj de eroare care va fi afișat în cadrul paginii JSP;
  • se goleşte coşul de cumpărături.

</spoiler>

12. Să se implementeze operaţia de deautentificare printr-un buton plasat sub mesajul de întâmpinare pentru fiecare utilizator în pagina de tip client. În această situație, utilizatorul se va întoarce în pagina de autentificare.

<spoiler|Indicații de Rezolvare> În pagina client.jsp, se afișează un element de tip <input>, având atributul type cu valoarea image și denumirea signout (valoare reținută de constanta SIGNOUT din interfața Constants). Resursa grafică se regăsește în directorul images, în subdirectorul user_interface, având denumirea signout.png.

În clasa ClientServlet, în cazul în care a fost apăsat butonul pentru operația de deautentificare:

  • se obține lista cu toți parametrii (metoda getParameterNames() din clasa ServletRequest), aceștia fiind eliminați, prin invocarea metodei removeAttribute();
  • se elimină elementele conținute de listele shoppingCart, formatsFilter, languagesFilter, categoriesFilter;
  • valorile conținute de obiectele previousRecordsPerPage, currentRecordsPerPage, currentPage vor fi cele implicite;
  • se elimină conținutul obiectului books;
  • se transferă contextul către servletul care gestionează operația de autentificare (LoginServlet):
    RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/" + Constants.LOGIN_SERVLET_PAGE_CONTEXT);
    if (dispatcher != null) {
      dispatcher.forward(request, response);
    }
  • se invalidează sesiunea prin invocarea metodei invalidate() pe obiectul de tip HttpSession, - după această operație nu mai este permis să se utilizeze pagina Internet curentă;
    session.invalidate();
Se poate utiliza ca model implementarea din cadrul paginii de administrator (clasa AdministratorServlet / pagina administrator.jsp).

</spoiler>

Resurse

Soluții

laboratoare/laborator05.txt · Last modified: 2015/11/25 20:00 by Andrei Roșu-Cojocaru
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0