====== 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.
{{ :laboratoare:laborator05:01clientserverelationship.png?nolink&600 }}
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.
{{ :laboratoare:laborator05:02JavaServletJSPgeneration.png?nolink&700 }}
===== 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://://%%'' este ''index.jsp'' sau cea precizată prin elementul '''' din secţiunea '''' 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\\\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 {
// ...
}
{{ :laboratoare:laborator05:03JSPpagelifecycle.png?nolink&400 }}
Toate aceste metode fac parte din interfaţa [[https://docs.oracle.com/javaee/7/api/javax/servlet/jsp/HttpJspPage.html|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 [[http://docs.oracle.com/javaee/7/api/javax/servlet/jsp/JspException.html|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.
{{ :laboratoare:laborator05:04webapplicationarchitecture.png?nolink&800 }}
Î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.
{{ :laboratoare:laborator05:05JSPpagestructure.png?nolink&1024 }}
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;
==== 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" %>
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" %>
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" %>
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 '''' 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:
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:
| '''' | defineşte atributul unui element XML definit dinamic |
| '''' | defineşte corpul unui element XML definit dinamic |
| '''' | defineşte elemente XML în mod dinamic |
| Prin acţiunile '''', '''' şi '''' elementele XML pot fi generate în momentul rulării, ca răspuns la o cerere şi nu atunci când sunt compilate sursele.
Attribute Value
Body for XML element
→
Body for XML element
||
| '''' | 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''.
|
| '''' | 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ă;
...
|
| '''' | 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);
...
|
| '''' | 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.
|
| '''' | 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.
|
| '''' | generarea codului specific browser-ului (o etichetă '''' sau '''') 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 '''', în caz de producere a unei erori, se poate specifica un şir de caractere care să fie afişat prin acţiunea ''''
Unable to load Java Plugin
|
| '''' | 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
My text template
|
==== 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 %>
Java code fragment
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 %>
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; ]+ %>
declaration;
[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 [[http://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequest.html|javax.servlet.ServletRequest]] | cererea care a invocat pagina JSP |
| ''response'' | subclasă a [[http://docs.oracle.com/javaee/7/api/javax/servlet/ServletResponse.html|javax.servlet.ServletResponse]] | răspunsul pe care îl generează pagina JSP |
| ''out'' | [[http://docs.oracle.com/javaee/7/api/javax/servlet/jsp/JspWriter.html|javax.servlet.jsp.JspWriter]] | obiect care scrie în fluxul de ieşire |
| ''session'' | [[https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html|javax.servlet.http.HttpSession]] | obiect sesiune asociat cererii care a invocat pagina JSP |
| ''application'' | [[http://docs.oracle.com/javaee/7/api/javax/servlet/ServletContext.html|javax.servlet.ServletContext]] | context pagină JSP |
| ''config'' | [[https://docs.oracle.com/javaee/7/api/javax/servlet/ServletConfig.html|javax.servlet.ServletConfig]] | informaţii de configurare referitoare la servlet |
| ''pageContext'' | [[http://docs.oracle.com/javaee/7/api/javax/servlet/jsp/PageContext.html|javax.servlet.jsp.PageContext]] | contextul paginii JSP |
| ''page'' | [[https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html|java.lang.Object]] | referinţă către pagina JSP prin care poate fi accesat servlet-ul asociat |
| ''exception'' | [[https://docs.oracle.com/javase/8/docs/api/java/lang/Throwable.html|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:
...
Header Name Header Value
<%
Enumeration headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String headerName = (String)headers.nextElement();
String headerValue = request.getHeader(headerName);
%>
<%= headerName %> <%= headerValue %>
<%
}
%>
...
=== 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'':
60
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 '''' 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 '''' indică numele filtrului, clasa asociată precum şi parametrii folosiţi la iniţializarea acestuia, iar elementul '''' 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 ''''.
==== Î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'':
file-upload
My Upload Location
Pentru procesarea în cadrul paginii JSP a încărcării fişierului pe server, poate fi folosită [[http://commons.apache.org/proper/commons-fileupload/|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 [[https://java.net/projects/javamail/pages/Home|API-ul JavaMail]] şi [[http://www.oracle.com/technetwork/java/javamail/index-135046.html|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.
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ă.
#{inputName} #{inputValue}
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 text1 ${expression} my text2
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:
* 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:
Î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
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şă.
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:
- etichete JSTL de bază;
- etichete JSTL pentru formatare;
- etichete JSTL destinate gestiunii informaţiilor dintr-o bază de date SQL;
- etichete JSTL pentru gestiunea documentelor XML;
- 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:
| '''' | 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.
|
| '''' | 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.
|
| '''' | 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ă.
|
| '''' | 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
<% some expression(s) that may potentially throw an error %>
|
| '''' | 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.
<% do some operations %>
|
| '''' | etichetă de tip condiţional, indicând condiţii ce se exclud mutual, specificate prin '''' şi ''''; funcţionează ca instrucţiunea ''switch'' din Java, permiţând alegerea dintre mai multe alternative: ramurile case sunt specificate prin '''' în timp ce ramura default este specificată prin ''''.\\ \\ Eticheta nu are atribute.
<% do some operations %>
<% do some operations %>
...
<% do some operations %>
<% do some other operations %>
|
| '''' | subetichetă a '''', 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ă. |
| '''' | subetichetă a '''', ce urmează uneia sau mai multor etichete '''', determinând evaluarea corpului său, dacă nici una dintre condiţiile care o preced nu este îndeplinită.\\ \\ Eticheta nu are atribute. |
| '''' | 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'';
|
| '''' | 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;
|
| '''' | iterează asupra unor particule, separate prin delimitatori\\ \\ Suportă aceleaşi atribute ca şi , la care se adaugă delim, care indică caracterele utilizate ca delimitatori
|
| '''' | adaugă un parametru la URL-ul specificat în cadrul unei etichete '''', 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;
...
|
| '''' | redirectează controlul la un alt URL, realizând suprascrierea sa în browser; suportă URL-uri relative la context şi eticheta '' ''\\ \\ Atributele asociate etichetei sunt:\\ • ''url'' (obligatoriu) – URL-ul la care se realizează redirectarea controlului;\\ • ''context'' – caracterul / urmat de numele aplicaţiei web.
|
| '''' | 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 '' ''\\ \\ 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;
|
==== 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:
| '''' | 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ă. |
| '''' | 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ă. |
| '''' | 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ă. |
| '''' | parsează reprezentarea sub formă de şir de caractere pentru o valoare de tip dată calendaristică / timp\\ \\ Are aceleaşi atribute ca '''' la care se adaugă ''parseLocale'', indicând localizarea care trebuie utilizată atunci când se parsează informaţia de tip dată calendaristică. |
| '''' | încarcă o resursă ce urmează să fie utilizată în corpul său, de eticheta ''''\\ \\ 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 ''''.
echivalent cu
|
| '''' | 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. |
| '''' | î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. |
| '''' | 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. |
| '''' | 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. |
| '''' | 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. |
| '''' | 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:
| '''' | 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ă;\\ • ''url'' – URL-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.
|
| '''' | 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.
|
| '''' | 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.
<%-- some INSERT, UPDATE or DELETE query -->
|
| '''' | stabileşte valoarea unui parametru al unei instrucţiuni SQL, fiind folosit de obicei împreună cu etichetele '''' sau ''''\\ \\ Atributul asociat etichetei este value prin care se indică valoarea care se doreşte a fi asociată parametrului.
SELECT FROM table WHERE attribute = ?
<%-- some INSERT, UPDATE or DELETE query with one or more
missing attribute values -->
|
| '''' | 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 '' ''. |
| '''' | oferă elemente care realizează acţiuni folosind un obiect ''Connection'' partajat, executate în cadrul unei tranzacţii; grupează interogări exprimate de etichetele '''' şi '''' î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''.
<%-- some INSERT queries -->
<%-- some UPDATE queries -->
<%-- some DELETE queries -->
|
==== 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:
| '''' | 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 |
| '''' | 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'');\\ • ''systemId'' – URI-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''.
|
| '''' | 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''.
|
| '''' | 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''.
The attribute of the element at index is not null!
|
| '''' | 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
|
| '''' | etichetă de tip condiţional care stabileşte un context pentru operaţii condiţionale care se exclud mutual, marcate prin '''' şi ''''\\ \\ Eticheta nu are atribute.
Attribute has value 1!
Attribute has value 2!
...
Attribute has value n!
Attribute has unknown value!
|
| '''' | subetichetă a etichetei '''' 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ă. |
| '''' | subetichetă a etichetei '''' ce urmează uneia sau mai multor etichete '''', determinând evaluarea corpului său, dacă nici una dintre condiţiile care o preced nu este îndeplinită.\\ \\ Eticheta nu are atribute. |
| '''' | se aplică la transformare XSL a unui document XML\\ \\ Atributele asociate etichetei sunt:\\ • ''doc'' – documentul XML sursă pentru transformarea XSLT;\\ • ''docSystemId'' – URI-ul documentului XML original;\\ • ''xslt'' (obligatoriu) – foaia de stil XSLT care conţine instrucţiunile pentru transformare;\\ • ''xsltSystemId'' – URI-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.
|
| '''' | 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.
|
==== 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''.
|
| ''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''.
|
| ''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''.
|
| ''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''.
|
| ''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)
|
| ''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''
|
| ''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''.
|
| ''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''
|
| ''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[]''.
|
| ''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''.
|
| ''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''.
|
| ''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''.
|
| ''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''.
|
| ''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''
|
| ''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''
|
| ''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''
|
==== 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()''.
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 '''', denumirea clasei care îi implementează funcţionalitatea (elementul '''') precum şi tipul de conţinut al corpului etichetei (elementul '''', 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'').
1.0
2.0
A short description of my custom tag
CustomTag
mypackage.CustomTag
scriptless
customAttribute
true
java.lang.Integer
false
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'':
...
Some custom tag body
...
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.
{{ :laboratoare:laborator05:bookstore_webapplication_structure.png?nolink&300 }}
**Structura aplicaţiei BookStore**
Atributele care sunt transmise între clasele servlet și paginile .jsp sunt:
- 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);
- 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ă;
- 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.
{{ :laboratoare:laborator04:bookstore_webapplication_loginservlet.png?nolink&300 }}
**Pagina de tip autentificare din cadrul aplicaţiei BookStore**
{{ :laboratoare:laborator04:bookstore_webapplication_administratorservlet.png?nolink&800 }}
**Pagina de tip administrator din cadrul aplicaţiei BookStore**
{{ :laboratoare:laborator04:bookstore_webapplication_clientservlet.png?nolink&800 }}
**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 [[:utile:apache_tomcat|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 //File// → //Import// → //General// → //Existing 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//.
{{ :laboratoare:laborator04:eclipse01.png?nolink }}
{{ :laboratoare:laborator04:eclipse02.png?nolink }}
{{ :laboratoare:laborator05:eclipse03.png?nolink }}
==== 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).
{{ :laboratoare:laborator04:netbeans01.png?nolink }}
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//.
{{ :laboratoare:laborator04:eclipse04.png?nolink }}
Î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.
{{ :laboratoare:laborator04:eclipse05.png?nolink }}
==== 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//.
{{ :laboratoare:laborator04:netbeans02.png?nolink }}
===== =====
**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.
{{ :laboratoare:laborator04:activitate_de_laborator_exercitiu07.png?nolink }}
Î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 [[http://www.w3schools.com/tags/tag_input.asp| ]], 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 16x16, prin specificarea atributelor ''width'' și ''height'').
Elementele vor fi incluse ca linii în cadrul unui tabel (''... '').
Iterația pe elementele unei liste în cadrul unei pagini JSP se face folosind eticheta [[http://www.tutorialspoint.com/jsp/jstl_core_foreach_tag.htm|]], 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.
**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.
Î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:
{{ :laboratoare:laborator04:activitate_de_laborator_exercitiu08.png?nolink&700 }}
**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 '' '' 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'' 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);
**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.
{{ :laboratoare:laborator04:activitate_de_laborator_exercitiu09.png?nolink }}
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 [[http://www.tutorialspoint.com/jsp/jstl_core_choose_tag.htm|]]:
* în cazul în care lista nu este vidă (condiția de verificare este ''''), se afișează conținutul coșului de cumpărături;
* în cazul în care lista este vidă (condiția de verificare este ''''), se afișează mesajul conținut de constanta ''EMPTY_CART'', definită în interfața ''Constants''.
<%-- display shopping cart content --%>
<%-- display Constants.EMPTY_CART message --%>
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 [[http://www.tutorialspoint.com/jsp/jstl_core_set_tag.htm|]].
<%-- do other processing --%>
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 [[http://www.tutorialspoint.com/jsp/jsp_java_beans.htm|]].
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 [[https://tomcat.apache.org/tomcat-8.0-doc/jspapi/javax/servlet/jsp/JspContext.html#getAttribute%28java.lang.String%29|getAttribute()]] a obiectului implicit ''pageContext'' (de tipul [[https://tomcat.apache.org/tomcat-8.0-doc/jspapi/javax/servlet/jsp/PageContext.html|PageContext]]).
" />
" />
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 [[http://www.w3schools.com/tags/tag_table.asp|]]), datele corespunzătoare unui obiect din coșul de cumpărături fiind incluse pe o linie a acestuia (''... '').
**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.
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 [[http://www.w3schools.com/tags/tag_input.asp| ]], 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 [[http://www.tutorialspoint.com/jsp/jstl_function_tolowercase.htm|fn:toLowerCase()]], respectiv [[http://www.tutorialspoint.com/jsp/jstl_function_replace.htm|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''.
**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.
Î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 [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#now--|now()]] din clasa [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html|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.
**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.
{{ :laboratoare:laborator04:activitate_de_laborator_exercitiu12.png?nolink }}
În pagina ''client.jsp'', se afișează un element de tip [[http://www.w3schools.com/tags/tag_input.asp| ]], 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 [[http://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequest.html#getParameterNames--|getParameterNames()]] din clasa [[http://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequest.html|ServletRequest]]), aceștia fiind eliminați, prin invocarea metodei [[http://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequest.html#removeAttribute-java.lang.String-|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 [[https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html#invalidate--|invalidate()]] pe obiectul de tip [[https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html|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'').
===== Resurse ======
[[https://docs.oracle.com/javaee/7/tutorial/doc/javaeetutorial7.pdf|Eric Jendrock, Ricardo Cervera-
Navarro, Ian Evans, Kim Haase, William Markito - The Java EE 7 Tutorial]] - capitolul 9\\
[[http://tomcat.apache.org/|Apache Tomcat]]\\
[[http://www.tutorialspoint.com/jsp/|Basic JSP Tutorial]]\\
[[http://www.java-samples.com/jsp/|Knowledge Base on JSP]]\\
[[http://www.javatpoint.com/jsp-tutorial|JSP Tutorial]]\\
[[http://www.jsptut.com/|JSP Tutorial]]\\
[[https://www.hscripts.com/tutorials/jsp/|JavaServer Pages Tutorial]]\\
[[http://courses.coreservlets.com/Course-Materials/csajsp2.html|Building Web Apps in Java: Beginning & Intermediate Servlet & JSP Tutorials]]\\
[[http://courses.coreservlets.com/Course-Materials/msajsp.html|Advanced Servlet and JSP Tutorials]]\\
[[http://www.vogella.com/tutorials/EclipseWTP/article.html|Java web development with Eclipse WTP - Tutorial]]\\
[[http://books.google.com/books?isbn=1430204656|Giulio Zambon with Michael Sekler – Beginning JSPTM, JSFTM and Tomcat Web Development: From Novice to Professional, Apress, 2007]]\\
Irina ATHANASIU, //Java ca limbaj pentru programare distribuita//, Editura Matrix Rom, București, 2002
===== Soluții =====
[[https://github.com/aipi2015/Laborator05/tree/master/solutions/eclipse/05-BookStore-JSP|Proiect Eclipse]]\\
[[https://github.com/aipi2015/Laborator05/tree/master/solutions/netbeans/05-BookStore-JSP|Proiect NetBeans]]