P. 1
tUTORIALJavaServlet

tUTORIALJavaServlet

|Views: 55|Likes:
Published by stoica florina

More info:

Published by: stoica florina on Nov 05, 2011
Copyright:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

03/21/2014

pdf

text

original

Sections

  • 7.1.1. Locul servlet între tehnologiile Web
  • 7.1.2. Arhitecturile aplicaţiilor servlet
  • 7.1.3.1. Probleme generale
  • 7.1.3.2. Instalarea şi configurarea Tomcat
  • 7.1.3.3. Gestiunea porturilor
  • 7.1.3.4. Contextul unei aplicaţii Servlet: definire şi creeare
  • 7.1.3.5. Structura de subdirectoare a unui context şi invocarea de resurse
  • 7.1.3.6. Tomcat conectat la Apache
  • 7.1.4.1. Cum arată un servlet?
  • 7.1.4.2. Interacţiunea cu clienţii
  • 7.1.4.3. Primul exemplu şi compilarea unui servlet
  • 7.1.4.4. Interacţiunea cu containerul
  • 7.1.4.5. Configurarea şi iniţializarea servlet-urilor. Exemple
  • 7.1.5.1. Avantajele Servlet faţă de CGI
  • 7.1.5.2. Acces la variabilele de mediu CGI
  • 7.2.1.1. Servlet-ul Maxim, apelat prin GET şi prin POST
  • 7.2.1.2. Servlet-ul DisplayQueryString
  • 7.2.1.3. Servlet-ul MaximForward
  • 7.2.2.1. Elemente specifice de comunicare
  • 7.2.2.2. Clientul Applet2Servlet
  • 7.2.2.3. Servlet-ul Servlet2Applet
  • 7.2.3.1. Noţiunea de cookie
  • 7.2.3.2. Exemplu de utilizare cookies
  • 7.2.4.1. Conceptul de sesiune
  • 7.2.4.2. Implementarea unui counter de pagină Web
  • 7.2.4.3. Clientul counter
  • 7.2.4.4. ServletCounter
  • 7.2.4.5. ServletCounterSession
  • 7.3.1.1. Clientul mail.html
  • 7.3.1.2. Clasa Mailer, expeditor de mesaje email
  • 7.3.1.3. Clasa HTML.java, auxiliar pentru servlet
  • 7.3.1.4. ServletMail
  • 7.3.2.1. Clasa NoteAccessDB
  • 7.3.2.2. Programul ServletProfesorDB
  • 7.3.2.3. Programul ServletStudentDB
  • 7.3.2.4. Clientul StudentDB
  • 7.3.2.5. ClientProfesorDB
  • 7.3.3.1. Definirea referinţei la resursa bază de date
  • 7.3.3.2. Utilizarea referinţei în codul Java
  • 7.3.3.3. Definirea resursei baza de date

7.

TEHNOLOGIA JAVA SERVLET

7.1. Conceptul de servlet; containere de servlet-uri
7.1.1. Locul servlet între tehnologiile Web
Foarte simplu spus, un servlet [49] este un program Java care rulează pe un server Web şi care construieşte (dinamic) pagini Web. Din punct de vedere funcţional, un servlet face acelaşi lucru ca şi un program CGI, descris în 4.7.1. Să vedem mai întâi unde se află servlet în panoplia tehnologiilor Web actuale. Există mai multe lucrări care tratează acest subiect. Părerea noastră este că lucrarea [51] face o analiză pertinentă a subiectului, motiv pentru care ne-o însuşim. Mai mult, ceea ce vom prezenta în această secţiune este în mare măsură preluat din [51]. Pentru realizarea de pagini Web dinamice şi pentru asigurarea unei interacţiuni bidirecţionale între browser şi server-ul Web, ultimii 10 ani au consacrat mai multe tehnologii. Următoarele sunt cele mai răspândite şi le enumerăm aproximativ în ordinea apariţiei lor. 1. Common Gateway Interface (CGI) Este prima tehnologie de acest tip. În 4.7.1 am prezentat această tehnologie. 2. ColdFusion [51] Este un produs al corporaţiei Allaire. În esenţă este vorba de extinderea HTML cu o serie de tag-uri noi pentru operaţii speciale, mai ales pentru interogarea bazelor de date. Tehnologia şi-a avut locul ei în istorie şi a fost atractivă (doar) până când au apărut şi alte tehnologii Web. 3. Server-Side Includes (SSI) [23] Oferă posibilitatea execuţiei unor script-uri sau a altor acţiuni în partea de server, prin specificarea unor comenzi incluse direct în codul HTML. Din cauza multor slăbiciuni, mai ales pe partea de securitate, utilizarea SSI este din ce în ce mai rară. 325

4.

Server-Side JavaScript (SSJS) [51] Limbajul JavaScript este destinat în principal acţiunilor la nivel de client. SSJS este o extensie a limbajului JavaScript pentru a descrie clase care să acţioneze la nivel de server.

5.

PHP (Personal Home Page, sau mai recent Professional Hipertext Processor) Este o tehnologie open-source extrem de atractivă şi de răspândită în prezent. PHP oferă facilităţi simple de descrierea unor acţiuni la nivel de server, operând inclusiv cu conceptul de sesiune şi oferind o serie de funcţiuni interne legate de acces la fişiere şi baze de date.

6.

Servlet Este o tehnologie introdusă de Sun în 1996. O vom trata în acest capitol.

7.

Java Server Pages (JSP) Este o extensie a tehnologiei servlet, bazată pe script-uri, de care ne vom ocupa în capitolul următor.

8.

Active Server Pages (ASP) Este o tehnologie bazată pe script-uri, promovată de Microsoft pentru a opera pe platforme Windows. Lucrează în principal în tandem cu server-ele Web produse de Microsoft, adică cele de tip IIS. Se încearcă adaptarea şi pentru server-ele Web de tip Apache. Următoarea tehnologie o include.

9.

Active Server Pages .NET (ASP.NET) Face parte din iniţiativa .NET a Microsoft. Introduce elemente noi faţă de ASP. Este interesant faptul că la baza .NET stă limbajul C#, care este extrem de asemănător cu limbajul Java. De asemenea, executivul .NET - numit Common Language Runtime (CLR) este extrem de asemănător cu Java Virtual Machine (JVM)!

În ultima vreme, piaţa programării Web a fost dominată pe de o parte de servlet/JSP, iar pe de altă parte de ASP. Apariţia ASP.NET introduce în competiţie un element nou. În sfârşit, PHP vine puternic din urmă. Care va fi mâine realitatea? Greu de anticipat.

326

În spiritul prezentei lucrări ne simţim obligaţi să subliniem câteva dintre calităţile oferite de servlet/JSP, calităţi care nu se regăsesc la celelalte tehnologii: • Performanţa Tehnologia servlet este superioară CGI, deoarece nu este necesară crearea unui nou proces la fiecare cerere, ci numai un thread întreţinut de containerul de servlet-uri. • Portabilitate Aplicaţiile servlet sunt portabile, deoarece atât servlet-ul, cât şi containerul de servlet sunt scrise în Java. • Dezvoltare rapidă a aplicaţiilor Fiind o thnologie Java, servlet are acces la o bibliotecă bogată de pachete specializate, sporind astfel viteza de proiectare. • Robusteţe Fiind vorba de Java, JVM controlează gestiunea memoriei, garbage collection etc. Astfel proiectantul este scutit de o serie de gestiuni care de regulă conduc la pene de program greu de depistat. • Acceptare largă Din ce în ce mai multe case de soft preiau Java ca şi principală platformă de dezvoltare a proiectelor lor. Astfel, aplicaţiile servlet/JSP se pot integra uşor în proiecte de anvergură.

7.1.2. Arhitecturile aplicaţiilor servlet
Formal vorbind, un servlet este o clasă care poate fi încărcată dinamic şi apoi rulată într-un server web de tip special, numit container de servlet-uri (servlet engine). Un servlet interacţionează cu clienţii după modelul HTTP bazat pe cerere - răspuns. Din această cauză, containerul de servlet-uri permite comunicarea prin protocolul HTTP pentru cereri de la clienţi şi răspuns al servlet-ului. În plus, în special din raţiuni de securitate [71], containerul suportă şi protocoale înrudite, ca de exemplu HTTPS (HTTP securizat prin SSL). La această oră sunt cunoscute două tipuri de arhitecturi ale aplicaţiilor servlet: • aplicaţii prin container de sine stătător (standalone); • aplicaţii cu container cascadat dintr-un server web. 327

În fig. 7.1 este prezentată arhitectura cu container standalone.
Servlet Container servleturi Raspuns HTTP Continut static

Cerere HTTP Client (browser)

Figura 7.1. Servlet cu container standalone

O aplicaţie servlet conţine, pe lângă partea dinamică condusă de servlet şi o parte statică specifică web, ca de exemplu pagini HTML şi fişiere cu imagini. Containerul de servlet având şi funcţii de server web, va trebui, pe lângă execuţia servlet-ului, să gestioneze şi aceste conţinuturi statice. Pentru aplicaţii mai serioase este de preferat ca partea statică să fie gestionată de către un server web robust şi destinat special, cum ar fi de exemplu Apache sau Microsoft IIS. Prin aceasta, containerul va fi mai puţin încărcat, iar serviciile web relative la aplicaţie vor fi mai bine şi mai sigur gestionate. Astfel apare necesitatea celei de-a doua arhitecturi, cea din fig. 7.2.
Container servleturi Server Web Raspuns HTTP Continut static

Cerere HTTP Client (browser)

Servlet

Figura 7.2. Servlet împreună cu un server web

7.1.3. Containere de servlet
7.1.3.1. Probleme generale Un container de servlet-uri este deci o aplicaţie Java cu rol de maşină virtuală în care să ruleze servlet-urile. Funcţionalitatea unui container nu se reduce numai la simpla execuţie a unui servlet, ci el trebuie să gestioneze acest servlet pe toată durata de viaţă a acestuia. La ora actuală există numeroase implementări de containere, unele dintre ele comerciale, altele dezvoltate ca proiecte open-source, care pot fi liber 328

conf. Alte containere pot fi descărcate de pe Internet într-un singur fişier arhivă. Instalarea şi configurarea Tomcat În continuare ne vom referi numai la containerul Tomcat. este fie un director sistem.3. de obicei zip Instalarea acestor containere se reduce la simpla dezarhivare a acestui fişier într-un anumit director. Fie că sunt comerciale. Unele containere. în cele ce urmează vom utiliza două variabile de mediu: • CATALINA_HOME prin care vom marca locul în structura de directori unde se află instalat (urmează a se instala) containerul Tomcat. Recomandăm cititorilor interesaţi parcurgerea acestor specificaţii. conform Sun Microsystem.sun.org/aboutJava/communityprocess/first/jsr053. De exemplu. Fiind scris în Java. un container de servlet-uri este în general independent de platformă. Spre exemplu un container pentru Linux poate prezenta script-uri care să permită lansarea în execuţie a containerului respectiv într-un mod compatibil System V.com/products/servlet/industry. aproximativ 36 de implementări de containere. pe o staţie Windows2000 această variabilă poate fi: 329 . două dintre cele mai cunoscute sunt Tomcat şi Jetty. s-au impus pe piaţă Macromedia Jrun. Dintre containerele open-source. După caz. toate implementările trebuie sa respecte specificaţiile Sun Microsystem cu privire la servlet-uri. Există în prezent. de obicei cu extensia . 7. Unele containere. Două versiuni ale aceluiaşi container. lista completă poate fi consultată la adresa: http://java. se instalează cu ajutorul unui program de setup. sau mai noi în fişiere xml.1. au diferite componente grafice pentru administrare şi configurare. fie un director al utilizatorului. Primul dintre ele este dezvoltat în paralel cu server-ul web Apache şi s-a impus ca model de referinţă. de obicei cele comerciale. recomandat de Sun Microsystem. diferă prin fişierele script de lansare. dezvoltate pentru platformele Microsoft Windows.2. pentru două platforme diferite. fie că sunt open-source. Altele pot prezenta o interfaţă web-based pentru a efectua aceste operaţii. Implementările open-souce prezintă opţiunile de configurare în fişiere text. Configurarea unui container de servlet-uri diferă de la caz la caz. Aceste produse excelează în primul rând prin uşurinţa în instalare şi configurare. Pentru a putea rula un servlet trebuie instalat şi configurat un container de servlet-uri.distribuite.html. Pentru fixarea ideilor. Dintre implementările comerciale de containere. Borland AppServer şi IBM WebSphere Application Server. care sunt disponibile pe Internet la adresa: http://jcp. în timp ce un container pentru Windows 2000 poate fi însoţit de fişiere binare care să permită lansarea containerului ca serviciu.

zip sau tar. este fie un director sistem.1 • JAVA_HOME prin care vom marca locul în structura de directori unde se află instalat pachetul Java. după caz. executată ca root: o rpm –Uhv $CATALINA_HOME 330 . De exemplu.apache.0 Setarea variabilelor de mediu se face în conformitate cu cerinţele specifice ale sistemului de operare pe care se lucrează. acest lucru se face adăugând în fişierul autoexec.zip sau tar. fie un director al utilizatorului. atunci containerul poate fi instalat cu următoarea comanda Linux.0. fie în ~/. Dacă s-a optat pentru formatul .o C:\jakarta-tomcat-4.profile fie în ~/. Containerul Tomcat poate fi descărcat în mai multe formate: . • Instalarea containerului Tomcat În funcţie de formatul în care a fost descărcat containerul Tomcat.bat linia: set VAR=valoare o Pentru sistemele de operare Windows NT sau Windows 2000 această variabilă se setează apelând pe rând: My Computer / click dreapta / Properties / Users Profiles / User defined Variables.org. instalarea poate să difere. setarea unei variabile VAR se face: o Pentru Windows 9x.exe pentru platformele Windows.gz pentru ambele platforme.rpm. fie în /etc/profiles.bash_profile următoarele două linii: VAR=valoare export VAR Pentru instalarea Tomcat sunt necesari următorii paşi: • Descărcarea containerului Tomcat Se face de pe Internet de la adresa http://jakarta.4. . Dacă s-a optat pentru formatul . o Pentru Unix se depun. De exemplu.exe se execută fişierul exe descărcat.gz se dezarhivează acest fişier în $CATALINA_HOME. . După caz.rpm pentru platformele Linux. Daca s-a optat pentru formatul . pe o staţie Windows 2000 această variabilă poate fi: o C:\j2sdk1.

bat După instalarea Tomcat. adică: ${CATALINA_HOME}/bin/startup.sh %CATALINA_HOME%\bin\startup. Dacă este cazul. Pentru platformele Unix se va rula script-ul startup.xml care este fişierul principal de configurare Tomcat şi web.sh.jar. Dacă se doreşte.bat. Restul elementelor de configurare le vom prezenta în secţiunile următoare. iar pentru Windows script-ul startup. se vor modifica unele dintre numerele de port cu care operează Tomcat. • lib Conţine o serie de clase pentru folosinţă comună. 331 . • clases Este directorul cu clasele globale necesare aplicaţiilor web. Dintre acestea. Setarea se face în conformitate cu cerinţele sistemului de operare gazdă.• Configurarea containerului Mai întâi trebuie setată variabila JAVA_HOME. • server Conţine fişierele arhivă (tip . grupate în arhive .jar) ale Tomcat. cele mai importante sunt server. • conf Este directorul pentru fişierele de configurare. se poate seta şi variabila CATALINA_HOME. • Lansarea containerului Tomcat În $CATALINA_HOME există un subdirector bin care conţine script-urile de lansare ale lui Tomcat. în $CATALINA_HOME apare următoarea structură de directori: • bin Este directorul în care se găsesc programele execuabile şi scripturile de bază Tomcat.xml care este fişierul machetă pentru descriptorii aplicaţiilor.

• logs Este directorul în care Tomcat întreţine o serie de fişiere jurnal (log-uri). Consultarea acestora este uneori utilă, mai ales când apar o serie de erori în funcţionarea unui servlet. • common Conţine o serie de clase de folosinţă atât pentru Tomcat, cât şi pentru aplicaţiile web. • webapps Este directorul în ale cărui subdirectoare pot fi găzduite diverse aplicaţii web. Aici se află, printre altele exemplele demonstrative de aplicaţii livrate odată cu distribuţia Tomcat. Tot aici pot fi plasate noi aplicaţii. Pentru fiecare aplicaţie se va depune ori structura completă de directori a ei, ori o arhivă .war a acestei structuri, care va fi desfăcută automat de către Tomcat. Odată cu distribuţia Tomcat, acest director conţine cel puţin subdirectoarele ROOT, manager şi examples. • work Este spaţiul în care sunt depuse servlet-urile generate automat din paginile JSP. Recomandăm ca în primă fază, instalarea şi configurarea unui container de servlet să o facă programatorul. Acesta trebuie să se familiarizeze cu toate opţiunile de configurare şi cu modalităţile de instalare a unui astfel de container, pentru a putea folosi şi exploata la maxim serviciile oferite. De asemenea, recomandăm ca în faza de dezvoltare şi testare a unei aplicaţii, containerul să fie de asemenea întreţinut de către programator şi repornit ori de câte ori este nevoie. Astfel, pentru testare fiecare programator îşi va întreţine propria instanţă Tomcat. În faza de exploatare se va folosi, eventual, un Tomcat unic, întreţinut şi securizat de către un administrator. 7.1.3.3. Gestiunea porturilor Un container servlet are un port de ascultare cereri HTTP. De obicei acesta este portul 8080, dar el poate diferi de la container la container. Specificarea acestui număr de port se face în fişierul de configurare $CATALINA_HOME/conf/server.xml unde se găseşte secvenţa următoare:

