Documente Academic
Documente Profesional
Documente Cultură
Cuprins
Modulul 1: Swing notiuni de baza si componente
1.1
Majoritatea aplicatiilor astazi folosesc o interfata grafica, ce are importantul rol de comunicare intre
utilizator si computer. Diferenta intre lucrul cu o consola penru folosirea unei aplicatii software si o
interfata grafica este aceea ca interfata grafica interactioneaza in mod direct cu utilizatorul si creeaza
astfel un mediu user-friendly. Orice aplicatie software ce are ca destinatie finala un utilizator
oarecare ( fara experienta in domeniu IT ) trebuie sa foloseasca obligatoriu o interfata grafica (GUI
Graphic User Interface) deoarece aceasta este mult mai usor de invatat chiar si pentru cineva care nu
a avut tangente cu programul respectiv.
Exista mai multe metode de dezvoltare a interfetelor grafice cu Java. Ne amintim de modalitatile de
creare de appleturi folosind pachetul java.awt si de metodele de dezvoltare a aplicatiilor stand-alone
cu pachetul java.swing; Swing este tehnologia pe care o vom folosi in continuare pentru dezvoltarea
tuturor aplicatiilor la cursul de Java 2 Advanced, de aceea vom face un studiu aprofundat in
primele doua module ale cursului pentru a intelege pe deplin toate componentele pe care le vom
folosi in vederea dezvoltarii aplicatiilor cu baze de date sau cu comunicare la nivelul unei retele.
Laboratoarele la acest curs le vom dezvolta in mediul de programare NetBeans. Puteti descarca
aplicatia gratuit de pe siteul official NetBeans www.netbeans.org ;
Pentru inceput sa ne amintim modul de creare a unei ferestre folosind tehnologia swing. Clasa
JFrame este cea care descrie un obiect de tip fereastra. O fereastra este de asemenea un container,
ceea ce inseamna ca poate sustine alte componente. Fereastra este princialul obiect de tip container
folosit pentru crearea unei interfete grafice pentru o aplicatie software.
Putem observa caracteristica de container a unei ferestre din ierarhia de mostenire a claselor:
java.lang.Object
java.awt.Component
java.awt.Container
java.awt.Window
java.awt.Frame
javax.swing.JFrame
JFrame()
JFrame(String s)
Cel mai des vom folosi al doilea constructor pentru crearea instanelor de ferestre.
5
setIconImage(Image i)
setLayout(LayoutManager lm)
setJMenuBar(JMenuBar mb)
Pentru inceput sa vedem modul de dezvoltare a unei aplicatii care sa deschida o fereastra de tip
JFrame:
Dupa deschiderea aplicatiei NetBeans va trebui sa continuam cu deschiderea unui nou proiect pentru
a creea aplicatia ceruta. Pentru a crea un proiect nou trebuie fie sa apasam optiunea New Project din
meniul File, fie sa folosim scurtatura din taste Ctrl Shift N. Imaginile de mai jos va arata modul
de creare a unui proiect nou cu NetBeans.
Dupa acest pas trebuie sa denumim proiectul. Numele folosit de mine a fost Aplicatie1;
Dupa deschiderea ferestrei de editare a clasei principale a programului Main, scrisa in fisierul
Main.java, ce contine si metoda main(), se poate continua cu scrierea aplicatiei.
Fara a creea un alt fisier, am scris o aplicatie care deschide o fereastra la pornirea acesteia.
Pentru inceput fereastra apare fara o dimensiune in coltul din stanga sus al ecranului. Pentru a ii seta
acesteia o dimensiune si o pozitie default de deschidere putem folosi fie metoda setBounds(): definita
astfel:
10
1.2
Totusi, pana in prezent nu am reusit decat crearea unei ferestre prin instantierea clasei JFrame.
Desigur, pe aceasta instanta de fereastra am putea foarte usor sa adaugam alte componente, cum ar fi
butoane, campuri de text sau etichete pentru afisare, totusi modalitatea de dezvoltare a unei aplicatii
software profesionale nu este aceasta.
In continuare vom dezvolta o clasa care instantiaza obiecte de tip fereastra ce au dj aplicate pe
acestea un buton. Practic, acesta este modul in care se dezvolta ferestre utile in asamblarea unui
program. Vom denumi aceasta clasa: FereastraPrincipala; Pentru a crea o clasa noua in cadrul
aplicatiei noastre in NetBeans mai intai vom da click dreapta pe aplicatie1, din interiorul proiectului
dezvoltat de noi. Acesta este folderol de contine fisierul Main.java; Pe meniul pop-up deschis dupa
click dreapta din optiunea New vom allege Java Class;
11
Dupa denumirea noului fisier FereastraPrincipala putem modifica continutul acestuia in editorul de
text care s-a deschis in partea dreapta.
Aici vom importa pachetul javax.swing imediat dupa apelul instructiunii package:
12
import javax.swing.*;
Este necesar pentru inceput sa mostenim clasa JFrame; pentru acest lucru folosim keyword-ul
extends, asa cum dj stim. Definitia clasei devine:
Singurul atribut al obiectului de tip FereastraPrincipala in acest caz este un obiect de tip buton;
Dupa cum ne amintim obiectul de tip buton este definit in clasa JButton. Cu acesta clasa putem
defini butoane cu text sau cu imagine. Pentru inceput vom folosi constructorul pentru definirea unui
buton cu text;
13
public
public
public
public
JButton ();
JButton(String text);
JButton(Icon ico);
JButton(String text, Icon ico);
Vom trimite paramentrul catre constructorul clasei pe care o mostenim cu ajutorul metodei super(),
ce trebuie neaparat apelata ca prima linie a cosntructorului pe care il descriem;
Mai departe adaugam pe fereastra butonul cu sintaxa getContentPane().add(b);
In acest moment putem spune am am terminat construirea clasei FereastraPrincipala;
Revenim la clasa Main unde cream o instant a obiectului FereastraPrincipala si il pozitionam pe
ecran.
14
Daca dorim ca butonul nostru sa fie reprezentat si de o imagine pe langa text va trebui sa folosim
constructorul:
Vom face cateva modificari in clasa FereastraPrincipala; Atrubutele clasei vor deveni:
public Icon imi = new ImageIcon("animal.jpg");
public JButton b = new JButton("Maimutzica",imi);
Imaginea animal.jpg am adaugat-o in directorul din proiect in care se afla si fisierele sursa si in cel
in care se afla clasele compilate (fisierele cu extensia .class).
Iata si rezultatul obtinut la executia programului care deschide o fereastra pe care se afla un buton cu
imaginea aleasa de mine "animal.jpg".
15
In continuare vom modifica textul de pe buton (label-ul butonului) la apasarea acestuia. Desigur
exemplul este unul clasic de folosire a evenimentului de tip ActionEvent si va ajuta sa intelegeti sau
sa va amintiti modul in care comandam executia unei instructiuni la apasarea unui buton.
Pentru inceput este necesar sa importam pachetul java.awt.event;
import java.awt.event.*;
16
17
18
1.3
Pentru inceput vom crea un proiect nou. Pe acest proiect eu l-am denumit Aplicatie2. Dupa
deschiderea editorului pentru fisierul Main.java putem incepe scrierea programului prin dezvoltarea
clasei Main. Vor trebui importate pachetele javax.swing si java.awt.
import java.awt.*;
import javax.swing.*;
In interiorul clasei vom defini global o instanta a unui obiect de tip JFrame cat si o instanta de obiect
de tip JButton. Fereastra creata va fi componenta container pe care vom experimenta aplicarea
managerilor de pozitionare (Layout Managers) iar butonul va fi componenta pozitionata in container.
Asa cum va fi pozitionat in aceste exemple butonul in fereastra, similar este efectul si pentru orice
alta compoenta grafica (Eticheta, camp de text sau un alt container) la pozitionarea pe un anumit tip
de container(fereastra, panou sau applet).
Dupa instantierea celor doua clase (JFrame si JButton) in interiorul metodei main() adaugam butonul
pe interfata ferestrei. Atentie la modul de definire global a celor doua instante de obiecte. Este
necesar si obligatoriu sa folosim modificatorul "static", deoarece urmeaza sa folosim cele doua
instante in interiorul metodei main() care este prin definitie statica. Ne amintim ca o metoda statica
nu poate apela si folosi decat alte metode sau variabile statice.
19
20
la stanga: FlowLayout.LEFT
la dreapta: FlowLayout.RIGHT
pe centru: FlowLayout.CENTER
justify spre stanga: FlowLayout.LEADING
justify spre dreapta: FlowLayout.TRAILING
Default este stata constanta CENTER, prin urmare ne asteptam ca butonul sa fie asezat pe primul
rand pe centru adica in partea de sus a ferestrei, pozitionat central.
21
Modul in care sunt ordonate componetele poate fi precizat inca de la instantierea obiectului
FlowLayout, deoarece unul dintre constructori primeste ca parametru constanta de pozitionare. In
cazul in care nu am instantiat obiectul de la inceput cu constanta dorita putem folosi mutatorul
setAlignment(int aling) pentru setarea ulterioara a modului in care dorim sa fie pozitionate
componentele pe container. Aceasta metoda primeste ca paramentru una dintre constantele
prezentate mai sus. In exemplul urmator eu am folosit direct constructorul pentru definirea modului
de aliniere al butonului:
22
Ne asteptam dupa scrierea acestui cod ca butonul sa fie pozitionat pe primul rand in partea stanga,
adica in coltul din stanga sus al ferestrei:
Desigur daca dorim alinierea la drepta a componentei vom folosi constanta RIGHT:
23
24
Pentru a vedea efectul constantelor LEADING si TRAILING vom mai adauga doua butoane pe
fereastra:
25
26
Observam ca in functie de marime ferestrei componentele sunt asezate pe mai multe randuri sau nu.
In imaginea de mai jos am incercat redimensionarea cu mouse-ul a ferestrei astfel incat am ajuns cu
fiecare buton pe un rand:
Spatiul care se afla intre randuri si cel dintre componente poarta denumirea de "gap" (en. crapatura).
Distanta dintre componentele de pe un rand are denumirea de "horizontal gap" iar cea dintre
randurile de componente de "vertical gap". Default aceasta distanta este de 5 pixeli, dar ea poate fi
modificata in doua moduri. Unul dintre constructorii FlowLayout permite setarea acestor distante.
Acest constructor are urmatoare definitie:
27
28
In exemplul urmator vom dezvolta o clasa care mosteneste JFrame. Pe aceasta vom seta default
managerul de pozitionare FlowLayout.
In clasa fereastra butonul devine unul dintre atributele clasei. Adaugarea butonului pe fereastra se
face in interiorul constructorului, deoarece acesta face parte din fiecare instanta creata a obiectului
fereastra. Sintaxa de adaugare a componentei este:
getContentPane().add(b);
getContentPane().setLayout(new FlowLayout(FlowLayout.LEFT));
29
Dupa salvarea clasei Fereastra in clasa main construim global o instanta de Fereastra pe care o setam
vizibila si ii dam o marima default.
30
Iata rezultatul:
31
1.4
JPanel si BorderLayout
JPanel este o componenta de tip container ce ne ajuta in principal la pozitionarea altor componente
pe ferestre, deci la crearea interferelor grafice. Un panou nu este vizibil - by default - si nici nu a fost
construit pentru a il face vizibil. Pentru inceput, pentru a putea vedea pozitionarea unei astfel de
componente vom colora fundalul panoului.
In urmatoarea aplicatie vom pozitiona un panou intr-o fereastra. Panoul va fi plasat default adica de
un manager BorderLayout.CENTER, iar pe panou vom plasa un buton in partea dreapta folosind
LayoutManager-ul FlowLayout();
Voi construi pentru inceput un nou proiect - Aplicatie3; In metoda main(), dupa importarea
pachetelor necesare voi construi o instanta de JFrame, o instanta de JPanel si o instanta de JButton.
Cele trei for fi definite global, dar toate fiind neaparat precedate de modificatorul "static";
public static JFrame f = new JFrame("Fereastra");
public static JPanel p = new JPanel();
public static JButton b = new JButton("Buton");
In interiorul metodei main(), voi adauga panoul pe fereastra folosind metoda add() specifica
containerelor:
f.add(p);
Tot cu ajutorul metodei add() voi adauga butonul pe panou. Exista doua metode de a seta un manager
de pozitionare pe un panou. Fie folosind deja cunoscuta metoda setLayout(), fie dand o instanta a
managerului ca paramentru constructorului JPanel. In aceasta aplicatie am ales sa modific
instantierea obiectului JPanel in:
JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT));
32
33
Sa incercam cateva exemple cu fiecare constanta aplicata panoului creat. Pentru a vedea mai usor
pozitionarea acestuia vom colora fundalul panoului in rosu. Acest lucru se face cu ajutorul metodei
setBackground(Color c) - sintaxa folosita pentru colorarea fundalului panoului fiind:
p.setBackground(Color.red)
34
35
1.5
JLabel si GridLayout
GridLayout()
GridLayout(int randuri, int coloane)
GridLayout(int randuri, int coloane, int hgap, int vgap)
setHgap(int gap)
setVgap(int gap)
Si numarul de randuri si de coloane poate fi modificat sau setat ulterior dupa instantierea obiectului.
Pentru aceasta exista mutatorii:
setColumns(int coloane)
setRows(int randuri)
Acestea fiind spuse sa incercam exemplificarea unei iterfete cu o fereastra pe care este setat
managerul GridLayout:
Dupa crearea unui nou proiect pe care l-am numit aplicatie4, am deschis un nou fisier Fereastra.java,
pentru dezvoltarea clasei Fereastra. Aceasta clasa mosteneste JFrame si are un atribut vector de
etichete. Obiectul eticheta este descris de clasa JLabel si foloseste la afisarea fie a unui text, fie a
unei imagini. Pe fereastra intentionez sa afisez 20 de etichete pe 4 randuri si 5 coloane. Pentru acesta
va trebui sa setez un manager de tip GridLayout initializat corespunzator.
GridLayout(4,5);
Imediat dupa setarea managerului de pozitionare initializez fiecare eticheta in parte si le adaug pe
toate cu ajutorul unei structuri de control repetitive "for";
37
Pentru a vedea rezultatul, in clasa principala (Main) voi instantia clasa fereastra si voi afisa fereastra
cu cele 20 de instante JLabel;
38
Pentru afisarea unei imagini avem nevoie de un obiect de tip Icon; Acesta este instantiat cu ajutorul
clasei ImageIcon;
Icon ico = new ImageIcon("animal.jpg");
Am adaugat imaginea corespunzatoare "animal.jpg" in directorul proiectului. Folosind constructorul
JLabel(Icon i) am instantiat clasa JLabel construind astfel o eticheta care afisaza o imagine.
Metoda setDefaulCloseOperation() careia i-am trimis ca argument JFrame.EXIT_ON_CLOSE
(constanta de tip int) se ocupa de inchiderea programului odata cu inchiderea ferestrei. Acesta
metoda este specifica clasei JFrame;
39
Daca dorim sa afisam pe eticheta respetiva atat text cat si o imagine vom folosi constructorul
JLabel(String s, Icon i, int horizontalAlignement)
40
Vom folosi eticheta (JLabel) de acum incolo ca instrument de iesire - modalitate de afisare a
rezultatelor.
1.6
Probabil ca fiecare a folosit macar o data o aplicatie Microsoft Office. Sa luam drept exemplu
aplicatia Microsoft Word. La deschiderea unui document pentru editare text, editorul deschide in
interiorul aplicatiei reprezentata de o fereastra principala, o fereastra interioara in care se poate face
procesarea proproiu-zisa a continulului documentului. Aceasta lectie va prezenta in amanunt modul
in care putem dezvolta in java ferestre interioare ( altfel spus - ferestre in interiorul altor ferestre).
Pentru a dezvolta ferestre interioare avem nevoie de clasa JInternalFrame.
Cei mai importanti doi constructori pentru clasa JInternalFrame sunt:
42
43
In acest fel am creat o fereastra interioara default. Aceasta nu se poate minimaliza si nici nu poate fi
redimensionata. Mai jos vom construi o fereastra interioara careia ii vom da permisiuni de
redimensionare si minimalizare.
44
Cu ajutorul clasei cursor putem seta aparitia unui anumit tip de cursor deasupra unei anumite
componente. Clasa Cursor are urmatorii doi constructori:
Primul constructor creaza o instanta de cursor setata in sistemul de operare de un anumit tip. Iata
cateva constante ce definesc tipuri de cursor:
CROSSHAIR_CURSOR
DEFAULT_CURSOR
E_RESIZE_CURSOR
HAND_CURSOR
MOVE_CURSOR
TEXT_CURSOR
WAIT_CURSOR
45
1.7
Cu siguranta fiecare dintre voi a vazut si a folosit pana acum butoane de selectie.
Aceste butoane, dupa cum le spune si numele sunt folosite pentru selectarea a diferite optiuni
predefinite de catre utilizator.
Butoanele de selectie sunt de doua feluri: Checkbox si Radiobutton;
In principal butoanele de tip checkbox sunt definite separat pentru a se putea selecta mai multe
butoane, prin urmare mai multe optiuni date utilizatorului sunt disponibile simultan.
Butoanele radio sunt de obicei folosite pentru a nu permite utilizatorului sa selecteze decat o singura
optiune dintr-un grup.
Un exemplu mai concret ar fi:
Sa ne imaginam ca in setarile unui program pe care il cream trebuie sa oferim posibilitatea
utilizatorului de a schimba rezolutia monitorului in raport cu programul.
46
In acest caz ar trebui sa folosim butoane de tip radio, deoarece utilizatorul nu are voie sa selecteze
decat o singura rezolutie dintr-un grup de optiuni pe care il definesre programatorul.
Daca insa utilizatorul trebuie sa selecteze mai multe optiuni programatorul trebuie sa defineasca
pentreu acestea butoane de tip checkbox.
Clasa JCheckBox este cea care defineste butoanele de tip checkbox. Clasa JCheckBox face parte din
pachetul javax.swing; Iata cateva detalii despre clasa si constructor:
Cei mai importanti constructori ai clasei sunt urmatorii:
1. public JCheckBox()
2. public JCheckBox(String text)
3. public JCheckBox(String text, boolean selected)
47
Primul constructor creeaza un buton simplu, neselectat si fara o eticheta aplicata acestuia. Eticheta
este textul ce apare dupa buton si defineste optiunea care poate fi sau nu selectata de utilizator.
48
49
Cu ajutorul celui de-al treilea constructor se poate defini si starea butonului. Acesta poate fi selectat
sau neselectat. Daca cel de-al doilea argument al constructorului este true atunci butonul este selectat
iar daca acesta este false butonul ramane neselectat.
50
1. public JRadioButton()
2. public JRadioButton(String text)
3. public JRadioButton(String text, boolean selectat)
Primul constructor creeaza un buton de tip radio fara textul de eticheta ce reprezinta optiunea ce
poate fi selectata de utilizator. Al doilea este constructorul care defineste instanta acestei clase
urmata de un text de eticheta.
51
Daca folosim cel de-al treilea constructor ca in exemplul primului buton din imaginea de mai sus
acesta functioneaza idem celui de la constructia instantei JCheckBox. Daca al doilea argument este
true butonul este predefinit selectat. Daca acesta este false el ramane neselectat.
O observatie interesanta este ca cele trei butoane din exemplul de mai sus nu se comporta asa cum
ne-am astepta sa se comporte niste butoane de tip radio. Acestea pot fi selectate mai multe. Pentru a
le face sa se excluda voi adauga butoanele unui grup de butoane:
52
In acest moment din grupul de butoane creat nu mai poate fi selectat decat unul singur odata. Grupul
de butoane este definit de clasa ButtonGroup ce apartine tot pachetului javax.swing;
1.8
Butoane de selectie
O alta clasa importanta atunci cand folosim butoane de selectie este ButtonGroup. ButtonGroup
permite adaugarea butoanelor de tip radio (folosite pentru selectie simpla) intr-un grup. Astfel, dintrun grup e butoane poate fi selectata o singura optiune. In imaginile de mai jos aveti exemple de
folosire ale celor patru clase enumerate mai sus care definesc tipuri de butoane de selectie:
JCheckBox:
54
55
Folosind consructorul care primeste ca al doilea parametru o valoare boolean putem preciza daca
butonul creat este implicit selectat sau nu.
56
JRadioButton:
57
58
Din pacate, dupa cum observati mai sus nu putem selecta o singura optiune chiar daca butoanele sunt
de tip radio. Pentru a crea un grup de butoane din care sa se poate electa numai o singura optiune se
poate folosi clasa ButtonGroup dupa cum puteti vedea mai jos:
59
JCheckBoxMenuItem:
Asa cum ii spune si numele clasa JCheckBoxMenuItem este o optiune de meniu. Aceasta
functioneaza similar clasei JCheckBox dar este construita pentru a atasa instantele unui meniu nu
unui panu sau unei ferestre:
60
61
JRadioButtonMenuItem:
Clasa JRadioButtonMenuItem functioneaza similar clasei JRadioButton, dar instantele acesteia
sunt create special pentru a putea fi adaugate pe meniuri. Tot cu ajutorul clasei ButtonGroup se poate
crea un grup de butoane JRadioButtonMenuItem din care se se poata selecta o singura optiune.
62
63
Se poate verifica daca un buton de selectie este selectat folosind comportamentul isSelected(). Daca
isSelected() returneaza true atunci butonul este selectat, in caz contrar acesta nu este selectat.
1.9
Clasa JComboBox
JComboBox este clasa cu ajutorul careia cream o lista drop-down. Cele mai des folosite
comportamente pentu clasa JComboBox sunt:
64
65
66
67
Crearea unui tabel cu un numar de randuri si de coloane predefinit fara informatii implicite poate fi
creat folosind constructorul:
public JTable(int rows,int cols) - primeste numarul de linii si de coloane prin parametrii si
creaza tabelul
68
69
70
71
JTextArea:
Componenta JTextArea afisaza un camp de text cu linii si coloane folosit in general pentru afisarea
sau introdcerea unui text de dimensiuni mai mari.
72
Un text poate fi setat in campul de text folosind metoda setText() care primeste ca parametru un
String reprezentand sirul de caractere ce va fi adaugat in componenta text. Textul din componenta
poate fi obtinut prin apelul comportamentului getText() care returneaza situl de caractere sub forma
unui String.
Clasa JTextArea are comportamentul append() care primeste ca parametru un String pe care il
adauga in campul text.
JPasswordField:
Clasa JPasswordField defineste un camp de text similar lui JTextField, doar ca acesta ascunde
caracterele introduse. Este folosit in principal pentru campuri in care sunt introduse parole.
73
74
75
76
77
78
Exista si posibilitatea de a seta un text initial si o lungime a componentei diferita de cea a textului
initial. Pentru asta vom folosi ultimul constructor:
Cele mai importante metode ce definesc comportament al instantelor JTextField sunt getText() si
setText(String s). Aceste metode folosesc pentru preluarea textului dintr-un camp de text sub forma
de obiect String sau setarea unui text pentru instanta de JTextField.
Iata cum se poate folosi metoda getText();
JTextFIeld t = new JTextField("Text initial");
String s = t.getText();
// in acest moment variabila s retine textul "Text initial" pe care il contine si componenta text
Metoda setText(String s) primeste ca argument String-ul care trebuie atasat compoentei text;
t.setText("un text");
79
80
Pentru a crea o componenta cu mai multe linii am folosit caracterul \n cu semnificatia new line.(linie
noua)
Iata si un exemplu de componenta creata cu un text initial pe mai multe linii:
81
Constructorul JTextArea(int rows, int cols) defineste o componenta JTextArea cu un numai initial de
randuri si de coloane fara a avea un text predefinit:
82
In imaginea de mai sus aveti exemul de instantiere a unei componente text cu 10 linii de 20 de
coloane, dar fara text initial. Daca dorim ca aceasta sa contina si un text initial vom folosi ultimul
constructor enumerat.
83
Numele reprezinta numele fontului, stilul este dat ca o constanta ce apartine clasei Font, iar size
reprezinta marimea textului.
Cateva constante folosite frecvent din clasa Font sunt:
BOLD
ITALIC
MONOSPACED
PLAIN
SANS_SERIF
ROMAN_BASELINE
TRUETYPE_FONT
Se observa in imaginea de mai sus ca textul din componenta JTextArea si-a modificat fontul;
84
85
86
Metodele care pot fi folosite pentru preluarea sirului din componenta text este fie getText(), metoda
ce returneaza sirul sub forma unei instante String sau getPassword(), metoda ce returneaza sirul de
caractere sub forma unui vector de primitive char[]
2.4 Meniuri
Pentru a dezvolta o aplicatie cu un meniu simplu avem nevoie de cel putin trei clase care descriu
componente indispensabile. Aceste clase apartin pachetului javax.swing si se numesc: JMenuBar,
JMenu si JMenuItem;
87
Pentru inceput cream o instanta de JMenuBar. Aceasta este bara de meniu din partea de sus a
ferestrei pe care sunt asezate mai multe meniuri. In cazul aplicatiei din exemplu nu am atsat barei de
meniu decat meniul "File". Un meniu este definit de clasa JMenu. Textul ce reprezinta numele
meniului se da ca argument sub forma de String la instantierea clasei:
JMenu m1 = new JMenu("File");
Cu ajutorul metodei add() putem adauga meniul pe bara de meniu. Bara de meniu se adauga pe
fereastra folosind metoda setJMenuBar(JMenuBar mb).
f.setJMenuBar(mb);
mb.add(m1);
88
Pe un meniu se pot aduga alte meniuri sau instante ale clasei JMenuItem. In exemplul anterior
"New..." este un JMenuItem.
JMenuItem mi1 = new JMenuItem("New...");
Un menu item poate fi adaugat pe un meniu tot cu ajutorul metodei add()
m1.add(mi1);
In imaginea de mai jos aveti un exemplu de aaugare a unui meniu in interiorul unui alt meniu:
In acest submeniu pot fi adaugate alte submeniuri definite tot cu ajutorul clasei JMenu sau instante
de JMenuItem:
89
Pentru a separa vizual mai multe elemente intr-un meniu putem folosi metoda addSeparator().
Aceasta metoda de separare a elementelor unui meniu este utila gruparii acestora dupa functiile lor:
90
Se poate observa in imaginea de mai sus efectul folosirii metodei addSeparator() intre cele doua
instante de JMenuItem "Open" si "Exit";
Pentru executarea unei actiuni la apasarea unui element al unui meniu se procedeaza exact ca in
cazul butoanelor. Acestea reactioneaza la evenimente de tip ActionEvent. In imaginea urmatoare
aveti un exemplu de inchidere a aplicatiei la apasarea elementului "Exit" din meniul "File" :
Desigur, nu uitati ca aveti nevoie si de importarea pachetului java.awt.event; In aces moment, dupa
compilare si executie fereastra ar trebui sa se inchida dupa apasarea elementului "Exit" din meniul
"File";
Exista de asemenea posibilitatea de a inlocui apasarea elementului din meniu cu apasarea unei
combnatii de taste pentru executarea instructiunilor. Pentru aceasta vom folosi metoda
setAccelerator(KeyStroke ks) in urmatorul fel:
KeyStroke ks = KeyStroke.getKeyStroke("control alt X"); // "control alt X" adica ctrl-alt-X
mi3.setAccelerator(ks);
Argumentul String dat metodei getKeyStroke() poate fi spre exemplu:
control alt X
control X
control shift X
alt shift X
91
shift X
etc ...
In loc de "X" poate fi orice alt caracter, iar variatiunile intre <<control>> <<alt>> si <<shift>> pot fi
diverse;
In imaginea de mai jos aveti si modul de aplicare in exemplu direct:
In acest exemplu aplicat pe programul creat anterior, programul ar trebui sa se inchida ala apasarea
tastelor CTRL-ALT-X;
Iata si modul in care arata acum componenta JMenuItem:
92
Daca dorim ca o instanta de JMenuItem sa nu mai fie activa vom folosi metoda setEnabled(boolean
b); In functie de valoarea parametrului b componenta careia i se aplica comportamentul va fi activa
sau nu; b poate avea valoare true, caz in care componenta este activa sau false, caz in care aceasta se
dezactiveaza; Sa incercam dezactivarea componentei JMenuItem "New":
93
94
In exemplul de mai sus am afisat cate un mesaj diferit la intalnirea diferitelor evenimente ale mouseului;
Instantele de JMenuItem pot fi facute sa sesizeze si evenimentele tastelor. Pentru aceasta vom folosi
metoda: addMenuKeyListener()
95
Iata exemplul in care am afisat un mesaj in functie de un eveniment al tastelor; Nu uitati sa trebuie
mai inati selectata componenta pentru a sesiza evenimentele tastelor; (ca in imagine)
96
Un ultim tip de eveniment pe care il poate sesiza o componente JMenuItem este daca utilizatorul il
selecteaza sau nu; Iata cum procedam pentru acest tip de verificare:
Proprietate
Tipul obiectului
97
MenuItem.acceleratorDelimiter
MenuItem.acceleratorFont
MenuItem.acceleratorForeground
MenuItem.acceleratorSelectionForeground
MenuItem.actionMap
MenuItem.arrowIcon
MenuItem.background
MenuItem.border
MenuItem.borderPainted
MenuItem.checkIcon
MenuItem.commandSound
MenuItem.disabledForeground
MenuItem.font
MenuItem.foreground
MenuItem.margin
MenuItem.opaque
MenuItem.selectionBackground
MenuItem.selectionForeground
MenuItem.textIconGap
MenuItemUI
String
Font
Color
Color
ActionMap
Icon
Color
Border
Boolean
Icon
String
Color
Font
Color
Insets
Boolean
Color
Color
Integer
String
98
99
Aidoma butoanelor de tip checkbox descrise de clasa JCheckBox din pachetul javax.swing acestea
sunt folosite pentru o lista de optiuni cu posibilitate de selectare multipla. Butoanele sunt in general
insotite de un label care poate fi un text sau o imagine ce descrie optiunea ce poate fi bifata de
utilizator. In imaginile de mai jos aveti exemplul crearii unei astfel de componente cu un label de tip
imagine:
100
101
102
103
104
105
106
107
108
109
Metoda showDialog() returneaza o instanta de java.awt.Color care reprezinta culoarea selectata daca
utilizatorul a selectat o culoare sau culoarea implicita daca acesta a apasat Cancel.
110
pentru crearea unei ferestre de dialog de salvare. Dupa selectarea unui fisier pentru salvare sau
deschidere in functie de metoda folosita fisierul poate fi preluat din instanta JFileChooser cu ajutorul
metodei getSelectedFile() sub forma unei instante java.io.File;
In exemplul de mai jos textul continut de campul JTextArea poate fi salvat in fisier:
112
113
Similar se poate selecta un fisier pentru deschidere folosind metoda showOpenDialog() in loc de
showSaveDialog().
114
115
116
Dupa pornire verificati ca statusul celor doua servere sa fie "Running" , ca in imaginea de mai sus;
Vom incepe dezvoltarea bazelor de date folosind aplicatia PHP gratuita numita phpmyadmin ce se
instaleaza odata cu instalarea xampp. Aplicatia phpmyadmin se poate accesa dupa deschiderea
serverelor Apache si MySQL din orice browser accesand adresa 127.0.0.1/phpmyadmin; IP-ul
127.0.0.1 este cunoscut si sub numele de ip de loopback si este adresa care face referire catre
sistemul de unde se face accesarea;
117
3.2 Entitati
cnp
nume
prenume
facultate
grupa
an
data_nasterii
Dintre atributele pe care le-am enumerat ci care pot descrie entitatea Student "cnp" ar putea fi cel
care sa devina si cheie primara a acestei entitati; De ce? Pentru ca este singurul atribut ce ia valori
unice in functie de fiecare entitate de student inregistrata. Practic "cnp" este singurul atribut care cu
siguranta va fi unic fiecarui student in baza noastra de date.
Oricare dintre celelalte atribute pe care le-am ales se pot avea valori diferite pentru diferite
inregistrari. De exemplu pot exista doi sau mai multi Studenti cu numele George; Pot exista doi sau
mai multi studenti nascuti in aceeasi zi si cu siguranta mai multi studenti vor apartine aceleiasi
facultati sau aceleiasi grupe;
Mai jos aveti modul de descriere schematic al unei entitati. O entitate este denumita de obicei cu un
substantiv la singular (Ex. Student, Animal, Structura, Cont etc.). Acesta este desenata cu un
dreptunghi cu colturi rotunde denumit "soft-box". Acest dreptunghi incadreaza atributele entitatii.
Atributele pot fi marcate cu trei simboluri: #, o sau *;
# - inseamna ca atributul este primary key
o - inseamna ca atributul este mandatory (obligatoriu)
* - inseamna ca atributul nu are restrictii
118
Cheia primara "cnp" dupa care am ales sa identificam inregistrarile entitatii Student se numeste cheie
primara cu caracter real; De obicei atributele cu caracter real nu sunt folosite ca primary key. Pentru
oricare entitate pe care o vom crea vom defini un atribut numit "id", care va avea rol de cheie
primara si care va fi un numar incrementat pentru fiecare inregistrare noua. Acest mod de creare a
cheii primare se numeste "cheie primara cu caracter artificial".
Aceste inter-relationari sunt gandite in momentul in care dezvoltam baza de date teoretic. Pentru
dezvolotarea bazei de date este necesar mai apoi sa ajustam relatii intre entitati astfel incat sa nu
existe relatii many-to-many, acestea fiind dificil de controlat in momentul executiei programului de
interfatare pe care il dezvoltam cu java. Ralatiile intre entitati se fac prin intermediul cheilor primare
si se pot referi la oricare dintre atributele entitatilor care relationeaza.
Relationarea unu-la-unu este cel mai simplu tip de relatie intre doua entitati. Pentru a intelege acest
tip de relationare vom presupune urmatoarele doua entitati:
Culoare
Birou
120
o prenume
o materie
o elev
Elev
#id
o nume
o prenume
o cnp
o profesor
Observam ca daca cele doua entitati ar fi descrise in acest fel, pentru fiecare profesor ar trebui sa
facem mai multe inregistrari, in functie de cati elevi are, iar pe fiecare elev ar trebui sa il inregistram
de atatea ori cati profesori are. Acest lucru ar insemna pierderea unicitatii fiecarei inregistrari. Este
practic inposibil de facut practic aceasta relationare in vederea dezvoltarii unei baze de date fiebile.
Iata prin urmare ce modificari vom face pentru ca fiecare inrgistrare de entitate Elev sau Profesor sa
isi pastreze unicitatea:
Profesor
#id
o nume
o prenume
o materie
Elev
#id
o nume
o prenume
o cnp
Registru
#id
o profesor
o elev
Am scos atributele elev si profesor ale entiatilor initiale. Mai apoi am dezvoltat entitatea Registru
care are rolul de mediere intre cele doua entitati Elev si Profesor. Practic, nu inregistram decat datele
fiecarui elev si a fiecarui profesor, apoi in Registru facem referintele necesare intre inregistrari;
123
O alta gresala care se poate face este asignarea unor atribute entitatilor care se pot deuce unul din
altul. Exemplu - in vederea atributului Angajat
Angajat
#id
o nume
o prenume
o data_nasterii
o varsta
La dezvoltarea acestei entitati am asignat atributele "data_nasterii" si "varsta". In acest caz atributul
"varsta" este inutil asignat, deoarece varsta unu angajat se poate afla folosind atributul
"data_nasterii".
124
In imainea de mai sus sunt create trei campuri pentru stocarea unui singur tip de informatie: numarul
de telefon. Modalitatea aleasa este gresita, deoarece nu permite flexibilitate. In locul acestei abordari
ar fi trebuit creata separat o tabela telefoane care sa relatoneze one-to-many cu tabela persoane:
2. Intrducerea de informatii redundante se refera la adaugarea unui camp intr-o tabela care retine o
informatie ce poate fi obtinuta folosind valoarea altui camp. De exemplu tabela persoane de mai jos
contine campul varsta care este redundant, deoarece exista un camp numit data_nasterii cu ajutorul
caruia se poate afla foarte usor varsta:
125
3. Crearea buclelor in relatii apare in momentul in care o entitate relationeaza cu alte doua entitati
care au o relatie intre ele prin aceleasi chei externe. In acest caz una dintre relatii este suplimentara,
ea putand fi dedusa din celelalte doua.
126
Numeric
Date and Time
String
Spatial
11. BOOL
12. SERIAL
Tipurile date and time sunt:
1.
2.
3.
4.
5.
DATE
DATETIME
TIMESTAMP
TIME
YEAR
CHAR
VARCHAR
TINYTEXT
TEXT
MEDIUMTEXT
LONGTEXT
TINYBOLB
BOLB
LONGBOLB
Tipurile de date spatiale definesc puncte sau figuri geometrice regultate sau neregulate; In general
dintre toate tipurile de date enumerate la acestcurs vom folosi:
In principal vom prefera crearea relatiilor dintre entitati (acum tabele) prin interfata programata.
Exista posibilitatea de a relationa tabelele prin instructiuni SQL lacrearea tabelelor, dar, din motive
didactice voi prezenta relationarea tabelelor prin intermediul interfetei programate in Java.
Cheia primara sau unicitatea unui atribut reprezinta proprietati ale coloanelor in tabela ce reprezinta
o anumita entitate. Acestea se seteaza la crearea unei tabele.
129
Pentru carearea tabelei Elevi din lectia anterioara vom completa in continuare caseta de text
corespunzatoare numelui tabelei pe care o cream si numarul de campuri (coloane) pe care le va avea
tabela; In cazul nostru tabela urmeaza sa aiba 6 campuri;
130
Completam fiecare cam cu informatiile (proprietatile) corespunzatoare acestuia: nume, tip de data
etc.
131
132
133
134
135
=
LIKE
NOT LIKE
!=
IS NULL
IS NOT NULL
Operatorii = si != testeaza egalitatea exacta si sunt in general folositi pentru compararea valorilor
numerice sau datelor; Operatorii LIKE sau NOT LIKE sunt folositi pentru compararea valorilor de
tip siruri de caractere; Ultimii doi operatori enumerati nu necesita precizarea unei valori, acestia
avand rolul doar de a verifica daca inregistrarea are campul respectiv null sau non-null;
Exemplu:
SELECT * FROM `elevi` WHERE `nume` LIKE 'ion';
SELECT * FROM `elevi` WHERE `varsta` = 14;
SELECT * FROM `elevi` WHERE `varsta`!=12;
SELECT * FROM `elevi WHERE `nume` IS NOT NULL;
136
137
Dupa modificare se observa ca la selectare atributul nume al primei inregistrari are valoarea George;
140
141
142
Pentru a va usura munca in studiu puteti downloada versiunea 5.1.6 a Connector/J de pe urmatorul
link: download
Practic aplicatia noastra va functiona dupa schema:
APLICATIE <=> CONNECTOR/J <=> SERVER MySQL
Dupa downloadarea arhivei veti folosi din interioarul acesteia pentru crearea aplicatiei pachetul
mysql-connector-java-5.1.6-bin.jar
Pachetul mysql-connector-java-5.1.6-bin.jar va fi copiat in folderul specific proiectului NetBeans (de
obicei NetBeans salveaza proiectele in folderul My Documents/NetBeansProjects). Vom copia
aceasta arhiva jar in folderul proiectului pentru a nu modifica valoarea variabilei CLASSPATH.
AM creat proiectul SQL1; Pentru acest proiect am exemplificat modul in care am importat libraria
din pachetul mysql-connector-java-5.1.6-bin.jar
143
144
145
Este important sa tratam fiecare exceptie si sa afisam mesajele de eroare pentru a identifica usor
probeleme in cazul in care acestea apar. Daca nu afisam eroarile care pot fi aruncate va fi foarte greu
sa depanam aplicatia; Am folosit o structura try-catch in vederea tratarii exceptiilor ce pot aparea;
Pasul 2: Se creaza o baza de date
Voi folosi baza de date mydatabase deja existanta (am creat-o si folosit-o in modulele anterioare);
Puteti crea o baza de date noua in vederea construirii aplicatiei; Nu confundati baza de date cu tabela.
O baza de date poate avea una sau mai multe tabele ce relationeaza. In cazul meu tabela este elevi.
Pasul 3: Se creeaza o conexiune
Folosind metoda statica getConnection() din clasa DriverManager cream conexiunea cu serverul
MySQL; In fapt cream o conexiune directa la o baza de date creata ( mydatabase ).
Metoda getConnection() primeste trei parametri: o adresa (String), un user (String) si o parola
(String); Vom folosi userul root care default nu are parola setata;
146
147
Voi folosi o structura repetitiva while(){} pentru a parcurge randurile tabelului; Pentru ca nu stiu
numarul de inregistrari voi folosi sintaxa: while(rs.next()) {} care se traduce prin: "cat timp mai
exista un rand";
In interior voi folosi un for pentru a parcurge coloanele de la 1 la 7; (incepe cu 1 nu cu 0 ca la
tablouri):
while(rs.next()){
for(int i=1;i<7;i++) System.out.print(rs.getString(i)+" ");
System.out.println();
}
Metoda getString(int i) returneaza sirul de caractere specific unei anumite coloane; Am avut grija sa
afisez atributele elevilor cu spatii intre ele si fiecare inregistrare pe alt rand;
148
System.out.print(rs.getString("nume")+" ");
System.out.print(rs.getString("prenume")+" ");
System.out.print(rs.getString("varsta")+" ");
Metoda getString() ne ofera posibilitatea de a accesa valorile unori campuri folosind numele
campurilor respective: nume, prenume, varsta etc.
Statement s = con.createStatement();
Pasul 2: Scrierea instructiunii MySQL
String sql = "INSERT INTO `mydatabase`.`elevi` (`id`, `cnp`, `nume`, `prenume`, `scoala`,
`varsta`) " +
"VALUES " +
"(NULL, '183903429043', 'Florin', 'Vasile', 'Colegiul Mihai Viteazu', '17')";
Pasul 3: Executarea instructiunii:
s.executeUpdate(sql);
Observati ca de aceasta data am folosit metoda executeUpdate(); Aceasta nu returneaza un ResultSet
asa cum se intampla la folosirea metodei executeQuery();
150
151
153
154
Dupa executie, daca raspunsul este Y sau y se poate verifica faptul ca cele doua interogari au fost
executate. In caz contrar va fi afisat un mesaj ca in imaginea de mai jos:
155
Constructorul trebuie sa primesca ca parametru instanta Statement. Folosind instanta Statement este
trimisa o interogare SELECT si este preluat un ResultSet. Instanta ResultSet este trimisa ca
parametru Clasei Model care defineste AbstractTableModel pentru tabelul creat si afisat pe fereastra:
La apasare pe buton sunt luate randurile selectate si folosind id-ul afisat in prima coloana sunt sterse
acele inregistrari. Prin apelul metodei refreshModel() definita mai jos este reactualizata modelul:
156
158
Apoi clasa Main creaza si afisaza o fereastra dupa ce realizeaza conexiunea cu serverul de baze de
date pornit local:
159
Rezultatul:
Dupa stergere:
160
161
162
163
Fereastra de adaugare are un formular format din doua componente text si un buton. La apasare pe
buton, folosind informatiile adaugate in componentele text este adaugata o noua inregistrare si
tabelul din fereastra principala este actualizat:
164
Rezultatul:
165
166
167
168
169
170
Rezultatul:
171
Creati un proiect nou in care vom incepe scrierea mai intai a clasei care mosteneeste JFrame si
descrie fereastra ce interactioneaza cu utilizatorul.
172
La crearea fiecarui proiect pentru aplicatii care lucreaza cu o baza de date nu uitati sa copiati
pachetul mysql-connector-java.jar in locatia proiectului dumneavoastra si apoi sa il importati ca
librarie prin NetBeans.
173
174
Verificati cu ajutorul phpMyAdmin daca exista baza de date si tabela. Daca acestea nu exista creatile si verificati in functie de numele pe care dumneavoastra la dati tabelelor si bazei de date sintaxa
corespunzatoare in crearea exercitiului.
In exemplul de mai jos tabela mea are campurile:
# id
o cnp
o nume
o prenume
o scoala
o varsta
Atentie. Nu confundati tabela cu baza de date. Baza de date are numele mydatabase si tabela are
numele elevi
175
Descrieti interfata ferestrei .Creati campuri pentru fiecare valoare care trebuie inserata. In exemplul
de mai jos am creat interfata folosind componente JLabel, componente JTextField (campurile text
pentru introducerea de informatie) si un buton la apasarea caruia se va introduce informatia in tabela.
De asemena aveti in vedere faptul ca nu am tratat toate exceptiile, decat cele care erau neaparat
necesare la conexiunea cu baza de date. Pentur dezvoltarea unei aplicatii profesionale, avand in
vedere cunostiinele voastre fundamentale incercati dupa finalizarea aplicatiei sa descoperiti ce alte
erori ar putea interveni ca urmare a incercarii inserarii unor valori necorespunzatoare si tratati aceste
exceptii.
176
177
178
Dupa setarea managerului de pozitionare si a componentelor urmeaza crearea unei instante in metoda
main pentru a observa interfata pe care am reusit sa o dezvoltam.
179
Metoda setResizable() este un comportament care poate primi ca parametru o valoare booleana. Daca
valoare este true atunci fereastra poate fi redimensionata, daca aceasta este false atunci ea nu poate
fi redimensionata.
180
Nu uitati ca pachetul java.sql trebuie importat pentru a putea lucra cu bazele de date MySQL.
181
Iata si respectarea catorva pasi pe care deja ii cunoasteti din lectia trecuta:
1. Incarcarea driverului
2. Crearea conexiunii
3. Preluarea informatiei care trebuie inserata si prelucrarea acesteia. Prelucrarea inseamna de fapt
adaugarea ghilimelelor simple de o parte si de alta a fiecarei informatii ce trebuie introdusa. Aceasta
regula face parte din limbajul MySQL (vezi capitolul ce se refera la sintaxa MySQL).
4. Crearea interogarii (Sirul cu comanda MySQL)
5. Crearea unei instante Statement pe baza conexiunii create anterior cu clasa Connection
6. Executarea interogarii prin metoda executeUpdate;
182
183
La sfarsit putetisterge continutul campurilor text dupa apsarea butonului si preluzarea informatiilor si
puteti desigur afisa exceptiile care pot fi intampinate in blocul try, prin apelarea metodei print in
blocul catch
184
Incercati aplicatia, verificati functionalitatea ei si daca aceasta nu functioneaza reluati pasii si gasiti
erorile.
185
Aplicatia are un panou amplasat in partea centrala a ferestrei si un buton cu eticheta "Deseneaza"
amplasat in partea de jos a ferestrei.
186
Pasii de creare a conexiunii sunt similari celor de la introducerea informatiilor, doar ca, de aceasta
data va trebui sa si retinem informatia trimisa de server dupa executarea interogarii SELECT. vom
retine informatia intr-o colectie ResultSet.
Metoda pentru executarea interogarilor select este executeQuery.
187
Urmeaza acum sa cream clasa Punct, apoi vom parcurge colectia pentru a stoca toate punctele intrun vector de puncte. Acesta va fi folosit ulterior pentru desenarea drumului pe interfata panoului.
188
189
Am parcurs folosind o structura repetitiva while(){} colectia si am creat pentru fiecare inregistrare un
obiect Punct intr-un vector.
Dupa aceasta am parcurs vectorul si am desenat pe interfata panoului prin suprascrierea metodei
paint
190
191
Folosim aceeasi pasi pe care i-am invatat la introducerea inregistrarilor, dar vom schimba sintaxa
MySQL cu instructiunea DELETE.
192
193
194
195
196
197
198
Incercam aplicatia si verificam daca s-au facut sau nu modificari in tabela puncte.
199
200
Afisand un mesaj dupa fiecare client care reuseste conexiunea se poate observa ca este posibil pentru
mai multi clienti sa se conecteze la server:
201
202
203
Clientul are o fereastra principala in care poate scrie un mesaj pe care il trimite catre toti ceilalti
clienti conectati:
204
205
206
layerul Transport o aloca. Aceasta se numeste port si reprezinta un numar ce denumeste procesul
care comunica in retea. Exista doua tipuri importante de porturi cu care ne vom intalni in dezvoltarea
programelor: porturi bine-cunoscute (well-known) si alte tipuri de porturi;
Porturile well-known sunt cele care descriu protocoale definite prin standarde internationale cum ar
fi spre exemplu HTTP, FTP, SMTP, IMAP, POP3...etc. Pe acestea le vom folosi atunci cand vom
avea nevoie de unul dintre aceste protocoale binecunoscute;
Porturile well-known sunt numere intre 0 si 1023.
Exemplu:
80 HTTP
25 SMTP
110 POP3
22 SSH
20, 21 FTP
etc...
Pentru a dezvolta alte tipuri de procese vom folosi numere mai mari de 1023 si pana in 65535.
Adresa IP impreuna cu portul se noteaza sub forma IP:PORT si se numeste Socket. Exemplu:
192.168.1.200:80 sau localhost:1234
Socketul este adresa de care o aplicatie are nevoie pentru a forma o conexiune. Trebuie sa existe un
Socket pe fiecare dintre participantii la comunicare.
O alta notiune esentiala este "ip de loopback" - Se numeste ip de loopback adresa 127.0.0.1 denumita
si standard localhost pentru orice sistem. Este adresa care face referire la sistemul local. Aceasta
adresa este importata pentru ca in majoritatea exemplelor voi folosi localhost sau 127.0.0.1, deoarece
aplicatiile care comunica se vor afla ambele pe acelas computer (cel pe care construiesc exemplul);
complexe. Iata despre ce este vorba. Vom crea o aplicatie server la care nu se poate conecta decat
maximum un client o singura data. Clientul va trimite o informatie si serveul o va procesa intr-un
anumit fel apoi va da un raspuns clientului. Ce este foarte primitiv la aceasta aplicatie este faptul ca
ea nu poate sa raspunda decat cerintelor unui singur client odata. Bineinteles, nicio aplicatie server
nu este utila decat atunci cand poate fi accesata de un numar mare de clienti pentru ca altmiteri am
prefera sa cream o singura aplicatie care sa proceseze informatia, nu doua.
Iata ce vom face ca exemplu: Serverul despre care vorbeam va primi un sir de caractere si il va
inversa folosind metoda reverse din clasa StringBuffer. Apoi va trimite clientului sirul inversat.
Dupa crearea unui proiect voi crea separat o clasa Server. Aceasta contine metoda principala main(),
deoarece, ne amntim, Serverul este o aplicatie independenta. Pentru inceput vom importa pachetele
necesare:
java.net - contine clasa ServerSocket si clasa Socket; Sa discutam cate ceva despre aceste doua clase;
Clasa Socket este cea care descrie o instanta Socket - instanta ce reprezinta un capat de conexiune.
Pentru a crea o conexiune avem nevoie de doua Socket-uri, unul ce reprezinta procesul serverului iar
celalat ce reprezinta procesul clientului. Cu alte cuvinte avem doua capete de conexiune intre care
formam o conducta de transfer a informatiei. Putem compara conexiunea cu o conducta prin care
curge informatia in doua sensuri: de la server la client si viceversa;
209
Clasa ServerSocket este cea cu ajutorul careia noi construim capatul conexiunii (Socket-ul) pentru
server. In momentul in care capatul conexiunii pe server se formeaza se creeaza practic intraga
conducta de comunicare, dar pentru ca noi nu stim pe ce sistem se afla aplicatia care urmeaza sa se
conecteze si prin urmare nu stim informatii despre acesta (cum ar fi ip-ul lui) nu putem crea in mod
direct un Socket. In acest caz folosim o instanta ServerSocket si metoda accept() care intrerupe firul
de executie al aplicatiei si asteapta pana la conectarea unui client, pentru a putea prelua informatiile
de la acesta necesarea pentru crearea conexiunii.
java.io - Contine clasele cu ajutorul carora vom crea fluxurile de informatii pe conducta creata intre
doua socketuri;
210
Neaparat vom trata exceptiile care ar putea sa apara din cauza imposibilitatii de conectare intre cele
doua sisteme.
211
Instanta ServerSocket are ca atribut principal portul pe care definim functionalitatea serverului.
Acest port trebuie sa aiba o valoare intre 1023 ssi 65535, adica nu una dintre valorile unui port wellknown; Dupa crearea instantei de ServerSocket apelam metoda accept() care intrerupe firul de
executie si asteapta returnarea unui Socket la conexiunea cu un client. Returnarea Socket-ului este
echivalenta cu crearea conductei de comunicare.
212
Dupa ce suntem siguri ca avem o comunicare putem defini fluxurile de intrari si de iesire prin acea
conducta creata intre cele doua socketuri. Facem acest lucru folosind clasele BuffereReader si
PrintWriter.
Metodele getOutputStream() si getInputStream() sunc comportamente ale unui Socket si ne ajuta sa
preluam practic fluxurile de la capatul unei conexiuni.
213
Algoritmul este simplu. Tot timpul ( while(true) ) serverul asteapta un sir de caracter de la client apoi
in momentul in care se primeste acesta il inverseaza si trimite inapoi sirul de caractere inversat. Dupa
ce isi trimna treaba ciclul revine la prima instructiune unde se astepata din nou un sir de caractere de
la client.
214
Ne amintim ca si aplicatia Client este o aplicatie independenta. Cu alte cuvinte contine o metoda
main() de la care incepe executia aplicatiei. Algoritmul este simplu: Aplicatia trebuie sa trimita un sir
introdus de utilizator de la tastatura si sa afiseze pe ecran (in consola) informatia primita de la
serverul dezvotlat in lectia anterioara;
215
216
Pasii sunt asemanatori, doar ca de aceasta data putem crea direct un Socket pentru ca un client
trebuie sa stie cu exactitate care este IP-ul si care este port-ul pe care se conecteaza. In cazul meu am
dat ca parametii "localhost", pentru ca voi porni serverul pe aclas omputer pe care creez si exemplul
de client si portul 4321 pe care i-am precizat mai devreme serverului ca trebuie sa asculte.
Clasa Socket primeste ca parametii la construirea instantei adresa serverului sub forma de obiect
String si portul pe care clientul se conecteaza. Adresa poate fi un nume sau o adresa IP.
Pe baza Socket-ului construim fluxurile de intrare si de iesire la conexiunea creata si cream si un flux
pentru citirea din consola (de la tastatura). Am preferat in acest exemplu sa ciresc de la tastatura
folosind tot clasa BufferedReader. Puteti totusi folosi o alta metoda daca considerati.
217
Intr-un ciclu while care teoretic repata instructiunile la infinit citesc un sir de caractere de la
tastatura, il trimit catre server, apoi preiau mesajul serverului si afisez pe ecran ce a trimis acesta.
218
Pentru ca ciclul wile sa poata fi intrerup pot sa conditionez acest lucru de exemplu prin valoarea
sirului introdus de utilizator, daca acesta este "papa" atunci se executa o instructiune break care
intrerupe ciclul si incheie executia aplicatiei.
219
In exemplul de mai sus se vede cum eu am introdus sirul "Un mesaj" si am primit acelas sir inversat;
220
Prin urmare, pentru trimiterea unui mesaj de SMTP este necesar un sever care sa realizeze
operatiunea, iar pentru receptionarea unui mesaj este necesar un server POP3 sau IMAP. Pentru acest
curs am sa folosesc telacad.ro ca server SMTP si POP3.
222
Exemplul de mai sus este cel mai simplu exemplu de trimitere a unui mesaj de email printr-un server
SMTP. Este posibil insa ca serverul sa nu permita trimiterea prin configurari implicite. De exemplu
serverul nu foloseste portul implicit 25 pentru SMTP. In cazul in care se doreste modificarea
configurarilor implicite prin care este trimis mesajul este necesara modificarea proprietatilor din
antetul mesajului. Iata cele mai utile proprietati ale caror valori pot fi modificate:
223
Proprietate
Semnificatie
mail.from
mail.host
mail.user
mail.<protocol>.host
mail.<protocol>.port
mail.<protocol>.user
mail.<protocol>.password
In tabelul de mai sus <protocol> trebuie inlocuit cu protocolul folosit. De exemplu la trimitere este
smtp
224
In concluzie pasii care trebuie urmati pentru trimiterea unui mesaj de email sunt:
1.
2.
3.
4.
225
Daca se incearca in exemplul de mai sus formatarea cu HTML rezultatul nu va fi cel asteptat:
226
227
10.4 Atasamente
Exista posibilitatea de a trimite atasamente in mesajul de email. Aplicatia de mai jos deschide o
fereastra si lasa posibilitatea utilizatorului de a trimite mesaje prin intermediul unui server la care
acesta poate adauga si un fisier ca atasament:
Clasa Email are ca atribute toate piesele necesare pentru formarea mesajului care sa poata fi trimis.
Constructorul clasei defineste un mesaj, iar comportamentul sendEmail() este folosit pentru
trimiterea mesajului.
228
Metoda sendEmail() trimite mesajul pe baza informatilor setate. Deoarece mesajul va avea si un
fisier atasat acesta va fi compus din doua parti... mesajul si atasamentul:
229
Metosa getContentType() trebuie suprascrisa pentru a returna tipul de flux corespunzator (formatul
folosit). In acest caz "application/octet-stream"
230
Clasa Fereastra:
231
232
Clasa Main :
233
Rezultatul:
234
235
236
237
Dupa trimiterea unui mesaj spre aceasta adresa, mesajul apare in consola, acesta fiind afisat in
intregime cu tot cu antete.
238