332

<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --> <Connector className="org.apache.catalina.connector.http.HttpConnector" port="8080" minProcessors="5" maxProcessors="75 enableLookups="true" redirectPort="8443" acceptCount="10" debug="0" connectionTimeout="60000"/>

Dacă doreşte, utilizatorul poate să modifice acest număr de port după care trebuie să relanseze Tomcat. Această modificare este absolut necesară pentru evitarea conflictelor de aşteptare la porturi, atunci când pe aceeaşi maşină mai mulţi utilizatori îşi lansează propriile containere Tomcat. Pe lângă acest port, containerul mai foloseşte încă cel puţin două porturi. Unul dintre acestea este portul de oprire Tomcat. La acest port containerul aşteaptă comanda de oprire. În fişierul de configurare $CATALINA_HOME/conf/server.xml apare:
<Server port="8005" shutdown="SHUTDOWN" debug="0">

Printr-o comandă:
TELNET adresaMaşinaTomcat 8005

se realizează conectarea la acest port, după care se tastează o linie cu conţinutul şirului specificat prin atributul shutdown (în cazul de mai sus este şirul SHUTDOWN). Astfel se poate comanda, eventual de la distanţă, oprirea Tomcat. Dacă se doreşte, se poate schimba portul sau şirul de comandă a opririi. Pe lângă aceste două porturi, Tomcat mai utilizează şi următoarele numere de port:
Număr port 8008 8443 8082 8081 8009 Rol Conexiune warp cu serverul Apache conexiune SSL HTTP/1.1 Conexiune non SSL HTTP/1.0 Conexiune serviciu proxy Conexiune AJP

Pe moment este suficient cât am prezentat despre gestiunea porturilor. Într-o secţiune următoare o să revenim pentru conexiunea cu Apache. După fixarea numerelor de porturi, practic containerul este instalat. Pentru a verifica că instalarea este bună, mai întâi se va porni containerul, după caz sub Unix sau sub Windows: ${CATALINA_HOME}/bin/startup.sh %CATALINA_HOME%\bin\startup.bat

333

Apoi se va lansa, pe maşina pe care s-a pornit containerul, http://localhost:8080, iar dacă s-a modificat portul atunci în loc de 8080 se va pune portul respectiv. Efectul trebuie să fie afişarea paginii din fig. 7.3.

Figura 7.3. Pagina de start Tomcat

Pagina cuprinde printre altele şi o documentaţie completă despre container, o documentaţie completă despre Servlet API, precum şi câteva exemple de servlet-uri însoţite de codurile lor sursă. ATENŢIE Asiguraţi-vă că navigatorul nu are setat proxy. În caz contrar, navigatorul va trimite cererea http la server-ul proxy, care va interpreta localhost ca o maşină pe care rulează server-ul proxy şi nu maşina pe care rulează containerul! 7.1.3.4. Contextul unei aplicaţii Servlet: definire şi creeare Într-o aplicaţie web pot să apară servlet-uri, clase Java, pagini JSP, documente html statice, applet-uri Java etc. Toate aceste resurse trebuie plasate într-un director, numit rădăcina aplicaţiei şi în subdirectoare ale acestuia, respectând o anumită structură. Pentru fixarea ideilor, vom defini o variabilă de 334

mediu cu numele WEBAPP_HOME. Valoarea ei va fi calea de la rădăcina sistemului de fişiere şi până la directorul rădăcină al aplicaţiei. De exemplu, WEBAPP_HOME poate avea una dintre valorile: WEBAPP=${CATALINA_HOME}/webapps/OAplicatie WEBAPP=d:/Florin/Carti/Servlet/OAplicatie În primul caz aplicaţia OAplicatie este plasată în spaţiul rezervat de Tomcat pentru aplicaţiile utilizatorilor, iar în al doilea caz ea este plasată undeva în sistemul de directori. (NB - Tomcat foloseşte separatorul de directoare /, indiferent dacă este pe Unix sau pe Windows). Din păcate (sau poate din fericire), aplicaţia web din $WEBAPP_HOME nu poate fi invocată prin specificare absolută:
http://adresamasina[:port]/$WEBAPP_HOME...

Adică nici una dintre specificările:
http://localhost:8080/C:/jakarta-tomcat-4.0.1/webapps/OAplicatie... http://localhost:8080/d:/Florin/Carti/Servlet/OAplicatie...

nu este acceptată de către Tomcat! Tomcat, ca de altfel orice container de servlet, foloseşte pentru specificări un mecanism de alias, prin intermediul conceptului de context. El poate fi privit ca un domeniu de vizibilitate, care poate fi accesat din resursele conţinute în cadrul aplicaţiei web. Fiecare aplicaţie web are un singur context, iar containerul trebuie să-i asigure acestuia securitatea necesară. De exemplu, două aplicaţii web distincte nu îşi vor putea accesa una alteia contextul. Pentru fiecare aplicaţie se va defini un context care va avea asociat un nume. Pentru fixarea ideilor, vom defini o variabilă de mediu WEBAPP_NAME care va conţine numele asociat contextului. O primă întrebare se impune: Cum se defineşte un context? Definirea contextelor şi a parametrilor de configurare a acestora se face prin intermediul tag-urilor <HOST şi <CONTEXT din fişierul $CATALINA_HOME/conf/server.xml. O a doua întrebare: Cum se leagă directorul aplicaţiei de context? O astfel de întrebare apare în mod firesc, deoarece aplicaţia se află în $WEBAPP_HOME, iar containerul (Tomcat) o vede ca $WEBAPP_NAME. Vom răspunde deodată la ambele întrebări.

335

definire caracteristici context prin taguri interioare .. Pe lângă aceste atribute mai sunt şi altele.- Un tag <HOST defineşte un host virtual. definit prin: <HOST name="localhost" appBase="webapps" . În interiorul tag-ului <HOST se definesc tag-urile <CONTEXT. > .</HOST> ..</CONTEXT> . Mai jos prezentăm şi alte modalităţi de creare de contexte.. alteAtr . directorul de aplicaţii indicat de acest host implicit este: $CATALINA_HOME/webapps O primă regulă relativă la crearea de contexte este aceea că toate subdirectoarele directorului de aplicaţii devin în mod automat contexte..<HOST name="adresaMasina" appBase="dirAplicatii" .. ne vom opri numai la două atribute principale: name şi appBase... Din tag-ul <CONTEXT ne interesează numai atributele path şi docBase. /> sau <CONTEXT path="/nume" docBase="caleReala" .Tag-ul <HOST defineşte pentru container un host virtual.. Fără să intrăm în detalii (utilizatorul poate consulta [87] sau comentariile din fişierul de configurare). alteAtribute . Schematic. 38. 84]. Distribuţia Tomcat are definit în fişierul de configurare numai un singur host virtual.. Maniera de specificare în cele două tag-uri este specifică limbajului XML [87... iar într-un tag <HOST apar mai multe tag-uri interioare lui...<CONTEXT path="/nume" docBase="caleReala" . numele contextului fiind acelaşi cu numele directorului. partea legată de definirea contextelor Tomcat este: ..... Atributul appBase defineşte prin dirAplicatii subdirectorul lui $CATALINA_HOME destinat să găzduiască aplicaţiile web.. 336 .. > . alteAtr .. > Aşa cum am arătat mai sus. Atributul name al lui specifică prin adresaMasina adresa reală a maşinii care găzduieşte host-ul virtual.

urmată de valoarea atributului appBase din <HOST. implicit când nu se specifică nici un context.. atunci se foloseşta un tag vid (în terminologia XML [84]): <CONTEXT path="/nume" docBase="caleReala" .. Dacă pentru definirea unui context sunt suficiente atributele din cadrul tag-ului.. adică: WEBAPP_HOME=caleReala Referirea la aplicaţie se face prin intermediul contextului. Exemple de creare a unor contexte: 1. toate specificate relativ. destinat gestiunii Tomcat.. adică: WEBAPP_HOME=$CATALINA_HOME/dirAplicatii/caleReala În cazul specificării absolute.. Distribuţia Tomcat vine cu trei contexte predefinite. Prin atributul docBase se specifică caleReala din sistemul de directori unde se află aplicaţia. În cazul specificării relative valoarea variabilei WEBAPP_HOME se obţine concatenând trei elemente: valoarea variabilei CATALINA_HOME....</CONTEXT> Şi acum răspunsul la ambele întrebări. alteAtribute .. valoarea variabilei WEBAPP_HOME este valoarea atributului docBase din <CONTEXT... Deci... astfel: http://adresamasinaTomcat:portTomcat/$WEBAPP_NAME/. alteAtr . /> Pentru definiri de tag-uri mai complexe. 337 .Din interiorul unui tag <HOST ne interesează doar tag-urile <CONTEXT cu ajutorul cărora se pot defini contexte pentru diferite aplicaţii. În continuarea URL-ului se pot specifica resurse din orice subdirectoare ale contextului. > . El se defineşte prin <CONTEXT path="" docBase="ROOT . Valoarea nume din atributul path al unui context este numele contextului. definit prin <Context path="/manager" docBase="manager" . ca mai jos: • Contextul vid. • Contextul manager. Specificarea caleReala poate fi făcută relativ la appBase sau absolut. se foloseşte o structură XML cu tag de început şi de sfârşit: <CONTEXT path="/nume" docBase="caleReala" . pentru o anumită aplicaţie vom avea WEBAPP_NAME=nume... încheiată cu valoarea atributului docBase din <CONTEXT.

se face prin: http://localhost:8080/TfJaW/. spre exemplu de pe maşina locală.. care conţine în el mai multe exemple demonstrative de lucru cu servlet şi cu JSP. Tomcat va avea grijă ca la prima încărcare a lui să desfacă automat arhiva în webapps/OAplicatie şi să creeze contextul cu numele OAplicatie. prin adresa IP. 2. 338 . găzduit în directorul standard de aplicaţii. referirea de pe maşina locală prin portul 8080 la o resursă din contextul examples. De pe o altă maşină... Se doreşte crearea unui context cu numele OAplicatie. De exemplu. munele acesteia va fi schimbat în OAplicatie.zip. referirea. /> 4. Apoi. La fel ca şi la punctul 2. la o resursă din contextul OAplicatie. numai că structura de directoare şi fişiere pentru aplicaţie poate fi pregătită în altă parte. În sfârşit.40.. aşa cum pretinde Tomcat. Apoi se creează din întreaga structură o arhivă zip cu numele OAplicatie. contextul se defineşte prin: <Context path="/TfJdW" docBase="d:/Florin/Carti" . se face prin: http://localhost:8080/examples/. Se doreşte. referirea este: http://193.. 3. pe o maşină Windows. definit prin <Context path="/examples" docBase="examples" . crearea unui context cu numele TfJaW (acrostih de la titlul prezentei cărţi) care să se refere la o aplicaţie găzduită în subdirectorul Carti al directorului Florin din rădăcina discului D:.. în $CATALINA_HOME/webapps directorul OAplicatie care să conţină structura de directori şi fişierele necesare aplicaţiei. Pentru aceasta este suficient să se creeze. spre exemplu de pe maşina locală..war şi această arhivă se va depune în $CATALINA_HOME/webapps... se face prin: http://localhost:8080/OAplicatie/.130:8080/TfJaW/...226. Pentru aceasta.• Contextul examples.. Cu notaţiile de mai sus vom avea EBAPP_HOME=d:/Florin/Carti şi WEBAPP_NAME=TfJaW Referirea la o resursă din acest context.

339 . referirea la resursă se face din contextul gazdă completat cu calea relativă până la resursă. În interiorul acestuia apar câteva fişiere şi directoare. În $CATALINA_HOME/webapps se creează un subdirector pentru aplicaţia respectivă. 4. atunci se defineşte un context nou. este următoarea: $WEBAPP_HOME $WEBAPP_HOME/WEB-INF/web. în conformitate cu specificaţiile Sun.xml se numeşte descriptor al aplicaţiei şi prin intermediul lui se pot fixa o serie de configurări pentru aplicaţia web respectivă: parametri de iniţialzare.war cu numele aplicaţiei. 3. 2. al cărui nume este dat de atributul path al tag-ului <CONTEXT. În acest caz. iar locul fizic este indicat prin atributul docBase al tag-ului.5.Rezumând problema contextului.3. • Directorul $WEBAPP_HOME/WEB-INF/ este folosit în aplicaţie numai prin intermediul containerului. caz în care contextul este creat automat.1. iar numele contextului va fi chiar numele directorului respectiv. cu numele de context WEBAPP_NAME pentru acces la container: 1. Tomcat va crea automat un subdirector pentru aplicaţia respectivă. În $CATALINA_HOME/webapps se depune o arhivă nume. iar numele contextului este chiar numele directorului respectiv. există patru posibilităţi prin care se leagă spaţiul fizic al unei aplicaţii WEBAPP_HOME. 7.xml $WEBAPP_HOME/WEB-INF/classes/ $WEBAPP_HOME/WEB-INF/lib/ • În directorul $WEBAPP_HOME se plasează resursele statice şi paginile JSP ale aplicaţiei. Dacă aplicaţia web este conţinută în alt loc în sistemul de fişiere. Structura de subdirectoare a unui context şi invocarea de resurse Structura de subdirectoare şi fişiere a unui context. O anumită resursă dintr-o aplicaţie este găzduită în interiorul unui context deja definit. Contextul unei aplicaţii devine operaţional odată cu pornirea containerului după configurare. • Fişierul $WEBAPP_HOME/WEB-INF/web.

Accesul la acest servlet se face folosind un alias intermediar care substituie construcţia WEBINF/classes. repornit containerul. de pe maşina locală. acesta va fi depus în $WEBAPP_HOME/WEBINF/classes/. Presupunând că avem un servlet ClasaServlet. prin: http://localhost:8080/examples/servlet/SessionExample Pentru multe dintre exemplele care urmează în acest capitol. după care referirea se poate face prin: http://masinaTomcat:port/$WEBAPP_NAME/images/poza.elemente de depanare etc. după care poate fi invocat prin: http://masinaTomcat:port/$WEBAPP_NAME/servlet/ClasaServlet Pentru a lansa.class. arhivele JAR. am definit un context numit pdpj (acrostih după Programare Distribuită pe Platforme 340 .jpg Accesarea unui servlet Aşa cum am precizat mai sus. Structura de directoare a unui aplicaţii web nu este rigidă.class pentru toate servlet-urile şi bean-urile folosite de aplicaţie. • Directorul $WEBAPP_HOME/WEB-INF/classes/ conţine fişierele de tip . acesta poate fi invocat. spre exemplu. driver-ele JDBC etc. În multe aplicaţii acest fişier coincide cu cel implicit livrat de distribuţia Tomcat. servlet-ul SessionExample. Programatorul poate să extindă această structură de directoare după cum doreşte. un servlet trebuie plasat în directorul $WEBAPP_HOME/WEB-INF/classes/. • Directorul $WEBAPP_HOME/WEB-INF/lib/ conţine clasele adiţionale. necesare rulării aplicaţiei web. De exemplu poate plasa imaginile aplicaţiei într-un director numit $WEBAPP_HOME/images/.class livrat odată cu distribuţia Tomcat. Accesul la o resursă statică Accesul la o resursă statică a aplicaţiei web poate fi invocată prin container folosind un URL de forma: http://masinaTomcat:port/$WEBAPP_NAME/numeResursa unde în loc de $WEBAPP_NAME apare numele contextului aplicaţiei.

. Serviciul TomcatStandalone funcţionează aşa cum am arătat în fig. 7. Sarcinile de natură statică vor fi transmise unui server web profesional.. Containerul Tomcat. În acest scop se foloseşte serviciului oferit de Tomcat-Apache. practica a demonstrat că Tomcat-Standalone nu face faţă rezonabil.. ca de exemplu Apache. Serviciul Tomcat-Apache funcţionează aşa cum am arătat în fig.2. 7. se recomandă înainte salvarea fişierului de configurare într-o copie de siguranţă. este suficient să se şteargă din fişierul de configurare liniile dintre <Service name="Tomcat-Apache"> şi </Service>. în interiorul acestuia am definit subdirectorul WEB-INF iar în acesta am creat directoarele classes. utilizatorul poate dezactiva complet serviciul Tomcat-Apache.xml din $CATALINA_HOME/ROOT/web.1 şi 7. ca la nevoie să poată fi refăcut.3.xml prin intermediul tag-urilor <SERVICE: <SERVICE name="Tomcat-Standalone"> .Java). în care pot să apară mulţi clienţi.4.-</SERVICE> <SERVICE name="Tomcat-Apache"> . 7. Pentru a reduce consumul de resurse Tomcat.</SERVICE> La pornirea Tomcat. De aceea se recomandă ca el să se ocupe doar de gestiunea servlet-urilor şi să fie degrevat total de partea statică (vezi fig.6. Pentru aceasta. Cele două moduri de lucru sunt descrise în fişierul de configurare $CATALINA_HOME/conf/server. Tomcat conectat la Apache Containerul Tomcat are definite două servicii. El este recomandat mai ales în faza de testare a unei aplicaţii.1. Pentru aplicaţii de anvergură.2). 7.1. integrat împreună cu 341 . 7. Evident. lib şi am copiat fişierul web. acesta anunţă pornirea celor două servicii ca în fig. Fereastra de pornire Tomcat Serviciul Tomcat-Standalone oferă containerului funcţionalităţi relativ reduse şi puţin performante ca şi server web. Mai întâi am creat directorul $CATALINA/webapps/pdpj.4. Figura 7.xml.

dă răspunsul către Apache.2). În interiorul acestui tag se defineşte conectorul Warp. cu nume de conexiuni diferite.. Dacă cererea invocă containerul. există un modul adiţional numit mod_webapp. Pentru fiecare maşină Tomcat la care se doreşte conexiune..</Service> În fişierul de configurare httpd. când Apache primeşte din exterior o cerere pentru o resursă care nu solicită containerul Tomcat (vezi fig./> .so (cazul Apache) sau mod_webapp. iar acesta la rândul lui răspunde clientului.. Pentru integrarea Tomcat cu Apache. Server-ul web caută în URL apariţia substring-ului "/$WEBAPP_NAME/". cererea este trimisă la Tomcat spre a fi 342 .apache. numărul de port (8008) va fi schimbat în cele două fişiere de configurare. atunci server-ul web trimite cererea containerului. trebuie dată câte o linie WebAppDeploy. este suficient să se păstreze în fişierul de configurare liniile prin care se defineşte serviciul Tomcat-Apache. sunt necesare mici configurări atât la Tomcat.connector. atunci cererea va fi deservită direct de Apache.<Connector className="org.so WebAppConnection numeConexiune masinaTomcat:8008 WebAppDeploy $WEBAPP_NAME numeConexiune /$WEBAPP_NAME/ Din punct de vedere formal. appBase="webapps" . Să numin $WEBAPP_NAME numele contextului aplicaţiei.catalina. cât şi la Apache. 7. de comunicare cu Tomcat.. care la rândul lui defineşte un port pe care ascultă cereri de la server-ul web. În caz că în URL apare acest substring imediat după specificarea maşinii şi a portului. Dacă este cazul. La nivel de server web.WarpConnector" port="8008". Partea aceasta din configurare este: <Service name="Tomcat-Apache"> . trebuie dată câte o linie WebAppConnection. Pentru partea Tomcat. Acesta o procesează. există o singură linie LoadModule. Pentru fiecare aplicaţie conectabilă la un Tomcat. Fiecare linie WebAppConnection defineşte o conexiune Warp (numeConexiune) la o anumită maşină Tomcat..conf al server-ului Apache trebuie adăugate câteva linii. Prin intermediul primei linii se comandă serverului web să încarce în memorie modulul adiţional corespunzător. Urmează câte o line WebAppDeploy pentru fiecare aplicaţie web conectabilă la Tomcat. pentru ca acesta să poată comunica cu conectorul Warp: LoadModule webapp_module libexec/mod_webapp. Astfel.server-ul Apache oferă performanţe mai bune pentru aplicaţii şi oferă aplicaţiilor web un mediu mai sigur de rulare.warp..dll (cazul Microsoft IIS)..

executată.// Tratarea cererii si pregatirea raspunsului .4.getOutputStream() pentru raspuns binar . Aplicaţia pe care o va rula acest Tomcat va fi $WEBAPP_NAME.getWriter() pentru raspuns text // raspuns.1.http.io. atunci cererea este executată de către Apache. import java.getInputStream() la cerere binara . Fragmentul de program sursă de mai jos prezintă schema cadru a părţii esenţiale a unui servlet..- 343 . rezidentă în directorul lui de aplicaţii webapps (indicată prin atributul appBase în <Connector). Apoi trebuie să întoarcă un răspuns cu respectarea protocolului HTTP. Din punct de vedere practic.// Obtinerea elementelor cererii. Dacă string-ul "/$WEBAPP_NAME/" nu apare. Funcţionarea unui servlet 7. public class UnServlet extends HttpServlet { public void doGet ( // Metoda GET // public void doPost( // Metoda POST HttpServletRequest cerere.4. un servlet reprezintă în programarea web o alternativă la CGI.*.getParameter(. marea majoritate a servlet-urilor extind subclasa HttpServlet a clasei Servlet. import javax. Cum arată un servlet? Aşa cum am mai spus. eventual prin: // cerere. import javax. Formal. Practic. ea fiind aliniată complet la protocolul HTTP. 7. HttpServletResponse raspuns) throws ServletException. primirea unei cereri şi întoarcerea răspunsului. IOException { ...) la cerere text // cerere..*. toate exemplele noastre folosesc clasa HttpServlet pentru proiectarea servlet-urilor.. Selectarea containerului Tomcat se face prin numeConexiune.*. POST etc.servlet.1.1.// Obtinerea unui obiect pentru trimiterea raspunsului: // raspuns..servlet. Asta înseamnă că trebuie să preia o cerere HTTP printr-una din metodele GET. un servlet este o clasă care extinde clasa Servlet şi utilizează metoda service a acestei clase pentru tratarea cererii şi a răspunsului.

în cazul metodei GET. Accesarea datelor transmise prin cererea clientului Pentru accesarea datelor transmise prin cererea trimisă de client. cum ar fi getParameterNames pentru obţinerea numelor câmpurilor. sau getParameterValues pentrua obţine toţi parametrii. cererea este dată printr-un string de cerere conţinând nume de câmpuri şi valori ale acestora.// Inchiderea obiectelor } // UnServlet.// Fixarea si trimiterea unor parametri din antetul raspunsului // Creearea si trimiterea corpului raspunsului . 51].2. 344 . 7. ca şi partea de distrugere a servlet-ului.doGet } // UnServlet Lipseşte de aici partea de iniţializare. opţională şi ea. obiectul cerere (de tip HttpServletRequest) permite obţinerea elementelor constitutive ale cererii. metoda service transmite cererea spre procesare.. Interacţiunea cu clienţii Un servlet gestionează cererile clienţilor cu ajutorul metodei service. În funcţie de metoda (GET sau POST) cu care a fost formulată cererea clientului. fie ca şi corp al cererii în cadrul metodei POST. care procesează cererile clienţilor.4. Comunicarea este făcută cu respectarea protocolului HTTP [86. În secţiunile următoare vom relua şi detalia elementele constitutive ale unui servlet.1. au două argumente: • un obiect HttpServletRequest care încapsulează datele transmise de la client. Acest string de cerere poate sosi fie ca opţiune adăugată la URL-ul cererii.. sub forma: nume1=valoare1&nume2=valoare2. De asemenea. Metodele din clasa HttpServlet. De cele mai multe ori.. String-ul de cerere nu trebuie parsat. valorile câmpurilor se obţin cu ajutorul metodei getParameter. în fapt nu întotdeauna prezentă. • un obiect HttpServletResponse care încapsulează răspunsul server-ului spre clienţi. Ea primeşte la intrare numele câmpului şi dă la ieşire valoarea acestuia. La nevoie mai pot fi folosite şi alte metode ale obiectului cerere. unor metode precum doGet sau doPost. 24.

servlet-ul fixează header-ul HTTP al mesajului de răspuns. care nu primeşte nici o cerere şi dă ca răspuns un text static. pentru a scrie date de tip text. Pentru accesarea acestora.1. În cazul metodei POST este posibil ca în corpul cererii să fie cod binar. ca alternativă la codul binar. public class Primul extends HttpServlet { public void doGet(HttpServletRequest cerere. Transmiterea răspunsului Obiectul răspuns (de tip HttpServletResponse parametru al metodei doGet sau doPost). Mai întâi.4.3. care întoarce un obiect Writer.servlet.1) vom presupune pentru primul servlet că ar putea eventual primi şi un string de cerere.1.există mai multe metode prin care se pot accesa valori din antetul (header-ul) cererii. • folosind metoda getOutputStream. pentru a scrie date binare. obţinut de la metoda getInputStream.*. Tot metoda POST permite. răspunsul către client. obiectul cerere permite obţinerea unui obiect IO de acces. obiectul cerere permite obţinerea unui obiect IO de acces.1. care întoarce un obiect ServletOutputStream. înglobează conform protocolului HTTP. De exemplu. Pentru accesarea acestuia. să aibă în corp linii text. 7. de tip BufferedReader. import java. import javax. import javax.servlet. obiectul HttpServletResponse oferă unul dintre următoarele două moduri de a transmite date: • folosind metoda getWriter. de tip ServletInputStream. metoda setContentType setează tipul conţinutului răspunsului.io.*.http. Primul exemplu şi compilarea unui servlet Cel mai simplu servlet este unul de tip HelloWorld. Pentru trimiterea corpului răspunsului.*. Sursa acestuia este dată în programul 7. obţinut de la metoda getReader. 345 .4. Pentru a fi în ton cu schema cadru (7.

} // Primul.jar javac -classpath "%CPATH%" *. out.3. out. out.java El este scris pentru platforma Windows.println("<HEAD>").getWriter().jar.close(). out.c:\%CATALINA_HOME%\common\lib\servlet.println("</BODY>"). următorul fişier de comenzi: set CPATH=.println("</HEAD>"). out. Imaginea afişată de navigator va fi cea din fig. 7.println("<HTML>").5. PrintWriter out = raspuns. Mai întâi vom apela: http://localhost:8080/test/servlet/Primul. Acesta va fi contextul pentru câteva dintre servlet-urile care urmează. out. 346 . spre exemplu.println("<TITLE>Primul servlet</TITLE>"). IOException { raspuns. După compilare.doGet } // Primul Programul 7.class al servlet-ului se depune în: %CATALINA_HOME%\webapps\test\WEB-INF\classes După restartarea Tomcat. această arhivă se află în $CATALINA_HOME/common/lib. eventual prin intermediul unui fişier de comenzi. compilatorul trebuie să poată accesa arhiva servlet.println("<BODY>"). pentru situaţii ocazionale. fişierul Primul.5.1. Primul.getQueryString()). ce poate folosi. out. out.. dar se poate adapta uşor la Unix. servlet-ul se poate apela sub diverse forme. Pentru exemplele (simple) care urmează. împreună cu structura descrisă în 7.println("Am primit: "+cerere.1.HttpServletResponse raspuns) throws ServletException. out.setContentType("text/html").java Pentru a putea compila un servlet. out. În cazul Tomcat. am creat un director cu numele test în %CATALINA_HOME%\webapps.println("<CENTER><H1>Salutare!</H1></CENTER>"). Utilizatorul poate: • să seteze permanent variabila de mediu CLASSPATH ca să includă această arhivă. • să copieze arhiva într-un subdirector vizibil prin CLASSPATH. • să compileze cu opţiunea -classpath.println("</HTML>").

6.5. navigatorul va interpreta răspunsul ca un text simplu şi va afişa imaginea din fig.7. Imaginea la client va fi cea din fig.Figura 7. 7. unde se poate vedea şi URL-ul de apel. Apel servlet Primul cu text/plain 347 .7.6. Figura 7. Apel al servlet-ului Primul Apelăm apoi servlet-ul de pe o altă maşină şi în plus îi transmitem şi ceva parametri.1) "text/html" cu "text/plain". Figura 7. Al doilea apel al servlet-ului Primul Să înlocuim în sursa servlet-ului Primul (programul 7. Prin aceasta. 7.

8. 348 . Primul.ubbcluj. Figura 7. Să creăm fişierul: <html> <head> <title>Inainte de servlet</title> </head> <body> <form method=get action=http://florin.2. Documentul HTML din programul 7.html în %CATALINA_HOME%\webapps\test\ relansăm Tomcat. 7.ro/florin/servlet/Primul> <input type=submit value= "Apelul servletului Primul"> </form> </body> </html> Programul 7. Containerul apelează metoda init a instanţei. distingem cinci momente esenţiale: 1. Apel Primul prin formular După ce se dă click pe butonul "Apelul servletului Primul".8. Containerul creează o instanţă a servlet-ului. Programul servlet se poate lansa şi dintr-un formular.4.html Depunem fişierul Primul.2 este un exemplu de apel al acestui servlet. 2.4. va apare imaginea cu salutul servlet-ului Primul. 7.1. după care apare imaginea din fig. Interacţiunea cu containerul Relativ la ciclul de viaţă al unui servlet în cadrul containerului.cs.Acelaşi servlet se poate apela şi prin intermediul unui formular.

Iniţializarea se termină înainte ca servlet-ul să răspundă la cererile clienţilor şi înainte ca servlet-ul să fie distrus. Instanţa este distrusă şi pusă la dispoziţia garbage collection. În cazul în care procesarea cererilor accesează o resursă partajată. se pot folosi următoarele tehnici: • Server-ul menţine un contor care indică câte thread-uri rulează metoda service în mod curent. 5. pentru a realiza diferite operaţii de iniţializare specifice acestuia. Înainte de distrugerea instanţei. el apelează metoda init. pentru închiderea unor fişiere etc. 4. Pentru aceasta. În cazul unor cereri care necesită un timp mai mare de procesare. Un servlet poate fi reîncărcat numai după ce a fost distrus de către destroy.3. de exemplu la cererea administratorului server-ului. eventual un interval maxim de timp. Înainte de apelul lui destroy. în servlet trebuie prevăzute secvenţe de sincronizare. La apariţia unei cereri. după care aşteaptă terminarea lor. servlet-ul trebuie să implementeze interfaţa SingleThreadModel. containerul aşteaptă. containerul apelează metoda destroy. se apelează metoda destroy. 349 . Această funcţie este oferită de clasa HttpServlet şi poate fi suprascrisă în servlet-ul curent. ca toate instanţele ce deservesc cereri ale clienţilor. Există posibilitatea de procesare a unei singure cereri la un moment dat. şi în caz afirmativ îşi încheie activitatea. să se încheie. Într-o secţiune viitoare vom reveni asupra iniţializărilor unui servlet. Servlet-urile sunt capabile să deservească simultan mai mulţi clienţi. • Un thread care procesează timp mai îndelungat verifică periodic dacă server-ul a primit o cerere de shutdown. Când containerul încarcă un servlet. La terminarea ciclului de viaţă a unui servlet. • Metoda destroy anunţă thread-urile care procesează aceste cereri că trebuie să-şi încheie activitatea. pentru eliberarea unor resurse. care nu presupune descrierea unor metode suplimentare. deoarece fiecare cerere este tratată într-un thread separat. Metoda destroy este apelată când acest contor ajunge la valoarea 0. Această metodă este oferită de clasa HttpServlet şi poate fi suprascrisă în servlet-ul curent. containerul creează un thread nou (se alimentează dintr-un pool intern de thread-uri) şi din acesta apelează metoda service a instanţei servlet-ului pentru tratarea cererii.

de lipsa unor drepturi de acces sau de prea multe drepturi de acces etc. deoarece este normal ca fişierele locale ale aplicaţiei să se afle în interiorul contextului. Directorul implicit al containerului este $CATALINA_HOME/bin. Pentru a obţine valoarea unui anumit parametru se apelează metoda getInitParameter. Accesul la un fişier prin specificare absolută. sunt căutate în acest director. Metoda este foarte bună.separatorChar. 2. Este metoda cea mai recomandată. De exemplu. acces la directorul implicit al containerului. Toate fişierele invocate de servlet prin numele lor. este foarte simplă. 1. Din păcate. să presupunem că am creat în contextul aplicaţiei un director $WEBAPP_HOME/FisiereLocale/.separatorChar+ "FisiereLocale"+File. numele acestora poate fi obţinut apelând în funcţia init metoda getParameterNames(). Accesul unui servlet la resurse locale se face prin intermediul containerului. accesul la directorul implicit al aplicaţiei. citarea oricărui fişier din acest director se poate face prin: cale+"numeFisier" 3. sau printr-o cale relativă.getRealPath(""). la orice mutare a unui fişier dintre cele folosite de aplicaţie trebuie să se intervină în textul sursă. 3. Cel mai simplu este să se depună fişierele în interiorul contextului aplicaţiei. În faza de iniţializare servlet-ul fixează calea absolută spre aceste fişiere astfel: String cale = getServletContext(). dar în cazul unui container utilizat de către mai mulţi useri pot să apară dificultăţi legate de suprapunere de nume. destinat special fişierelor locale ale aplicaţiei. acces în orice loc al sistemului de fişiere prin specificare absolută. 2.Dacă pentru servlet au fost specificaţi parametri de iniţializare. Acest neajuns poate fi evitat dacă aceste specificări absolute sunt transmise la iniţializare ca şi parametri de configurare a aplicaţiei. După aceea. adică prin indicarea întregii căi de la rădăcină şi până la fişier. 350 . iar pentru accesul la ele este indicată una dintre următoarele trei metode: 1. având ca argument numele parametrului. Cele mai importante resurse locale sunt fişierele. servlet-ul să îşi determine mai întâi calea reală până la context. după care să citeze fişierele prefixate cu această cale. cale = cale+File.

1. Configurarea şi iniţializarea servlet-urilor. Fişierul de configurare pentru exemplul nostru va fi: 351 .xml Acest fişier mai poartă numele de "Deployment Descriptor" al aplicaţiei.3. Ne propunem. folosind standardul XML. Fişierele class ale celor două servlet-uri rămân cele iniţiale.com/dtd/web-app_2_3. În mod analog. Exemple Am văzut cum se face configurarea containerului prin modificarea fişierului lui de configurare: $CATALINA_HOME\conf\server.3//EN" "http://java.xml.4. de specificare a unor elemente de securizare etc. o serie de informaţii specifice pentru servlet-urile sau fişierele . În el sunt trecute.5. Dacă nu se introduce nici o informaţie de configurare. Ne propunem ca prin configurare să asociem nişte nume aliate celor două servlet-uri. iar al doilea va mai avea şi numele CuInit.5) fişierul web. fiecare aplicaţie NU fiecare servlet. ca servlet-ul CuInit să preia un parametru de iniţializare numit MAXIM cu valoarea 12.4.sun. Un astfel de fişier poate fi preluat din distribuţia Tomcat şi el are conţinutul: <?xml version="1.7.xml care se depune în structură se recomandă să fie unul fără conţinut semnificativ. Unul este servlet-ul Prim descris mai sus în programul 7.java ce se poate vedea mai jos în programul 7. în contextul test două servlet-uri. Primul va avea în plus numele First şi Unu.1 şi servlet-ul care are sursa ServletCuInit.1. de specificare a utilizării unor filtre. de asemenea.dtd"> <web-app> </web-app> Acest fişier se găseşte în distribuţie la: $CATALINA_HOME/webapps/ROOT/WEB-INF În funcţie de necesităţile de configurare.jsp din cadrul aplicaţiei. Inc. În cele ce urmează vom prezenta doar câteva elemente de configurare şi iniţializare.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems. are un fişier de configurare: $WEBAPP_HOME/WEB-INF/web. Nu vom intra în detalii. între tag-urile <web-app> şi </web-app> vor fi introduse construcţiile XML necesare. presupunem că avem.//DTD Web Application 2. Este vorba de o serie de parametri de iniţializare furnizaţi prin perechi nume . ci lăsăm cititorul să consulte [87. 51] pentru amănunte.valoare. Trebuie să precizăm din capul locului că la crearea structurii de directori a contextului (7. atunci în loc de perechea <web-app> </web-app> se poate scrie un tag XML vid: <web-app/> În cele ce urmează.

*. Considerăm că fişierul are un conţinut foarte sugestiv.3.xml Conţinutul lui este prezentat în programul 7.3.xml (aplicaţia test) Toate tag-urile XML din acest fişier au semnificaţie precisă pentru Tomcat. import javax.http.init public void doGet(HttpServletRequest cerere. Informaţiile concrete de configurare sunt date ca şi conţinuturi ale celor mai interioare tag-uri.println("Initializare.com/dtd/web-app_2_3.sun.3//EN" "http://java.servlet. import java.parseInt(config.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems. int numarMaxim. Numarul maxim de "+ "afisari la Tomcat este: "+numarMaxim). HttpServletResponse raspuns) 352 . web. public void init(ServletConfig config) { numarMaxim = Integer.io.%CATALINA_HOME%\webapps\test\WEB-INF\web.java.dtd"> <web-app> <servlet> <servlet-name>First</servlet-name> <servlet-class>Primul</servlet-class> </servlet> <servlet> <servlet-name>Unu</servlet-name> <servlet-class>Primul</servlet-class> </servlet> <servlet> <servlet-name>CuInit</servlet-name> <servlet-class>ServletCuInit</servlet-class> <init-param> <param-name>MAXIM</param-name> <param-value>12</param-value> </init-param> </servlet> </web-app> Programul 7. motiv pentru care nu îl mai comentăm. System. <?xml version="1.out. import javax.*.*.4 prezentăm sursa ServletCuInit. public class ServletCuInit extends HttpServlet { int numarApeluri=0.getInitParameter("MAXIM")).//DTD Web Application 2. } // ServletCuInit. În programul 7.servlet. Inc.

În apelurile următoare se vor afişa. Scopul lui este de a demonstra folosirea metodei init.println("</HEAD>").9. Figura 7.close().out. Începând cu cel de-al 13-lea apel.println("<CENTER><H1>Salutare!</H1></CENTER>"). până la 12 inclusiv.println("</BODY>").getWriter(). IOException { raspuns.println("Apelul nr: "+numarApeluri). ServletCuInit. out.9.throws ServletException. numarApeluri++. out.println("</HTML>").doGet } // SevletCuInit Programul 7.println într-o aplicaţie web! De fapt. toate aceste tipăriri sunt efectuate pe consola de lansare Tomcat. liniile de apel. la primul apel al servlet-ului CuInit se va afişa linia de iniţializare şi linia cu apelul nr: 1. out.1. PrintWriter out = raspuns.java Acest servlet este obţinut prin adaptarea programului 7. nu se mai afişează linii pe consola Tomcat. 353 . out.println("<HEAD>").println("Am primit: "+cerere. Fereastra Tomcat la apelurile CuInit După liniile de pornire a Tomcat. 7. Cititorul poate fi surprins de prezenţa unor tipăriri System.4. destroy(). out. if (numarApeluri <=numarMaxim) System.println("<BODY>"). out.println("<TITLE>Primul servlet</TITLE>"). out. Acest exemplu arată că metoda init este apelată doar o singură dată.setContentType("text/html"). out. Afişările pe această consolă sunt prezentate în fig.getQueryString()).println("<HTML>"). aşa după cum prevede programul. out. out.out. } // ServletCuInit.

Uşurinţa proiectării: Putere: Portabilitate: Java este un limbaj perfect portabil. evident.9 se obţine doar dacă în URL-ul de apel este de forma: .5. toate containerele sunt perfect compatibile între ele.Din cauza schimbărilor de nume din această aplicaţie. se pot folosi atât numele atribuite prin configurare. în timp ce CGI-urile nu prea. ceea ce.. sunt pe bază de licenţă etc. cu o observaţie: Comportarea din fig.1. În cazul apelurilor de servlet. deci aplicaţiile pot fi transportate fără probleme între platforme. În cazul servlet-urilor. inclusiv Apache. În schimb. înseamnă consum mult mai mic de resurse.1. deoarece metoda getInitParameter nu va găsi parametrul MAXIM! 7.1. Soluţii ieftine: Java.5. cel puţin din următoarele motive: Eficienţa: Pentru fiecare apel de CGI. acestea „fac” întreaga regie în locul programatorului. 354 . În consecinţă.. cu tot ce ţine de ea.-/servlet/CuInit Dacă în locul lui se apelează: . Parametrii de cerere şi răspuns din servlet-uri oferă numeroase posibilităţi de colaborare cu serverul Web. Avantajele Servlet faţă de CGI Utilizarea tehnologiei servlet este mai avantajoasă decât utilizarea CGIurilor clasice.-/servlet/ServletCuInit atunci Tomcat va arunca o excepţie în prima linie a metodei init. Este evident că servlet-urile sunt mult mai uşor de proiectat decât CGI. JVM creează doar un nou thread. Dezvoltarea unui CGI în Perl sau C reclamă respectarea unui număr mare de restricţii. server-ul Web lansează un nou proces. Servlet-urile Java pot să comunice uşor cu servlet-ul Web. sunt produse free. platformele tradiţionale. cât şi numele de clasă ale servlet-urilor. Servlet vis-a-vis cu CGI 7. 7.

getRemoteAddr() request. uzual GET sau POST.getMethod() HEAD.getContentLength() numărul de octeţi trimişi Tipul MIME ataşat datelor request. În tabelul următor am presupus că request este parametrul cerere pentru service. Ca mai sus.getQueryString() deoarece cererea are metoda request. întoarce şirul cerere codificat de client. TRACE.1.getRemoteHost() QUERY_STRING REMOTE_ADDR REMOTE_HOST REMOTE_USER Partea user. corespun. Variabilă CGI AUTH_TYPE CONTENT_LENGTH CONTENT_TYPE DOCUMENT_ROOT HTTP_XXX_YYY Semnificaţie Acces din doGet sau doPost Furnizează tipul de autorizare. request. doGet sau doPost din servlet. nu este request.getServletPath() REQUEST_METHOD SCRIPT_NAME 355 .7. dacă se foloseşte request. PUT.getPathInfo() cu server-ul web. poate discuta request.getRemoteUser() autorizarea Intoarce metoda de cerere. DELETE.getAuthType() dacă există Numai pentru cereri POST. Deoarece servlet-ul. OPTIONS. dar ocazional request. Acces la variabilele de mediu CGI Pentru păstrarea completă a compatibilităţii cu CGI. Acest tabel dă funcţiile şi corespondenţele necesare accesului la aceste variabile. spre deosebire de CGI. request.getPathTranslated() necesară la servlet Pentru cereri GET. nu este necesară tratarea separată a acestei informaţii Map-area reală a unei informaţii PATH_TRANSLATED path.getServletContext(). Calea spre servlet request.getParameter Adresa IP a clientului Adresa Internet a clientului request. dă request. zătoare lui http://host/ getRealPath("/") Acces la un antet oarecare HTTP request.getHeader( "Xxx-Yyy") PATH_INFO Informaţia path ataşată unui URL.getContentType() Calea spre director.5.2. Rar este necesară parsarea şirului. clasele de definire şi utilizare a servlet-urilor deţin instrumentele necesare accesului la toate variabilele de mediu oferite CGI-urilor.

{ "SERVER_PROTOCOL". public class ShowCGIVariables extends HttpServlet { public void doGet(HttpServletRequest request. String.getServerPort()) }.*.getPathInfo() }. getServletContext().getMethod() }. javax.http.1).servlet. { "PATH_TRANSLATED". request.getQueryString() }. { "PATH_INFO". request. out. getServerInfo() Programul 7.getRemoteAddr() }. request.setContentType("text/html").getServerInfo() } }. { "REMOTE_USER". request.println("<html><head><title>"+ "Variabilele CGI</title></head>" + "<BODY>\n" + "<H1 ALIGN=CENTER>Variabilele CGI</H1>\n" + "<TABLE BORDER=1 ALIGN=CENTER>\n" + "<TR>\n" + "<TH>Variabla CGI<TH>Valoare").getServerName() request. { "SERVER_NAME".*. HttpServletResponse response) throws ServletException.getWriter().Variabilă CGI SERVER_NAME SERVER_PORT Semnificaţie Numele server-ului Web Portul la care aşteaptă server-ul Acces din doGet sau doPost request.io.getRealPath("/") }. request. 356 .getRemoteHost() }. request. SERVER_SOFTWARE Informaţii despre server-ul Web getServletContext(). { "REMOTE_ADDR".getPathTranslated() }.5 afişează conţinutul variabilelor CGI dintr-un servlet. { "CONTENT_TYPE". { "QUERY_STRING".getContentLength()) }. { "REQUEST_METHOD".getServletPath() }.getContentType() }. IOException { response. getServletContext().*.*. import import import import java. { "DOCUMENT_ROOT". { "REMOTE_HOST". request. { "SERVER_SOFTWARE". { "SCRIPT_NAME". request.getRemoteUser() }. PrintWriter out = response.getProtocol() ( HTTP/1. { "SERVER_PORT". { "CONTENT_LENGTH". String[][] variables = { { "AUTH_TYPE". String.servlet.getAuthType() }. request.util.getServerName() }.valueOf(request. request.getServerPort() Name şi versiunea protocolului SERVER_PROTOCOL de cerere request. java. request. javax.valueOf( request.getProtocol() }.0 sau HTTP/1. request.

doPost } // ShowCGIVariables Programul 7. ShowCGIVariables. } // for out. i++) { String varName = variables[i][0]. 7. out.println("</TABLE></BODY></HTML>").length. Figura 7.10. response).println("<TR><TD>" + varName + "<TD>" + varValue).java Execuţia servlet-ului va avea ca rezultat imaginea din fig.for(int i=0. HttpServletResponse response) throws ServletException. if (varValue == null) varValue = "<I>(NESPECIFICATA)</I>". } // ShowCGIVariables. } // ShowCGIVariables.10. Lista variabilelor CGI 357 . i<variables. IOException { doGet(request.5.doGet public void doPost(HttpServletRequest request. String varValue = variables[i][1].

7. 7. Figura 7. apelat prin GET şi prin POST Vom construi un servlet simplu care primeşte de la un formular client două numere (reprezentate prin string-uri) şi întoarce cel mai mare dintre acestea. Formularul prezentat de navigator este prezentat în fig. <html><head><title>Maximul a doua numere</title></head> <body><form action="http://localhost:8080/pdpj/servlet/Maxim" method="get" > <p>Primul numar:<input type="text" name="unu"> <p>Al doilea:<input type="text" name="doi"> 358 . Exemple de aplicare GET.1. Formular pentru Maxim Textul HTML al formularului este prezentat în programul 7.11.11. session etc.xml vid. inclusiv fişierul web. Facilităţi specifice servlet În acestă secţiune vom prezenta exemple de lucru cu metoda GET şi POST. creată prin crearea directorului: %CATALINA_HOME%\webapps\pdpj Odată cu el s-a creat întreaga structură de sub el. Toate exemplele sunt rulate într-o aplicaţie cu numele pdpj. forward 7.2.2. facilitatea forward pentru servlet-uri. 7. Servlet-ul Maxim. cookies. POST.1.2.1.6.

out.servlet.println("</BODY></HTML>").<p><input type=submit value= "Maxim"> </form></body></html> Programul 7. HttpServletResponse res) throws ServletException. răspunsul servlet-ului ajunge la client aşa cum se vede în fig.http. De aceea se observă în URL-ul cererii către servlet că. import javax. apare string-ul care reprezintă cererea.println("<CENTER><H1>Maxim("+unu+".getParameter("doi")). import java.io.7.getParameter("unu")). Figura 7.*.parseInt(req. IOException { int unu. Rezultatul apelului Maxim Metoda de cerere este GET."+doi+ ")= "+((unu>doi)?unu:doi)+"</H1></CENTER>"). public class Maxim extends HttpServlet { public void doGet(HttpServletRequest req.html După apăsarea butonului <Maxim>. out.setContentType("text/html").6. 359 .getWriter(). out. 7. out.servlet. începând cu semnul de întrebare. Textul sursă al servlet-ului este prezentat în programul 7. res. out.*. doi = Integer. Maxim.parseInt(req.*.println("<TITLE>Maximul a doua numere</TITLE>").println("</HEAD><BODY>"). PrintWriter out = res.12. unu = Integer.12. doi. import javax.println("<HTML><HEAD>").

penultimele patru linii ale textului sursă al servlet-ului nu sunt necesare! Dacă utilizatorul doreşte ca în acest exemplu să comunice prin metoda POST.2. IOException { doGet(req.doPost } // Maxim Programul 7. } // Maximum.getQueryString(). În linia a cincea a sursei servlet se va înlocui doGet cu doPost.*. String nume. javax.*. 360 .servlet.*.servlet. import import import import javax.doGet public void doPost(HttpServletRequest req. java. HttpServletResponse res) throws ServletException.*. atunci sunt necesare doar două modificări: 1. HttpServletResponse res) throws ServletException.util.2. res). în funcţie de cum i se transmite de la client.io. În linia a doua a formularului HTML trebuie înlocuit method=”GET” cu method=”POST”.close().7.out.8. Maxim. Cu penultimele patru linii (definirea lui doPost prin doGet – sau este posibil şi invers) prezente în sursa servlet-ului. Servlet-ul DisplayQueryString Servlet-ul care urmează este unul simplu: el primeşte prin metoda GET un şir de cerere oarecare şi îl afişează ca răspuns pe navigatorul clientului. mai puţin string-ul de cerere care nu va apare în URL. 7. IOException { StringTokenizer st = new StringTokenizer(req. răspunsul de pe navigator va coincide cu cel de la GET. 2. java. } // Maxim. public class DisplayQueryString extends HttpServlet { public void doGet(HttpServletRequest req.java Pentru apelul prin metoda GET. "&").http.1. servlet-ul acceptă oricare dintre metodele de cerere. Făcând aceste modificări. Textul sursă al servlet-ului este dat în programul 7.

2. out. ne inspirăm după servlet-ul Maxim prezentat 361 . out.println("<CENTER><H1>Urmeaza "+st.nextToken(). } // DisplayQueryString. 7.hasMoreTokens().println("<HTML><HEAD>").1.3.println("<P>"+nume+"</P>"). out. out.println("</HEAD><BODY>"). DisplayQueryString.close(). out. } // for out.doGet } // DisplayQueryString Programul 7. for ( . Pentru a exemplifica. st.13 este prezentat un exemplu de apel al acestui servlet: Figura 7. Este vorba de posibilitatea ca dintr-un servlet să se apeleze alt servlet. out.getWriter().setContentType("text/html").countTokens()+ " parametri</H1></CENTER>").8.13. PrintWriter out = res.println("</BODY></HTML>"). ) { nume = st.println("<TITLE>Argumentele de apel</TITLE>"). Rezultatul DisplayQueryString 7.res.java În fig. Servlet-ul MaximForward Servlet-ul care urmează exemplifică una dintre facilităţile oferite de către tehnologia servlet.

*.*.io. IOException { ServletContext sc = getServletContext(). unu = (unu>doi)?unu:doi. rd.getRequestDispatcher("/MaximError. import java. import javax. În exemplul nostru.parseInt(sdoi).http.9.getRequestDispatcher( "/servlet/DisplayQueryString?maxim="+unu). sunu = req.getParameter("unu").res). if ((sunu==null)||(sdoi==null)) { rd = sc.*. Apoi cere acestuia din urmă retransmiterea unei cereri şi a unui răspuns către noua resursă.mai sus şi vom crea un nou servlet. servlet-ul cere obiectului său context o instanţă a dispecerului de cereri (gestionat de container).res). rd = sc. doi. HttpServletResponse res) throws ServletException. String sunu. sdoi = req. rd. int unu. ori spre un server. furnizat de obiectul ServletContext. care transmite cererea de forward ori spre o resursă statică a server-ului web. Pentru realizarea de forward. MaximForward.parseInt(sunu). MaximForward va folosi două obiecte speciale: • Un obiect de tip ServletContext care deţine elementele necesare realizării acţiunii de forward.9. Pentru aceasta.forward(req. care va fi unul din două posibile. va transfera spre tratare altei componente. } else { unu = Integer.getParameter("doi"). • Un obiect de tip RequestDispatcher. public class MaximForward extends HttpServlet { public void doGet(HttpServletRequest req.servlet.servlet. } // if } // MaximForward. RequestDispatcher rd. iar pentru răspuns. sdoi. import javax.forward(req.doGet } // MaximForward Programul 7.java Prezentul servlet primeşte parametrii cererii.html"). doi = Integer. Noul servlet va purta numele MaximForward şi sursa lui este prezentată în programul 7. vom introduce în 362 .

atunci servlet-ul face forward către resursa MaximError.2. În cazul în care string-ul de cerere este corect. Elemente specifice de comunicare Este natural ca între un client applet şi un servlet să existe o comunicare de o factură mai deosebită.2.html. după care o citire şi atât! Dacă se doresc schimburi multiple. deoarece este vorba de doi protagonişti Java. În mod natural. care vor comunica cu instanţe thread diferite ale servlet-ului. clientul poate să facă. prezentat în programul 7. trebuie sa dati doi parametri</h3> </body> </html> Programul 7. transmiterea de obiecte este posibilă doar folosind metoda de cerere POST. MaximError. Dacă acesta nu este corect. protagoniştii îşi pot transmite unul altuia obiecte Java! Evident. atunci determină valoarea maximă. eventual o scriere.%CATALINA_HOME%\webapps\pdpj\ resursa statică constituită din documentul MaximError.2.10. <html><head><title>Eroare Maxim</title></head> <body> <h3>Ne para rau.html Apoi servlet-ul MaximForward verifică dacă string-ul cerere venit de la client este corect.10. aşa cum am arătat la CGI. aceştia pot să-şi construiască pentru comunicare obiecte ObjectInputStream şi ObjectOutputStream. atunci acestea vor fi făcute prin intermediul unor URLConnection diferite. Lăsăm pe seama cititorului să testeze modul de comportare a acestui ansamblu de resurse statice şi de servlet-uri. 363 . Cu acestea din urmă. literatura tratează prea puţin acest subiect [31] 7. conform rigorilor protocolului URLConnection (parte din HTTP). după care lansează o cerere GET cu răspunsul către servlet-ul DisplayQueryString prezentat în secţiunea precedentă. 7. În plus. În plus. Comunicare applet . un applet poate contacta un servlet folosind URLConnection.servlet Deşi este cel mai natural mod de comunicare Java peste web.html de mai sus.1.2. cu tot ce am prezentat acolo.

2. Clientul Applet2Servlet Elementele acestui client sunt documentul HTML din programul 7. 7. cel puţin insolit. de programare Java. cât şi fişierul class al applet-ului trebuie depuse (în cazul nostru) în: %CATALINA_HOME%\webapps\pdpj\ Prin acest exemplu mai ilustrăm încă un element. datorită eleganţei cu care se lucrează. int i. 364 . Applet2Servlet.*.*.2 (transformarea unui şir prin CGI).applet.În mai multe dintre exemplele care urmează am preferat schimbul de obiecte între applet şi servlet. ObjectInputStream in.11 şi applet-ul a cărui sursă este prezentată în programul 7. Arătăm o modalitate simplă prin care un applet citeşte din documentul HTML invocator un număr variabil de parametri. Vom începe printr-un exemplu simplu. Atât documentul HTML.2.2.io.12.7. java.*.11. java.awt.class" width=500 height=300> <param name="Linia1" value="Aceasta este linia 1"> <param name="Linia2" value="Aceasta este linia 2"> <param name="Linia3" value="Aceasta este linia 3"> <param name="Linia4" value="Aceasta este linia 4"> <param name="Linia5" value="Aceasta este linia 5"> <param name="Linia6" value="Aceasta este linia 6"> <param name="Linia7" value="Aceasta este linia 7"> <param name="Linia8" value="Aceasta este linia 8"> <param name="Linia9" value="Aceasta este linia 9"> <param name="Linia10" value="Aceasta este linia 10"> <param name="Linia11" value="Aceasta este linia 11"> <param name="Linia12" value="Aceasta este linia 12"> </APPLET></body></html> Programul 7.net. java.html import import import import java. TextArea raspuns = new TextArea(). reluare a exemplului prezentat în 4. Applet2Servlet extends Applet { public class public void init() { URL url. ObjectOutputStream out. <html><head><title>Aplet ce apeleaza un Servlet</title></head> <body><APPLET code="Applet2Servlet.*. URLConnection urlCon.

În ea îşi creează din obiectul cerere un obiect ObjectInputStream.String s="".2. urlCon.init } // Applet2Servlet Programul 7.java Mai întâi.html liniile pe care le va transmite servlet-ului spre a le transforma în litere mari.setText(s).setVisible(true).getOutputStream()). Se creează un obiect out de tip ObjectOutputStream prin intermediul căruia se trimite obiectul String la servlet.2. try { for (i=1.add(raspuns).readObject(). out. Apoi se deschide conexiunea URL. un obiect de tip String.openConnection(). va primi un obiect String şi va întoarce obiectul String cu toate 365 .3. Din toate aceste linii la applet se formează un singur string.setDefaultUseCaches(false). l. 7. fără staţionări prin zone catch.12. i++) s += l+"\n".setDoOutput(true). Applet2Servlet. Servlet-ul Servlet2Applet Perechea servlet pentru clientul prezentat mai sus este extrem de simplă. iar din obiectul răspuns un obiect ObjectOutputStream. Acesta este apoi depus pentru a fi afişat pe navigator.getHost()+ ":8080/pdpj/servlet/Servlet2Applet").close(). iar transmisia să se facă direct.setUseCaches(false). Pentru partea a doua – receptarea răspunsului. // Depune liniile de raspuns } // try catch(Exception e) { e. // Deschide conexiunea urlCon.close(). // Fa applet-ul vizibil raspuns. url = new URL("http://"+getCodeBase(). out.getInputStream()). clientul applet îşi extrage din tag-urile <PARAM existente în a. in. se configurează aşa încât pe ea să se poată citi şi scrie. in = new ObjectInputStream(urlCon. folosind obiectul in de tip ObjectInputStream. pereche cu cele duale din applet. urlCon = url. El suprascrie metoda doPost. applet-ul citeşte de la servlet.writeObject(s). urlCon. // Adauga obiectul la applet this. this. } // catch } // Applet2Server. // Permite si scrierea in resursa out = new ObjectOutputStream(urlCon.printStackTrace(). Prin intermediul acestora. ((l = getParameter("Linia" + i))!= null). s = (String)in.

el se aseamănă foarte mult cu cel din fig.12. import javax.class în: %CATALINA_HOME%\webapps\pdpj\WEB-INF\classes şi restartarea Tomcat.writeObject(s). import java.close().close().io.*. Servlet2Applet. in.printStackTrace().flush(). String s = (String)in.servlet. s = s.13. out. 7.toUpperCase(). } // try catch (ClassNotFoundException e) { e. HttpServletResponse res) throws ServletException. ObjectOutputStream out = new ObjectOutputStream(res.doPost } // Servlet2Applet Programul 7.http.*. 366 .literele transformate în litere mari. out.14.*.readObject().13.getOutputStream()). 4.servlet. } // catch } // Servlet2Applet. IOException { try { ObjectInputStream in = new ObjectInputStream(req. public class Servlet2Applet extends HttpServlet { public void doPost(HttpServletRequest req.getInputStream()). În mod firesc. out. efectul execuţiei este cel din fig. Sursa servlet-ului este prezentată în programul 7.java După depunerea fişierului Servlet2Applet. import javax.

Figura 7.14. Efectul apelului applet <--> servlet 367 .

valoare). server-ul Web se poate folosi de aceste informaţii. Ca şi cifre aproximative. se poate consulta: Edit / Preferences / Privacy & Security / Cookies / manager / Cookies manager. Pentru Mozilla. permit vizualizarea acestora. ca de exemplu Mozilla. • optimizarea căutării frecvente a unor informaţii – reţinerea unor parametri mai des invocaţi.1.3. Prelucrarea cookies în servlet trebuie să respecte anumite cerinţe. La un nou apel al browserului spre server-ul web. spaţiul total limitat la 4Ko etc.2. Un element de mare nesiguranţă privitor la cookies este faptul că orice utilizator al unui navigator poate să-i comande acestuia ştergerea cookies! Pentru informaţii privind cookies la Internet Explorer. Altele. Utilizare cookies 7. Cookies nu se pot vizualiza în IE. titularul lor este server-ul generator. utilizatorul poate consulta: Tools / Internet options / Delete cookies. Analog.2. Deoarece cookies sunt transmise prin header-ul cererii. mecanismul este folosit adesea pentru a depăşi restricţia comunicării fără stare (stateless client/server communication) între browser şi server-ul web. Trebuie reţinut faptul că deşi navigatorul găzduieşte cookies. • ajustarea parametrilor unui site în funcţie de clientul care îl consultă. spaţiul rezervat pentru cookies este limitat. Prin acest mecanism. De fapt. un cookie este o pereche de forma (nume. browser-ul le returnează neschimbate server-ului generator. atunci când servlet-ul transmite cookies spre navigator. Noţiunea de cookie Cookies sunt mici informaţii textuale pe care un server web le generează şi le trimite la un browser spre a fi accesate ulterior.7. Din păcate. Mai mult. acestea trebuie citite primele. 368 .3. unele browsere acceptă maximum 20 cookies/site şi 300 total. înainte de citirea parametrilor. deşi comunicarea web este fără stare. reprezentate ASCII şi fără spaţii în interiorul lor. Printre sarcinile pe care informaţiile cookie le pot îndeplini enumerăm: • identificarea unui user în timpul unei sesiuni e-commerce. Din punct de vedere formal. • controlul username – password în doi paşi. • controlul unor elemente de protecţie şi securitate a comunicaţiei între browser şi server-ul web. unele browsere nici măcar nu permit vizualizarea acestor cookies. acesta trebuie să trimită mai întâi cookies şi abia apoi răspunsul efectiv.

java. Cookie c. // numele parametrilor sunt puse in vector for ( i=0.hasMoreElements(). IOException { int i. k.io. Concret. e. if (k >=0 ) { // un nume de parametru coincide cu un nume de Cookie tc[i].3.servlet.14.util. 369 .getName()). HttpServletResponse res) throws ServletException. v.nextElement())). java.*.getValue()))).length.Nu intenţionăm să prezentăm API cookies. Sursa acestui servlet este prezentată în programul 7. public class CookieCountParameters extends HttpServlet { public void doGet(HttpServletRequest req.setContentType("text/html").setMaxAge(60*60*24*365). i<tc.2. servlet-ul îşi propune să contorizeze.add((String)e. de câte ori sunt invocate fiecare dintre nume care apar în cererile de la un anumit client (browser). i++ ) { k = v.getParameterNames().*.getCookies(). prin cookies. // Urmeaza depunerea Cookies vechi for ( i=0. for ( . i++ ) { tc[i]. i<tc. PrintWriter out = res. v. Exemplu de utilizare cookies Exemplul pe care îl prezentăm este de fapt o schemă cadru pentru servlet-uri care doresc să utilizeze cookies.http.*.remove(k). Cookie[] tc = req. valoare).setValue(""+(1+ Integer.*. } // if } // for // // Aici este locul pentru prelucrarea parametrilor de intrare // res.servlet. 7.2. vom prezenta în secţiunea următoare un exemplu de utilizare cookies care acoperă multe dintre aspectele de utilizare a acestora. // e contine toate numele // parametrilor Vector v = new Vector(). ştiut fiind că orice cerere de la un client este o pereche de string-uri (nume. // tc contine toate Cookies if (tc == null) tc = new Cookie[0]. În schimb.indexOf(tc[i].parseInt(tc[i].length. // Inca nu exista cookies Enumeration e = req. import import import import javax.getWriter(). javax.

addCookie(tc[i]).java Pentru realizarea scopului propus. aşa cum se vede în fig.println("</HEAD><BODY>"). out. out.getValue()+"</p>"). } // CookieCountParameters. for ( i=0. i<v.15. out.close(). după care se depun în vectorul v (pentru o prelucrare mai uşoară). 7.length. În final.println("<TITLE>Lista cookies</TITLE>"). în obiectul enumerare e se reţin numele câmpurilor din cerere. i++ ) out. i++ ) out. cât şi pentru cele noi şi adăugarea fiecăreia dintre ele în obiectul răspuns res.size().println("<h3>Cookies vechi</h3>").elementAt(i).size(). Valoarea fiecărui cookie este un întreg reprezentând de câte ori browser-ul a invocat în cereri numele respectiv.elementAt(i))+"</p>").println("</BODY></HTML>"). se dă ca răspuns un document HTML cu numerele tuturor cookies şi numerele lor de apariţie. 370 . numai pentru a se evidenţia pentru client acţiunea servlet-ului. } // for // // Aici este locul raspunsului HTML dat de servlet // out.println("<p>"+((String)v. i<tc. } // for // Urmeaza depunerea Cookies noi. i++ ) { c = new Cookie((String)v. După aceea. În cazul în care de la navigator nu vine nici un cookie. c. Se compară apoi numele cookies din tabloul tc cu numele de parametri cerere actuali din v. fiecare dintre cookies va avea drept nume exact numele care este transmis prin cerere. valoarea cookie corespunzătoare din tabloul tc este mărită cu o unitate şi numele respectiv este şters din vectorul v. ramase in v for (i=0.println("<h3>Cookies noi</h3>").getName()+ " = "+tc[i]. atunci tc va fi un tablou cu 0 elemente.14.println("<p>"+tc[i]. out. În caz de coincidenţă.setMaxAge(60*60*24*365).addCookie(c).println("<HTML><HEAD>").doGet } // CookieCountParameters Programul 7. CookieCountParameters. Pasul următor constă în fixarea vârstei maxime (un an) atât pentru cookie vechi. res. for ( i=0. i<v. "1"). out. out.res. Servlet-ul CookieCountParameters reţine în tabloul tc toate cookies primite de la navigator.

15.Figura 7. Numărarea parametrilor prin cookies 371 .

2. Exemplul care urmează ilustrează utilizarea obiectelor HTTPSession la counteri de pagini Web.. într-un fel sau altul dependente de client..”>. sub forma: <input type=”hydden” name=”session” value=”. aceste informaţii ajung la server care le poate interpreta ca şi obiecte de tip session. Informaţiile sunt păstrate la server sub forma unor perechi (nume . • simularea unei sesiuni prin intermediul construcţiilor „ascunse” la client. 372 . acţiunile: • răspunde dacă este un obiect nou sau nu (metoda isNew).4. printre altele. Conceptul de sesiune Obiectele HTTPSession au fost introduse pentru a permite.7. obiect).7. Un obiect HTTPSession poate desfăşura. Formal. • se pot depune obiecte cărora li se asociază nume (metoda setAttribute). • obiecte HTTPSession. telegrafic. 91]. • etc. toate celelalte fiind. • întreţinerea unui mecanism cookies cu fiecare navigator.1. 4.4.3 (contor de pagini Web). prin intermediul servlet-urilor. modalităţile prin care se obişnuieşte asigurarea comunicării Web „statefull”. Sesiuni servlet 7. Credem că aici este locul de a prezenta. Exemplul este unul similar (şi inspirat de) cap. Este evident că ultima soluţie este cea veritabilă.2. Pentru detalii se poate consulta API HTTPSession [89. să se asigure comunicare cu stare (statefull client/server communication) între clienţi şi server-ul Web. un obiect de tip HTTPSession poate reţine informaţii între două invocări succesive ale servlet-ului din cadrul aceleiaşi lansări a browser-ului. • se pot extrage obiecte din el invocându-se numele asociat (metoda getAttribute). • adăugarea la URL de către client a unor câmpuri cu rol de informaţii de tip session.

out. după caz (diferenţa dintre ele o prezentăm mai târziu). } // if f = new RandomAccessFile(a[0]. System.4. Implementarea unui counter de pagină Web Aşa cum am prezentat şi în 4.length != 2) { System.15. Fişierul binar poate fi creat.parseInt(a[1]).io.writeInt(i).4 am expus şi alte metode de plasare a fişierelor locale. } //CounterInit. f. prin intermediul unui fişier binar care reţine întregul reprezentând numărul curent de accese. Clientul counter Aşa cum am spus mai sus. i = Integer.println("Apel: java CounterInit "+ "numeFisier valoareInitialaContor").2. if (a.java 7.4.7.main } // CounterInit Programul 7.15.2. Pentru a fi accesat de servlet. • Un client applet AppletCounter care să preia obiectul Integer şi să-l afişieze pe pagină într-un obiect grafic Label. am ales plasarea lui în $CATALINA_HOME/bin.7. f.close().3.*. • Un servlet ServletCounter sau ServletCounterSession.1. Servlet-ul trimite spre client un obiect Integer conţinând numărul de accese. "rw"). Invocarea acestuia în cadrul paginii se face prin tag-ul: 373 . care este directorul curent al containerului de servlet. CounterInit. de exemplu. În 7. în modul cel mai simplu.2.3 un counter Web este realizat. int i. Prezenta implementare utilizează: • Un fişier binar numit FileServletCounter. prin intermediul programului 7. clientul efectiv al counter-ului este un applet. public class CounterInit { public static void main(String a[]) throws Exception { RandomAccessFile f. import java.exit(1).4.

java În cadrul metodei init se stabileşte conexiunea URL cu servlet-ul. this.intValue()). 374 . 7.getInputStream()). Label raspuns.printStackTrace(). } // try catch(Exception e) { e. } // catch } // AppletCounter. raspuns = new Label(""+i. AppletCounter extends Applet { public class public void init() { URL url.4.setUseCaches(false). java.4.openConnection().applet.io.awt. singura modificare este înlocuirea numelui servlet-ului. java. this.init } // AppletCounter Programul 7. URLConnection urlCon.16.*. in = new ObjectInputStream(urlCon.16. i = (Integer)in.*.2. java. ServletCounter Sursa acestui acestui servlet este dată în programul 7.setDefaultUseCaches(false).setVisible(true).class" width="50" height="30"> </APPLET> Textul sursă al applet-ului este dat în programul 7. urlCon = url.<APPLET code="AppletCounter. Integer i.17. in. try { url = new URL("http://"+getCodeBase(). se citeşte obiectul Integer de la servlet şi se afişează grafic sub forma unui Label. ObjectInputStream in.net. În cazul apelării lui ServletCounterSession. urlCon.*.readObject(). urlCon.add(raspuns). AppletCounter. import import import import java.getHost()+ ":8080/pdpj/servlet/ServletCounter").close().*.

io. out.flush(). // Rescrie noul numar f. ObjectOutputStream out.*. Lăsăm pe seama cititorului să testeze acest tandem applet . } // ServletCounter.*.*. // Inchide fisierul } // synchronized res. deoarece.import javax.17. // Incrementeaza f. IOException { int i=0.doGet } // ServletCounter Programul 7. public class ServletCounter extends HttpServlet { public void doPost(HttpServletRequest req.seek(0). ServletCounter. HttpServletResponse res) throws ServletException. import javax. out = new ObjectOutputStream(res.close(). // Repozitioneaza la inceput f. import java. out. RandomAccessFile f. în absenţa trimiterii unui mesaj de la client nu se poate stabili implicit metoda de cerere. "rw"). S-au definit atât metoda doPost cât şi doGet. HttpServletResponse res) throws ServletException.servlet destinat contorizării accesului la o pagină Web. } // ServletCounter. synchronized (this. // Trimite numarul la client out.setContentType("application/octet-stream").http. După incrementare se creează obiectul out de tip ObjectOutputStream prin care se trimite applet-ului obiectul Integer care conţine numărul de accese. res).getClass()) { // Blocheaza pentru incrementare f = new RandomAccessFile("FileServletCounter". // Deschide fisierul i = f.servlet.getOutputStream()). // Citeste numarul i++.writeInt(i). 375 .doPost public void doGet(HttpServletRequest req.writeObject(new Integer(i)). IOException { doPost(req.close().servlet.java Trebuie mai întâi să remarcăm faptul că accesul la fişierul binar este sincronizat cu clasa servlet-ului.readInt(). pentru a se evita multiacces simultan la fişierul contor.

setContentType("application/octet-stream"). Efectul va fi că numărul de accese va creşte. Sursa servlet-ului ServletCounterSession este dată în programul 7. trebuie să se oprească navigatorul după care să se lanseze din nou un acces la aceeaşi pagină!.servlet.getSession(true). out.18. // Deschide fisierul i = f.seek(0). Pentru aceasta vom folosi un obiect HTTPSession. } // if res. IOException { int i=0. // Repozitioneaza la inceput f. Din această cauză vom prezenta un servlet modificat care va fi „imun” cu numărarea în situaţiile expuse mai sus.*. new Integer(i)).intValue().getClass()) { // Blocheaza pentru incrementare f = new RandomAccessFile("FileServletCounter". // Trimite numarul la client 376 . "rw"). ObjectOutputStream out.writeInt(i). // Incrementeaza f.*.isNew()) { synchronized (this.servlet. El va considera un acces doar primul acces al browser-ului la pagină. } // synchronized } else { // sesiune exista deja i = ((Integer)sesiune. out = new ObjectOutputStream(res. // Citeste numarul i++.close(). Ba chiar mai simplu decât <BACK>: cereţi navigatorului <RELOAD> şi numărul de accese va creşte din nou! Evident că această numărare (cel puţin după unii) nu este una corectă. // Inchide fisierul sesiune.readInt().2. Pentru a se număra două accese. RandomAccessFile f. HttpSession sesiune. Accesaţi o pagină ce este contorizată cu ServletCounter definit mai sus. sesiune = req.writeObject(new Integer(i)).4.io. HttpServletResponse res) throws ServletException. // Rescrie noul numar f.getAttribute( "contorCurent")). import javax. public class ServletCounterSession extends HttpServlet { public void doPost(HttpServletRequest req. ServletCounterSession De ce a fost nevoie de un alt servlet? Dintr-un motiv foarte simplu. // Creeaza o sesiune daca nu exista if (sesiune.getOutputStream()).setAttribute("contorCurent". Apoi daţi <BACK> la browser şi accesaţi din nou pagina. import java.*. import javax.5.http.7.

out. Mai întâi din parametrul cerere req s-a creat obiectul sesiune de tip HTTPSession. } // ServletCounterSession. IOException { doPost(req. Ultima arhivă se află în distribuţia "Java Enterprise Edition". cât şi o nouă arhivă. locul ei este în: c:\j2sdkee1.1.1\lib\j2ee.jar. la fel ca şi cele din secţiunea precedentă. j2ee. ServletCounterSession. Acestui obiect i se asociază numele contorCurent.close(). } // ServletCounterSession.doPost public void doGet(HttpServletRequest req. HttpServletResponse res) throws ServletException. atunci se introduce în el un obiect Integer care conţine valoarea curentă a contorului.flush(). sunt incluse în aplicaţia pdpj.jar Aşa cum am arătat în 7. Trimiterea de mesaje e-mail din servlet Pentru compilarea şi execuţia programelor din această aplicaţie este nevoie ca în zona classpath să poată fi accesată atât arhiva servlet.1.3. Se testează apoi dacă obiectul sesiune este unul nou. j2ee1. cu foarte mici completări. res).1.java De fapt este uşor de văzut că este acelaşi servlet ca şi precedentul. 377 . out.3. În această distribuţie.doGet } // ServletCounterSession Programul 7. 7.3. 7.3. Noi am preferat să adăugăm permanent această arhivă la variabila CLASSPATH. se extrage din el obiectul cu numele asociat contorCurent şi se trimite acesta clientului.18. Dacă da.3. Dacă obiectul sesiune nu este unul nou.jar.4. Câteva exemple mai complexe Aceste exemple. trebuie efectuată una dintre cele trei acţiuni prin care această arhivă devine vizibilă în zona classpath.

html Exemplul care urmează reprezintă versiunea română a celui similar descris în [2].1. <HTML><HEAD><TITLE>Compunere de mesaj</title></HEAD> <BODY> <FORM ACTION="http://florin.ro:8080/"+ "pdpj/servlet/ServletMail" METHOD="POST"> <CENTER> <H1>Compuneti un mesaj</H1><HR><BR> <TABLE ALIGN="center" WIDTH="100%" CELLSPACING="2" CELLPADDING="2"> <TR> <TD ALIGN="right">Numele:</TD> 378 .16. Formular de trimitere a unui mesaj Documentul HTML de descriere a acestui formular este dat în programul 7. Intrarea se face printr-un formular prezentat în fig.16.cs. 7.ubbcluj. Clientul mail.1.7.3. Figura 7.19.

379 . Clasa Mailer.19.mail şi javax.2.<TD><INPUT TYPE="Text" NAME="txtFirst" ALIGN="LEFT" SIZE="15"></TD> <TD ALIGN="right">Prenumele:</TD> <TD><INPUT TYPE="Text" NAME="txtLast" ALIGN="LEFT" SIZE="15"></TD> </TR> <TR> <TD ALIGN="right">Email:</TD> <TD><INPUT TYPE="Text" NAME="txtEmail" ALIGN="LEFT" SIZE="25"></TD> <TD ALIGN="right">Telefon:</TD> <TD><INPUT TYPE="Text" NAME="txtPhone" ALIGN="LEFT" SIZE="15"></TD> </TR> <TR> <TD ALIGN="right">Software:</TD> <TD> <SELECT NAME="ddlb_software" SIZE="1"> <OPTION VALUE="Word">Microsoft Word</OPTION> <OPTION VALUE="Java">Java SDK1.internet.3.1.html 7. expeditor de mesaje email Trimiterea mesajelor e-mail din Java se poate face în mai multe feluri. Ne vom opri doar la una dintre modalităţi. cunoscute şi sub numele de pachetul JavaMail.mail. mail.4</OPTION> <OPTION VALUE="SQL Server">SQL</OPTION> </SELECT> </TD> <TD ALIGN="right">Operating System:</TD> <TD> <SELECT NAME="ddlb_os" size="1"> <OPTION VALUE="W2k">Windows 2000</OPTION> <OPTION VALUE="Linux">Linux</OPTION> <OPTION VALUE="Solaris">Solaris</OPTION> </SELECT> </TD> </TR> </TABLE> </CENTER> <BR>Continutul mesajului: <BR><TEXTAREA NAME="txtProblem" COLS="50" ROWS="4"> </TEXTAREA><HR><BR> <CENTER> <INPUT TYPE="Submit" NAME="btnSubmit" VALUE="Trimite mesajul"> </CENTER> </FORM></BODY></HTML> Programul 7. aceea oferită de către pachetete javax.

internet Clasa Mailer. Acest obiect va fi explorat de API JavaMail.Aceste pachete nu se află în distribuţia standard j2sdk1. . sau dacă se doreşte adresele destinatarilor separate prin virgulă. To. În absenţa distribuţiei j2skdee. se poate descărca de la java.jar conţine pachetele javax. Se setează în obiectul Message câmpurile From. 5. În esenţă. .com doar pachetul JavaMail. eventual şi câmpurile Cc. • cc (copy carbon) indică eventuale alte adrese la care se va trimite mesajul (poate fi vidă). Din obiectul Session se creează un obiect Message. dar se găseşte în distribuţia j2sdkee1. Pentru compilarea şi pentru execuţia unui astfel de program trebuie să aibă specificat în classpath calea spre o arhivă jar care conţine JavaMail. pentru trimiterea unui mesaj e-mail prin protocolul SMTP folosind JavaMail. ) Această metodă are ca şi parametri şapte string-uri (nu există legătura cu cei 7 paşi de mai sus): • from indică adresa expeditorului. Se creează un obiect Session JavaMail. Se încarcă obiectul Properties cel puţin cu adresa maşinii din reţeaua locală care este server SMTP. 380 .mail.4: c:\j2sdkee1. Metoda esenţială este una statică: Mailer.4 (distribuţia Java Standard).jar Arhiva j2ee. Se trimite mesajul folosind metoda statică Transport.4 (distribuţia Enterprise Edition).util. este destinată trimiterii de mesaje e-mail.Properties. • to indică adresa destinatarului.send().sun. Bcc.mail şi javax. trebuie parcurşi următorii şapte paşi: 1. pe care o prezentăm în continuare. 3. În cazul nostru această arhivă este luată din distribuţia j2sdkee1. Se depune textul efectiv al mesajului în corpul acestuia. 4. Subject. 2. Se va crea un obiect java. 7. 6. cu informaţii despre server-ul de mail.send( .4\lib\j2ee.

} setTo(String to) {this.*.length()==0)|| (text.} getTo() {return to. } // Mailer.mailHost = mailHost. javax.length()==0)||(mailHost. import import import import java. javax.length()==0)||(to.} public boolean isComplete() { if ((from==null)||(to==null)||(subject==null)|| (text==null)||(mailHost==null)) return false.20.util.java este prezentat în programul 7.} getText() {return text. /** Mailer este o clasa destinata trimiterii unui email */ public class Mailer { protected Session session. • mailHost conţine adresa maşinii locale care este server SMTP.} setCc(String cc) {this.mail.mail. dar un destinatar nu vede care sunt ceilalţi destinatari (poate fi vidă).} setText(String text) {this. // Adresele destinatarilor (To:) protected String cc.} setMailHost(String mailHost) {this. // Adresa expeditorului protected String to.} setFrom(String from) {this.io. // Adresele destinatarilor din (Bcc:) protected String subject. • text conţine efectiv mesajul de transmis.to = to.• bcc (blint copy carbon) cu acelaşi rol ca şi cc.internet. • subject conţine linia cu subiectul mesajului. return true.*.text = text. // Adresele destinatarilor (Cc:) protected String bcc.length()==0)) return false. if ((from.isComplete 381 .from = from. java. // Corpul mesajului protected String mailHost. // Obiectul sesiune javamail protected String from.cc = cc.subject = subject.*.length()==0)|| (subject.} getSubject() {return subject.*. // Adresa serverului local SMTP public public public public public public public public public public public public public public String String String String String String String void void void void void void void getFrom() {return from.} getBcc() {return bcc.} getCc() {return cc.bcc = bcc.} setSubject(String subject) {this.} setBcc(String bcc) {this. // Linia Subject: protected String text.} getMailHost() {return mailHost. Textul sursă Mailer.

// Creeaza un mesaj mesg.protected InternetAddress[] adrese(String lista) throws AddressException { InternetAddress[] adr = new InternetAddress[0]. mailHost).BCC. // Adresele din Cc: mesg.setSubject(subject).setRecipients(Message.countTokens()]. // Fixeaza Subject in mesaj mesg. // Se vor transmite la MAIL API props. // Creeaza obiectul sesiune final Message mesg = new MimeMessage(session). i++) adr[i] = new InternetAddress(st.adrese public synchronized void doSend() throws MessagingException. } // catch } // run }.").doSend 382 .send(mesg). return adr.length. for (int i=0. if (lista.nextToken().setText(text).setFrom(adrese(from)[0]). // (Din ratiuni de eficienta.setRecipients(Message. if (session==null) session = Session. // thread de trimitere } // Mailer. // Fixeaza corpul mesajului // Trimite mesajul prin metoda statica Transport. if (lista==null) return adr.TO. // Adresele din To: mesg.CC.smtp.RecipientType. adrese(cc)).RecipientType. adr = new InternetAddress[st. adrese(bcc)). Properties props = new Properties().RecipientType. } // try catch (MessagingException e) { throw new IllegalArgumentException( "Eroare la transport:" +e). StringTokenizer st = new StringTokenizer(lista. trimiterea se face intr-un thread separat) new Thread() { public void run() { try { Transport. ". i<adr. null).put("mail.length()==0) return adr. // Fixeaza From: in mesaj mesg. adrese(to)). } // Mailer.host".trim()).start().setRecipients(Message.getDefaultInstance(props. AddressException { if (!isComplete()) throw new IllegalArgumentException( "nu se poate apela inainte de completarea mesajului"). // Adresele din Bcc: mesg.

String bcc. trimiterera se efectuează într-un thread separat. completează câmpurile cu valorile parametrilor. m.doSend(). Mailer. . /* La executie programul se va conecta la "mailHost" (daca administratorul permite. Din raţiuni de eficienţă.java Cei şapte parametri pot fi setaţi şi individual. că metoda doSend începe prin a controla completarea rubricilor obligatorii ale unui e-mail. "florin@scs. "nessie. la rândul ei. } // Mailer. String to.20. Dacă aceste câmpuri se completează individual. m. doSend().ubbcluj.ubbcluj. De remarcat. dupa care trimite mesajul */ } // Mailer.ro". m. 383 . folosind în acest scop metoda isComplete(). Cititorul poate renunţa la acesta şi să trimită direct prin Transport.setSubject(subject).ubbcluj. În interiorul metodei doSend se poate vedea definirea celor şapte paşi necesari trimiterii unui e-mail. m.fboian@yahoo. String cc. String subject.ro"). "". În sfârşit.send( .setText(text). apoi identifica protected "from".cs. prin metode getter şi setter. folosită doar pentru a putea testa mai uşor clasa. metoda Mailer. String mailHost) throws MessagingException { Mailer m = new Mailer().setFrom(from).ubbcluj.setMailHost(mailHost).ro".ro.send(). de asemenea. "Asta-i textul\ncu doua linii". ) îşi creează propriul obiect Mailer. String text.send("florin@cs. după care apelează. utilizatorul poate să-şi declare un obiect de tip Mailer şi să apeleze metoda doSend() a acestui obiect.setTo(to). De fapt. "Test Mailer multiplu". .send public static void main(String a[]) throws Exception { Mailer. metoda adrese transformă adresele date prin string-uri întrun tablou de obiecte de tip InternetAddress. m.setBcc(bcc).setCc(cc). în maniera specifică componentelor Java (JavaBeans). Sursa Mailer se termină cu o metodă main. m.// Metoda apelabila din exterior pentru trimitere e-mail public static void send(String from.main } // Mailer Programul 7. "florin@cs. m.com". m.

length. this.add public boolean addTable(String _labels[]. public class HTML { public static final public static final public static final public StringBuffer int NORMAL = 0.3. default: break. this.buffer.3.21.buffer. Clasa HTML. case HEADING: this. break.java.append("<h1>"). this.buffer. this. Pentru ca servlet-ul să o poată folosi.buffer. break.*. } // switch if(_break) { this. import java.append("<hr>").1. this. 384 .append(_text).sql.buffer. } // if } // HTML.buffer. ResultSet _rs){ int cols = _labels.append(_title).append("<html><head><title>"). this.7. String _text.append("</h1>"). public HTML(String _title) { buffer = new StringBuffer(4096). auxiliar pentru servlet Clasa HTML este concepută pentru ca servlet-ul să fie ajutat să realizeze mai uşor o serie de construcţii HTML simple sau tabele. } // HTML. break. buffer. int HEADING = 1.buffer. this.append("<body>"). case LINE: this.buffer. boolean _break) { switch(_style) { case NORMAL: this.buffer.append("<table width='100%'>").append(_text).HTML public void add(int _style. cel mai simplu este ca fişierul class al ei să fie depus în acelaşi director cu servlet-ul: %CATALINA_HOME%\webapps\pdpj\WEB-INF\classes Sursa este prezentată în programul 7.append("</title></head>").buffer.buffer. int LINE = 2.append("<br>"). Lăsăm pe seama cititorului să deducă din sursă rolul acestei clase.

toString() + "</body></html>". PrintWriter out = res. msgFrom.22.*.buffer. return true.buffer.buffer.printStackTrace().3. } // HTML. for (int i = 1.append("<th align='left'>"). for (int i = 0. this. } // catch this.http.buffer. HTML.append("</th>").java 7. import import import import javax. ServletMail Sursa acestui servlet este dată în programul 7.append("<tr>"). HttpServletResponse res) throws ServletException. javax.buffer. i++) { this. this. msgTo. java.buffer.buffer.append("</tr>"). this. this. java.append(_rs.getPage } // HTML Programul 7.setContentType("text/html").4. } // for this.servlet. i++) { this. return false. } // HTML. public class ServletMail extends HttpServlet { String message. try { while (_rs. } // while } // try catch (SQLException e) { e.append("</tr>"). getParameters(req).servlet.buffer. i < cols.addTable public String getPage() { return this. IOException { res.this.21.append(_labels[i]).util. 385 .*.next()) { this.buffer. } // for this.*.getWriter().getString(i)).1.buffer.append("<td>"). i <= cols.append("<tr>"). public void doPost(HttpServletRequest req.buffer.io.buffer.append("</td>"). msgSubject.*.append("</table>").

msgTo.getParameter("txtLast")).getParameters } // ServletMail Programul 7.getParameter("txtPhone")). tempStringBuffer.append("Email: ").close(). h.getParameter("txtProblem")).append(req.append("\n"). iar poşta este citită pe maşina linux. tempStringBuffer.ubbcluj.append("\n\n").append(req. msgSubject = "Trimitere de mesaj". IOException { StringBuffer tempStringBuffer = new StringBuffer(1024). } // try catch (Exception e) { e.println(h. folosind clientul de mail pine [98]. tempStringBuffer.ubbcluj. tempStringBuffer. "".try { Mailer.ro. out.append("OS: "). "".append("\n"). tempStringBuffer. care prezintă mesajul completat ca în fig. } // catch HTML h = new HTML("Transmitator de mesaje mail").append("\n"). tempStringBuffer. tempStringBuffer.append("Mesajul: ").ro".send(msgFrom.append("De la: ").17.append("Software: ").getPage()). 386 . message = tempStringBuffer.getParameter("ddlb_os")).scs. message. "nessie.getParameter("txtEmail").append(req.22. return. msgSubject. tempStringBuffer.append(req.getParameter("txtFirst")).HEADING. "Mesajul a fost transmis". msgFrom = "florin@cs. msgTo = req.getParameter("txtEmail")). tempStringBuffer. tempStringBuffer. false).cs.append(req.append(req.add(HTML. tempStringBuffer. tempStringBuffer. tempStringBuffer.ubbcluj.append(req.append("\n"). } // ServletMail. tempStringBuffer. tempStringBuffer. 7.java Efectul execuţiei acestui servlet este prezentat în fig.append("Telefon: "). tempStringBuffer.16. tempStringBuffer. tempStringBuffer.append("\n\n"). tempStringBuffer. out. } // ServletMail. 7.ro").append(" ").getParameter("ddlb_software")).printStackTrace().doPost private void getParameters(HttpServletRequest req) throws ServletException.toString(). tempStringBuffer. ServletMail.

permite accesul prin Web al fiecărui student să-şi vadă doar propriile note.17.5 am prezentat şi implementat sub RMI aplicaţia Note.2.adăugări. cât şi pentru maşina Student.Materie. care apelează la rândul lui server-ul Profesor. Înlocuim păstrarea datelor (CATALOG) ca obiecte serializate cu păstrarea acestora în două tabele dintr-o bază de date.de către un server Profesor a unor perechi (Materie. Aplicaţia Note. Este vorba de gestionarea .Figura 7. Înlocuim comunicaţia RMI utilizarea servlet-urilor. În această secţiune reluăm problema. modificări .3. Un server Student. 2.Profesor) şi a unor triplete (Student. Această aplicaţie va purta numele Note şi atât pentru maşina Profesor. ştergeri. în %CATALINA_HOME%\webapps\ 387 . Mesajul citit cu pine 7.Nota). dar schimbăm două elemente esenţiale în implementare: 1. versiunea servlet În 5.

public class NoteAccessDB { NivelJDBC db = null. aşa cum am arătat în 7. String profesor) throws Exception { rs = db. este dată în programul 7.16) pentru încărcarea iniţială a bazei de date prin linii date la intrarea standard.odbc. } // NoteAccessDB.3. Clasa NoteAccessDB Această clasă va fi folosită de către ServletProfesor pentru a accesa tabelele Perechi şi Triplete din baza de date.5.1. valoare="". "jdbc:odbc:Note").AccessDB public boolean isMaterieProfesor(String materie. } // NoteAccessDB. conectabilă la ACCESS.next().3. avem deja un astfel de program: este vorba de TestNivelJDBC (programul 3.2. i = db.next(). import java. rs = db.getString("Materie")+"\n". return rs. ResultSet rs.getString("Nota")+"\n".JdbcOdbcDriver".jdbc. } // NoteAccessDB. Pentru prezenta aplicaţie. public NoteAccessDB() throws Exception { int i.*. 7.2).trebuie creat un director Note. } // for return nume+"\t"+valoare.executeQuery("SELECT Profesor FROM Perechi "+ "WHERE Materie = '"+materie+"' and Profesor = '"+profesor+"'").sql. Nota FROM Triplete"+ " WHERE Student = '"+student+"'").isMaterieProfesor public String getMaterieNota(String student) throws Exception { String nume.23. for ( nume="". valoare. ) { nume += rs.1.setConnection("sun.getMaterieNota 388 . Sursa clasei.executeQuery("SELECT Materie. În varianta RMI am folosit BatchCatalogDB (programul 5. import java.util. valoare += rs. împreună cu toată substructura necesară.*.3) prin care am exemplificat utilizarea clasei NivelJDBC (programul 3. db = new NivelJDBC(). rs.

getStudentNota. } // for } // NoteAccessDB. valoare += rs. valoare="". rs = db. nota. else db. ) { student = stt. "+ "Nota FROM Triplete "+ "WHERE Student = '"+student+ "' and Materie = '"+materie+"'").2. if (rs.next()) db. prezentat în programul 3. materie = stt. stt. } // NoteAccessDB. student.executeQuery("SELECT Student.executeQuery("SELECT Student.executeUpdate("INSERT INTO Triplete VALUES ('"+ student+"'. ) { nume += rs.hasMoreTokens().nextToken(). NoteAccessDB.main } // NoteAccessDB Programul 7.executeUpdate("UPDATE Triplete SET Nota='"+nota+"'"+ "WHERE Student = '"+student+ "' and Materie = '"+materie+"'").setStudentNota public static void main(String a[]) throws Exception { new NoteAccessDB(). String materie.next(). } // NoteAccessDB. for ( . valoare.java Pentru acces la baza de date. Materie. nota = stt.23. 389 . "\t"). stt.getStudentNota public void setStudentNota(String studentnota) throws Exception { int i.public String getStudentNota(String materie) throws Exception { String nume.getString("Nota")+"\n". stt. } // for return nume+"\t"+valoare.nextToken(). Nota FROM Triplete"+ " WHERE Materie = '"+materie+"'"). StringTokenizer stt = new StringTokenizer(studentnota. rs = db.nextToken(). setStudentNota. rs. clasa foloseşte un obiect de tip NivelJDBC.nextToken().getString("Student")+"\n". for ( nume="".'"+nota+"')").nextToken(). Clasa oferă trei metode: − − − isMaterieProfesor.'"+materie+"'.

un alt obiect String specific. Metoda întoarce true sau false. după caz.2. separate tot prin <NEWLINE> ('\n'). atunci doPost interpretează acest cuvânt ca şi numele unui student. Dacă perechea nu există. profesor). În continuare apar un număr oarecare de perechi de cuvinte student.nota). Se verifică mai întâi dacă perechea (student. corespunzător cerinţelor. Al treilea cuvânt este materie pentru care se actualizează notele. notele studenţilor la o anumită materie. Metoda setStudentNota(String studentnota) Actualizează sau. În el se află mai întâi numele materiilor.2. nota. Metoda String getMaterieNota(String student) Întoarce pentru student notele lui la toate materiile. după caz adaugă. tabelele bazei de date. adică profesor predă sau nu materie. În funcţie de numărul de cuvinte conţinute metoda doPost trimite clientului.3.materie.Evident. String-ul rezultat are forma potrivită pentru a putea fi preluat simplu de către metodele apelatoare. Printr-un obiect de tip NoteAccessDB accesează baza de date şi apoi îi întoarce clientului (student) notele lui la toate materiile. Acest string conţine unul sau mai multe cuvinte separate prin caracterul <TAB> ('\t'). Primele două cuvinte sunt ignorate (dar trebuie transmise de apelator!). drept răspuns. Unicul parametru de intrare este un string cu un conţinut trimis de servlet. Metoda boolean isMaterieProfesor(String materie. separate prin caracterul <NEWLINE> ('\n'). El conţine o succesiune de cuvinte separate prin caracterul <TAB> ('\t'). toate trei accesează. 390 . 7. Dacă string-ul de intrare conţine un singur cuvânt. atunci se introduce un nou triplet (student.materie) există deja şi în caz afirmativ se actualizează doar nota. String profesor) Verifică dacă în tabelul Perechi există perechea (materie. Programul ServletProfesorDB Acest servlet primeşte de la client un obiect String. urmează un separator <TAB> ('\t') după care notele la fiecare materie.

atunci îi întoarce clientului (profesor) notele tuturor studenţilor la materia respectivă. parola invalida sau nu preda materia 391 .servlet.servlet.*. atunci primele trei sunt interpretate ca şi profesor.isFTPUser("localhost".*. public class ServletProfesorDB extends HttpServlet { public void doPost(HttpServletRequest req.getMaterieNota(student). if (ntokens == 1) { student = (String)adb. HttpServletResponse res) throws ServletException. out = new ObjectOutputStream(res. pentru a actualiza notele la materia respectivă. in.*. parola şi materie. } // Intoarce StudentNota if (ntokens >= 3) { profesor = st.isMaterieProfesor(materie.close(). return.close().util. if ((!AuthFTP. atunci transmite acest şir metodei setMaterieNota a obiectului NotaAccessDB. Dacă string-ul de intrare are mai mult de trei cuvinte. out. În caz de eşec întoarce clientului string-ul vid. "\t").countTokens(). Sursa acestui servlet este prezentată în programul 7.nextToken(). javax. NoteAccessDB adb = new NoteAccessDB(). parola = st.getInputStream()).getOutputStream()).close().writeObject(student).http. out. profesor))) { out = new ObjectOutputStream(res.Dacă are trei sau mai multe cuvinte.writeObject(""). ObjectOutputStream out. materie = st. String student. profesor. in = new ObjectInputStream(req.nextToken().readObject(). Dacă string-ul de intrare are exact trei cuvinte.*.nextToken(). out. Mai întâi se autentifică profesorul pe baza parolei şi apoi se verifică dacă predă materia respectivă. parola))|| (!adb. int ntokens = st. IOException { try { ObjectInputStream in. } // Intoarce esec.getOutputStream()). out. java. materie="". StringTokenizer st. java. profesor. student = (String)in.io. parola. return. st = new StringTokenizer(student.24 import import import import javax.

class.24.2.} // A trecut de autentificare if (ntokens == 3) { student = adb. out. trebuie ca pe maşina Profesor.doGet } // ServletProfesorDB Programul 7. 7.class. } // Intoarce studentii si notele pentru o materie adb.class. Programul ServletStudentDB Acest servlet este apelat prin Web de către studenţi pentru a-şi afla notele.java Pentru ca acest servlet să funcţioneze. Clientul (student) transmite servlet-ului un obiect te tip String. IOException { doPost(req.3. } // catch } // ServletProfesorDB.printStackTrace(). } // ServletProfesorDB. Primul cuvânt este numele studentului iar al doilea este parola lui. res). Deci în classes trebuie să existe fişierele: • • • • ServletProfesorDB. compus din două cuvinte separate printr-un caracter <TAB> ('\t').close(). împreună cu celelalte fişiere necesare.getStudentNota(materie).class. out = new ObjectOutputStream(res. out.getOutputStream()). HttpServletResponse res) throws ServletException. NoteAccessDB. } // try catch (Exception e) { e.writeObject("OK").doPost public void doGet(HttpServletRequest req. // Fixeaza notele studentilor la o materie out = new ObjectOutputStream(res. ServletProfesorDB. Servlet-ul autentifică 392 . return. AuthFTP. NivelJDBC. în: %CATALINA_HOME%\webapps\Note\WEB-INF\classes\ să fie copiat fişierul class al servlet-ului.close(). out.writeObject(student). out.3.getOutputStream()).setStudentNota(student).

java. java.*.net. După această conectare. trimite clientului obiectul String primit de la ServletProfesor.25.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems. iar în caz de eşec îi întoarce acestuia un obiect String de lungime zero.com/dtd/web-app_2_3.//DTD Web Application 2. public class ServletStudentDB extends HttpServlet { private String masina = null. Prin aceeaşi conexiune.*. Deci. atunci ServletStudent apelează.io.util. 393 . ServletProfesor prin URLConnection. invităm cititorul să consulte sursa acestui servlet în programul 7.25.xml (aplicaţia Note) Cu aceste precizări. Dacă autentificarea se face cu succes.http.*.3//EN" "http://java. Inc.*. <?xml version="1. prin conexiunea obţinută de la obiectul răspuns (res). la rândul lui.*. ServerProfesor îi întoarce un obiect String. Apoi.studentul. aşa cum am descris la metoda getMaterieNota a clasei NoteAccessDB.xml a se preciza adresa maşinii ServletProfesor. java.dtd"> <web-app> <servlet> <servlet-name>ServletStudentDB</servlet-name> <servlet-class>ServletStudentDB</servlet-class> <init-param> <param-name>MasinaProfesor</param-name> <param-value>localhost</param-value> </init-param> </servlet> </web-app> Programul 7. javax.sun. pe maşina Student trebuie să existe fişierul: %CATALINA_HOME%\webapps\Note\WEB-INF\web. import import import import import javax.xml Conţinutul acestui fişier este prezentat în programul 7.servlet.servlet. ServletStudent îi transmite lui ServletProfesor un obiect String ce conţine numele studentului. web.26. Acest servlet trebuie să fie iniţializat folosind fişierul web.

getOutputStream()). String student. in. out = new ObjectOutputStream(res.indexOf("\t")+1).getOutputStream()).isFTPUser("localhost". // Permite si scrierea in resursa urlCon.readObject(). out. out = new ObjectOutputStream(urlCon.close(). out. HttpServletResponse res) throws ServletException. res).getInputStream()).setDefaultUseCaches(false). out.close(). in = new ObjectInputStream(urlCon.close().setDoInput(true).close().printStackTrace().getOutputStream()). if (!AuthFTP. urlCon = url. // Deschide conexiunea urlCon.indexOf("\t")).setUseCaches(false). student = student.setDoOutput(true). in = new ObjectInputStream(req.init public void doPost(HttpServletRequest req. out.writeObject(""). student. IOException { doPost(req. parola = student. in.public void init(ServletConfig config) throws ServletException { super. urlCon.close(). ObjectInputStream in. student. if (masina == null) masina = "localhost". out.writeObject(student). parola)) { out = new ObjectOutputStream(res. out. } // ServletStudentDB. return.getInitParameter("MasinaProfesor").substring(student.openConnection(). } // catch } // ServletStudentDB. parola. 394 . URLConnection urlCon.writeObject(student). HttpServletResponse res) throws ServletException. masina = config. } // try catch (Exception e) { e. ObjectOutputStream out.getInputStream()).doPost public void doGet(HttpServletRequest req.substring(0. } // Intoarce esec url = new URL("http://"+masina+ ":8080/Note/servlet/ServletProfesorDB"). IOException { try { URL url. student = (String)in.init(config).readObject(). student = (String)in. urlCon.

java.3. public class ClientStudentDB extends Applet implements ActionListener { TextArea taNume. gc. 395 . public void init() { try { Label l. l = new Label("Materie"). gb.} // ServletStudentDB.class" width=300 height=400> Applet-ul se conectează la ServerStudentDB prin URLConnection. gc.*.java 7.4.*. apasă butonul <CITESTE>.doGet } // ServletStudentDB Programul 7.*. TextField tfUser.27.setConstraints(l. Din punctul de vedere al interfeţei cu utilizatorul este identic cu clientul prezentat în 5. ServletStudentDB.io.gridx = 0. Button citeste.awt.*.*.2. După ce studentul îşi completează numele şi parola. gc.*. this.6. java. this. Clientul StudentDB Acesta este un client Web care apelează servlet-ul prin intermediul unui applet. java.2.add(l). În acest moment este autentificat şi în caz de succes i se afişează notele.net. GridBagLayout gb = new GridBagLayout(). l = new Label("Nota").applet.CENTER. java. import import import import import import java. java. Apelul applet-ului dintr-un document HTML se face prin: <applet code="ClientStudentDB. textul sursă al applet-ului este prezentat în programul 7. ObjectOutputStream out. URLConnection urlCon. GridBagConstraints gc = new GridBagConstraints().gridy = 0. tfParola.26. ObjectInputStream in. URL url.setLayout(gb).anchor = GridBagConstraints. gc).awt.util. taValoare.event.5.

taValoare.gridx = 0.setConstraints(l. gb.WEST. url = new URL("http://"+getCodeBase(). l = new Label("Student:").setConstraints(taValoare.EAST. gb.anchor = GridBagConstraints.gridy = 1.setConstraints(l. this. gb.getHost()+ 396 .anchor = GridBagConstraints. gc. gc. gc. gc. this. gc.EAST.add(l).gridx = 0.add(tfParola). gc).CENTER. gc. taNume.setConstraints(tfParola. gc).gridx = 1. gc).setConstraints(tfUser.gridx = 0.gridx = 1. tfParola. 10).setConstraints(taNume. taValoare = new TextArea(10.EAST. gb.gridy = 0. this.add(citeste). gc). gc.gridx = 1. this.WEST.gridy = 2. gc. gb. gc. this.add(l).anchor = GridBagConstraints. gc. gc. this.gridy = 3.setVisible(true).gridy = 2. gc. this.gridy = 4.anchor = GridBagConstraints. tfParola = new TextField(10). gc. gc. gc.WEST.add(taNume). gc.gc. gc. gb. gc. gc.setEditable(false). citeste. citeste = new Button("Citeste").add(taValoare). gc). this.10). this. gc. l = new Label("Parola:").setEditable(false).anchor = GridBagConstraints.anchor = GridBagConstraints.setConstraints(citeste.anchor = GridBagConstraints.WEST.anchor = GridBagConstraints.add(tfUser). gc). gc).gridy = 3.addActionListener(this). gb. gb.add(l).gridx = 0. tfUser = new TextField(10). taNume = new TextArea(10. gc).setSize(this.setConstraints(l.getPreferredSize()).gridy = 1. this. gc.setEchoChar('*'). gc.gridx = 1. gc.

setUseCaches(false). out.substring(nume.getOutputStream()). in = new ObjectInputStream(urlCon. nume = nume. // Permite si scrierea in resursa } // try catch (Exception e) { e. } // catch } // ClientStudentDB.init public void actionPerformed(ActionEvent ev) { String nume.indexOf("\t")+1). Dat fiind faptul că ClientProfesorDB este un program standalone. out.5. valoare.readObject(). try { if ((ev.5.setDefaultUseCaches(false). Din punct de vedere al implementării este o aplicaţie Java Standalone care interfaţează cu utilizatorul printr-un Frame.setText(valoare).nume.java 7.2.":8080/Note/servlet/ServletStudentDB"). taValoare. tfUser. } // catch } // ClientStudentDB. // Deschide conexiunea urlCon. } else tfUser.getText()). urlCon = url. } // if tratare citeste } // try catch (Exception e) { e. urlCon.actionPerformed } // ClientStudentDB Programul 7.length() > 0) { valoare = nume.openConnection().equals("Citeste")) { out = new ObjectOutputStream( urlCon.materie!"). ClientProfesorDB Comportarea în relaţia cu utilizatorul a acestui client este identică cu cea a clientului descris în 5.1.setText(nume).setDoOutput(true). taNume. Poate deci să se elimine accesul la 397 . el poate fi scris ca un program simplu.printStackTrace().setText("ERR!citire:user.printStackTrace().getActionCommand()).indexOf("\t")).27.close().setText("OK citire"). ClientStudentDB.substring(0.writeObject(tfUser.6. urlCon.getText()+"\t"+ tfParola. cu două părţi: o interfaţă grafică şi o interfaţă cu baza de date. if (nume.getInputStream()).3. nume = (String)in.close().parola. in.

class ClientProfesorDB extends Frame implements ActionListener. gc. Acest fapt încalcă cerinţele protocolului HTTP. Lăsăm pe seama cititorului să conceapă un astfel de program. tfParola. gc.util. prezentăm în programul 7.*.event. la fiecare operaţie de citire sau de scriere se deschide o nouă conexiune! Deci. java.CENTER. Conexiunea dintre cei doi parteneri se face prin URLConnection. l = new Label("Nota"). programul transmite la ServerProfesorDB un obiect String şi primeşte înapoi ca şi răspuns un alt obiect de tip String. gc). GridBagConstraints gc = new GridBagConstraints(). import import import import import java. gc.io. din motive care se vor vedea imediat. GridBagLayout gb = new GridBagLayout().setConstraints(l.setLayout(gb). gb. ATENŢIE! Acest client poate cere ori de câte ori să citească şi să scrie. Noi vom rămâne.awt.ServletProfesorDB pentru a accesa baza de date. URLConnection urlCon. gc. WindowListener { TextArea taNume.gridy = 0. ObjectInputStream in. care permite numai o eventuală scriere spre server urmată. de fapt. tfMaterie. Cu aceste precizări. l = new Label("Student").*.gridx = 0. Din punct de vedere al conexiunii. this.anchor = GridBagConstraints. 398 . acest client discută cu mai multe instanţe thread ale servlet-ului.28 sursa acestui client. la un client care cere servlet-ului să acceseze baza de date. taValoare. java. scrie. TextField tfUser. java. Button citeste.*. Pentru a se permite oricâte operaţii şi în orice ordine. de o citire de la el. this. public ClientProfesorDB(String host) throws Exception { Label l. ObjectOutputStream out.add(l).gridy = 0.*.awt. java. URL url.net. eventual.gridx = 1.*. gc.

gridx = 0. gc.gridx = 0.setConstraints(l.gridx = 1. gc). gc.setConstraints(tfMaterie. gc.addActionListener(this). gb. gc.WEST. gc). gc.WEST.add(l).anchor = GridBagConstraints.gridy = 4. this.gridy = 2. gc. this. this. tfMaterie = new TextField(10). gc. gc). citeste. gb.setConstraints(tfUser. gb.anchor = GridBagConstraints. gc.EAST. this. gc).gridx = 0. gb.add(taNume).gridx = 1. tfParola. gb. gc).gridx = 1. gc. gc.gridy = 3. gb.anchor = GridBagConstraints.anchor = GridBagConstraints.setEchoChar('*'). tfUser = new TextField(10).setConstraints(l. gc).add(taValoare). gc. gc.WEST. gc. l = new Label("Profesor:"). gc). gc. gc.10). 399 . gc.anchor = GridBagConstraints.add(tfUser). gc. this.add(tfParola). gc). gc. l = new Label("Parola:"). taValoare = new TextArea(10. gc.EAST.WEST.setConstraints(l. gc.anchor = GridBagConstraints. this.EAST. this.anchor = GridBagConstraints. gc.gridy = 3. taNume = new TextArea(10.setConstraints(taNume. this.anchor = GridBagConstraints.gridy = 2. gb. gc.add(tfMaterie).gridx = 1. tfParola = new TextField(10). gb. citeste = new Button("Citeste").gridx = 0.add(l).add(l).EAST.anchor = GridBagConstraints. this.setConstraints(taValoare.CENTER.gridy = 1.setConstraints(tfParola.gridy = 4. gb. l = new Label("Materie:").add(l).setConstraints(l. gc. 10). gc).gridy = 1.gc. gc.

add(scrie). // Permite si scrierea in resursa urlCon. this.setVisible(true).getOutputStream()). int i.addWindowListener(this). taValoare. urlCon. std. nume = (String)in. valoare = "".add(citeste). this. // Deschide conexiunea urlCon. gc.materie!"). } // if tratare citeste if ((ev.setText("ERR!citire:user.getText()+"\t"+ tfParola.getText()+"\t"+tfMaterie.getText().getInputStream()). } else tfUser. out = new ObjectOutputStream(urlCon. this.getText()). gc. nume = nume. urlCon.EAST.equals("Citeste")) { url = new URL("http://localhost:8080/Note/"+ "servlet/ServletProfesorDB"). this.writeObject(tfUser.show().setConstraints(scrie.substring(0.setText(valoare). gc).getText(). taNume.gridx = 1.pack(). scrie. tfUser.gridx = 0. in = new ObjectInputStream(urlCon.setDoInput(true).anchor = GridBagConstraints. this. this. out.substring(nume. gc.gridy = 5.ClientProfesorDB public void actionPerformed(ActionEvent ev) { StringTokenizer stp. out.getActionCommand()). String nume = "". this. try { if ((ev.setText(nume).setUseCaches(false).parola. 400 .getPreferredSize()).gc.setText("OK citire"). "\r\n\t"). urlCon = url. gc).equals("Scrie")) { stp = new StringTokenizer(taNume.WEST.nume.close().getActionCommand()).setSize(this. gc.setDefaultUseCaches(false). } // ClientProfesorDB.gridy = 5. n.addActionListener(this). setTitle("Fixare note/materie").readObject(). scrie = new Button("Scrie").setConstraints(citeste. gc.openConnection().close().length() > 0) { valoare = nume. gb. in. if (nume. std = new StringTokenizer(taValoare.anchor = GridBagConstraints.indexOf("\t")).indexOf("\t")+1).setDoOutput(true). gb.

urlCon. url = new URL("http://localhost:8080/Note/servlet"+ "/ServletProfesorDB"). out.printStackTrace(). } // catch } // ClientProfesorDB. urlCon = url. // Permite si scrierea in resursa urlCon. else tfUser. urlCon."\r\n\t").nextToken()+"\t"+std.writeObject(nume). } // ClientProfesorDB. if (nume. } // if tratare scrie } // try catch (Exception e) { e. // Deschide conexiunea urlCon. n = (n > i) ? i : n.materie!").actionPerformed public public public public public public public void void void void void void void windowClosing(WindowEvent e) {System.setText("ERR!scriere:user.length >0)?a[0]:"localhost").close(). for (i=0.setDoOutput(true). out.28. nume = (String)in.getText()+"\t"+tfParola.getText()+"\t"+ tfMaterie.readObject().getText().java 401 . i = std.getOutputStream()). in.setUseCaches(false). in = new ObjectInputStream(urlCon.setDefaultUseCaches(false).setText("OK scriere").countTokens().nextToken().close().openConnection().length() >0) tfUser.getInputStream()).parola. out = new ObjectOutputStream(urlCon.exit(0).setDoInput(true). ClientProfesorDB. n = stp.countTokens().} windowClosed(WindowEvent e) {} windowActivated(WindowEvent e) {} windowDeactivated(WindowEvent e) {} windowOpened(WindowEvent e) {} windowIconified(WindowEvent e) {} windowDeiconified(WindowEvent e) {} public static void main(String a[]) throws Exception { new ClientProfesorDB((a. i<n.main } // ClientProfesorDB Programul 7. i++) nume += "\t"+stp. nume = tfUser.

</res-type> <res-auth> . Se elimină astfel legarea directă a servlet-ului de un anumit tip de bază de date... Pentru realizearea acestui mod de legare.xml un nume JNDI.. Descrierea unei astfel de referinţe se face prin intermediul unei substructuri XML înglobată în tag-ul <resource-ref>.5.7.</res-ref-name> <res-type> ..4. Structura acestuia este: <resource-ref> <res-ref-name> ... numele user-ului bazei de date. parola acestuia sunt fixate direct în cod. Definirea referinţei la resursa bază de date Prin această referinţă servlet-urile aplicaţiei se vor referi la baza de date.3. • să asigure în codul Java conectarea la baza de date prin referinţa de mai sus. prin nişte constante. proiectantul aplicaţiei trebuie să efectueze trei mici acţiuni: • să definească în web.</res-sharing-scope> </resource-ref> 402 .xml resursa baza de date şi să o lege de numele ei de referinţă.3. • să definească în server. Să le luăm pe rând.. prin care programele să se refere la resursa bază de date.1. O soluţie de a face mai elastică această legare este aceea de a transmite aceste date ca şi parametri de iniţializare. aşa cum am văzut în 7. string-ul de conectare.1.3. Alinierea Tomcat la JNDI simplifică această activitate şi face aplicaţiile mult mai scalabile.. practic codul devine complet independent de specificul unui anumit tip de bază de date. Astfel.3. 7.</res-auth> <res-sharing-scope> . sarcina detalierii parametrilor bazei urmând să fie legaţi doar de această referinţă. Conectare JDBC din Tomcat prin JNDI Unul dintre dezavantajele conectării directe la o bază de date prin JDBC este acela că informaţiile de conectare: • • • • clasa driver.

Valorile posibile sunt Container sau Application. aşa că de multe ori referinţa este întâlnită sub forma: java:comp/env/jdbc/numeConexiune res-type indică tipul clasei Java utilizat.com/dtd/web-app_2_3. această clasă este. după cum am mai arătat în 3. pentru baze de date acest nume are forma: jdbc/numeConexiune În codul Java.3.Conform specificaţiilor Tomcat. De obicei.2. res-sharing-scope indică gradul de partajabilitate al resursei.3//EN" "http://java. Inc. Dacă dorim ca pentru aplicaţia Note descrisă mai sus accesul să se facă prin JNDI. Valoarea poate fi Shareable .implicit -sau Unshareable.xml numai după tag-urile care se referă la parametri ai servlet-urilor. Să exemplificăm. tag-urile resource-ref trebuie să fie specificate în web. În cazul JDBC prin JNDI.sun. Acesta este un nume JNDI relativ la contextul java:comp/env şi trebuie să fie unic în cadrul aplicaţiei. acest nume este de obicei ataşat contextului lui. res-auth specifică cine autorizează accesul la resursă.dtd"> <web-app> <servlet> <servlet-name>ServletStudentDB</servlet-name> <servlet-class>ServletStudentDB</servlet-class> <init-param> <param-name>MasinaProfesor</param-name> <param-value>localhost</param-value> </init-param> </servlet> <resource-ref> <res-ref-name>jdbc/NoteDB</res-ref-name> <res-type>javax. <?xml version="1.xml al ei va fi cel din programul 7.29. res-ref-name este numele referinţei la resursă.DataSource</res-type> 403 . atunci fişierul web.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems. clasa DataSource.//DTD Web Application 2.sql.

3.sql.getConnection(). Utilizarea referinţei în codul Java Aşa cum am arătat în 3.lookup("java:comp/env/jdbc/numeConexiune").JdbcOdbcDriver".3. această referinţă este utilizată în locul conexiunii directe la baza de date.lookup("numeJNDIBazaDate"). javax.xml.Connection co = ds.odbc.Context cx = new InitialContext(). sau a schimbării motorului de bază de date. Rugăm cititorul să compare acest fişier cu cel din programul 7. secvenţa minimală este: javax. Evident.setConnection("java:comp/env/jdbc/NoteDB"). fişierul web. conexiunea se obţine prrin: javax.setConnection("sun. "jdbc:odbc:Note").Context cx = new InitialContext(). Se va apela astfel cea de-a doua metodă de conectare din clasa NivelJDBC (programul 3.<res-auth>Container</res-auth> </resource-ref> </web-app> Programul 7.DataSource ds = (DataSource)cx. Pentru fabricarea în acest mod a unei conexiuni JNDI la o bază de date.DataSource ds = (DataSource)cx.naming. se va folosi instrucţiunea: i = db. nici codul Java al aplicaţiei nu se vor modifica! Ceea ce se va modifica prezentăm în secţiunea următoare.29. 7.2.xml trebuie configurat aşa cum am arătat în secţiunea precedentă.Connection co = ds. Cititorul poate refolosi extrem de simplu codurile claselor aplicaţiei Note pentru a alinia aplicaţia la JNDI.jdbc. nici fişierul web. În cazul mutării aplicaţiei. 404 .25.2.xml (Note JNDI) Referinţa am numit-o jdbc/NoteDB. javax. javax.3. În cazul aplicaţiei Note. Singura modificare în cod este în clasa NoteAccessDB (programul 7.sql.naming. În acest program.getConnection().2). în locul inrtrucţiunii: i = db.sql. javax.23).sql. web.

1.3.3.2. am indicat ca şi valoare a acestui nume şirul vid.30.3.xml (parţial.7. 405 . resursa bază de date) Partea referitoare la resursa bază de date este cuprinsă în tag-ul <ResourceParams>. server. o bază de date Access aflată pe maşina locală a containerului. despre care am mai vorbit în 7. Pentru aplicaţia Note am folosit ca şi în 7. în programul 7. MySQL.3.2. Pentru fixarea ideilor.JdbcOdbcDriver</value> </parameter> <parameter> <name>driverName</name> <value>jdbc:odbc:Note</value> </parameter> </ResourceParams> </Context> Programul 7. Definirea resursei baza de date Definirea acestei resurse se face în fişierul server.3.1. deoarece Access nu pretinde neapărat o autentificare pe bază de nume de user. care conţine în el şi definirea resursei baza de date. aşa cum o face ORACLE.odbc. fie în contextul aplicaţiei în care se foloseşte resursa.jdbc.wml de configurare a Tomcat. Această definire se poate face fie în contextul implicit Tomcat (<DefaultContext>). MSSQLServer. <Context path="/Note" docBase="Note" debug="0" privileged="true"> <ResourceParams name="jdbc/NoteDB"> <parameter> <name>user</name> <value/> </parameter> <parameter> <name>password</name> <value/> </parameter> <parameter> <name>driverClassName</name> <value>sun. În cazul nostru.30 prezentăm tag-ul <CONTEXT al aplicaţiei Note. aplicaţia Note. Resursa a fost definită prin cei patru parametri caracteristici resursei: • user Specifică numele utilizatorului care accesează motorul de bază de date.

xml trebuie bine securizat. de asemenea aici are ca valoare şirul vid.2.• password Este parola de acces la bază.2. Atenţie însă: Dacă pentru driver este necesară o arhivă jar (este vorba de driver ce nu este în distribuţia Java). • driverName. sau url (sunt echivalente) Indică string-ul de conectare la baza de date. deoarece apare parola în clar! • driverClassName Indică numele clasei driver pentru acces la baza de date. fişierul server. Absenţa adresei maşină face ca implicit ea să coincidă cu adresa locală (unde se află Tomcat). atunci acesta trebuie să fie prezent în: $CATALINA_HOME/common/lib/ spre a putea fi accesat de către containerul Tomcat. Atenţie! Pentru situaţiile în care se impune o parolă.2. 406 . Lăsăm pe seama cititorului să testeze aplicaţia Note prin JNDI şi pe celelalte tipuri de baze de date prezentate în 3.

You're Reading a Free Preview

Download
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->