Vous êtes sur la page 1sur 27

I Introduction à JavaFX

JavaFX est une technologie créée par Sun Microsystems qui appartient désormais à Oracle. Avec
l'apparition de Java 8 en mars 2014, JavaFX devient la bibliothèque de création d'interface graphique
officielle du langage Java, pour toutes les sortes d'application (applications mobiles, applications sur
poste de travail, applications Web), le développement de son prédécesseur Swing étant abandonné
(sauf pour les corrections de bogues). JavaFX contient des outils très divers, notamment pour les
médias audio et vidéo, le graphisme 2D et 3D, la programmation Web, la programmation multi-fils
etc.
I II. Utilisation de la bibliothèque JavaFX.

JavaFX exécute dans l'ordre, chaque fois qu'une application est lancée, les actions suivantes :
• Construit une instance de la classe Application spécifiée
• Appelle la méthode init ()
• Appelle la méthode start (javafx.stage.Stage)
• Attend l'achèvement de l'application,
• Appelle la méthode stop ()
Notez que la méthode de démarrage (start) est abstraite et doit être surchargée. Les méthodes
d'initialisation (init) et d'arrêt (stop) ont des implémentations concrètes qui ne font rien. L’exécution
du code suivant montre que l’exécution de la méthode init n’est pas faite par le même fil d’exécution
(thread) que l’appel au constructeur par défaut et l’exécution de la méthode start.
public class FenetreApplication extends Application {
public void start ( Stage primaryStage ) {
// definir la troupe d’acteurs
Group root = new Group () ;
// definir la scène ( largeur , hauteur , fond )
Scene scene = new Scene ( root , 800 , 600 , Color .BLACK) ;
primaryStage . setTitle (”Un t i t r e de fenêtre . . . ”) ;
primaryStage . setScene ( scene ) ;
// definir un rectangle a peu près centré 2
Rectangle rectangle = new Rectangle (400 , 300 , 40 , 30) ;
rectangle . setFill ( Color .CHARTREUSE) ;
root . getChildren () . add( rectangle ) ;
// afficher le theatre
primaryStage . show () ;
}
public static void main( String [ ] args ) { launch ( args ) ; }
}
I III. Panneaux et composants de base.
II 1. Gestionnaire de la mise en page (Layout)

Un layout ou gestionnaire de mise en page est un noeud graphique qui hérite de la classe
javafx.scene.layout.Pane. Il s'agit d'une entité qui contient d'autres noeuds et qui est chargée de les
déplacer, de les disposer, voire de les redimensionner de manière à changer la présentation de cet
ensemble de noeuds et à les rendre utilisables dans une interface graphique. Les layout fonctionnent
donc de manière similaire aux layouts de AWT/Swing à ceci près qu'il ne s'agit pas ici de classes
utilitaires, mais d'instances de la classe Region qui sont directement placées dans la scène. Un
gestionnaire est un noeud graphique et peut donc être positionné et manipulé, ou subir des
transformations et effets comme n'importe quel autre noeud de SceneGraph. Les différences
importantes entre Panel (panneau) et Group (groupe) sont :
• Un panneau peut avoir sa propre taille et être redimensionnable, par contre un groupe prend les
limites collectives de ses enfants et n'est pas directement redimensionnable.
• Le panneau doit être utilisé lorsque vous souhaitez positionner ses noeuds en position absolue. Un
layout (organisation) est une classe de l’API Graphique permettant d’organiser les objets graphiques
dans la fenêtre. En JavaFX, il existe huit types de layouts :
1. Le BorderPane qui vous permet de diviser une zone graphique en cinq parties : top, down, right,
left et center.
2. La Hbox qui vous permet d'aligner horizontalement vos éléments graphiques.
3. La VBox qui vous permet d'aligner verticalement vos éléments graphiques.
4. Le StackPane qui vous permet de ranger vos éléments de façon à ce que chaque nouvel élément
inséré apparaisse au-dessus de tous les autres.
5. Le GridPane permet de créer une grille d'éléments organisés en lignes et en colonnes
6. Le FlowPane permet de ranger des éléments de façon à ce qu'ils se positionnent
automatiquement en fonction de leur taille et de celle du layout.
7. Le TilePane est similaire au FlowPane, chacune de ses cellules fait la même taille.
8. L'AnchorPane permet de fixer un élément graphique par rapport à un des bords de la fenêtre :
top, bottom, right et left.
I IV. Utilisation d'un éditeur graphique (JavaFX Scene Builder).
3
1. Configuration d’Eclipse

Nous devons paramétrer Eclipse pour qu’il utilise le JDK 8 et qu’il sache où trouver le Scene Builder :
• • Ouvrez les préférences et sélectionnez la partie Java | Installed JREs.
• • Cliquez sur le bouton Add… pour ajoutez le JDK 8 puis sur Standard VM et sélectionnez le
dossier contenant le JDK 8.
• • Supprimez les autres JREs et JDKs afin que le JDK 8 devienne le JDK par défaut (default) !
• • Sélectionnez la partie Java | Compiler. Définissez la Compiler compliance level à 1.8 !
• • Sélectionnez la partie JavaFX puis spécifiez le chemin de votre exécutable Scene Builder !
• 2. Utilisation de scene builder

Créer une classe vue de fichier fxml sur Eclipse par file new other new FXML document. Après, ouvrez
ce fichier en faisant un clic droit sur ce dernier et choisir open with scene builder. Dès lors, vous avez
l’interface de scene builder qu’on apprendra à utiliser en TP.
I V. Les évènements
II 1. Notion d’évènement

Dans les applications JavaFX, les événements signifient que quelque chose s'est produit : un
utilisateur a cliqué sur un bouton, appuie sur une touche, déplace une souris ou effectue d'autres
actions, … Dans JavaFX, un événement est une instance de la classe javafx.event.Event ou de toute
sous-classe d'Event. JavaFX fournit plusieurs sous-classe d'Event, notamment DragEvent, KeyEvent,
MouseEvent, ScrollEvent et d'autres. Vous pouvez définir votre propre sous-classe d'Event en
étendant la classe Event. Chaque événement inclut les informations suivantes : Event Type, Source
and Target. La hiérarchie des évènements :
Le type d'événement de niveau supérieur dans la hiérarchie est Event.ROOT, qui est équivalent à
Event.ANY. Dans les sous-types, le type d'événement ANY est utilisé pour désigner n'importe quel
type d'événement dans la classe d'événements. Par exemple, pour fournir la même réponse à
n'importe quel type d'événement de type « touche », utilisez KeyEvent.ANY comme type
d'événement pour le filtre d'événements ou le gestionnaire d'événements. Pour répondre
uniquement lorsque la touche est libérée, utilisez le type d'événement KeyEvent.KEY_RELEASED pour
le filtre ou le gestionnaire 4
Les gestionnaires d'événements (EventHandler) vous permettent de gérer les événements. Un noeud
peut avoir un ou plusieurs gestionnaires pour gérer un événement. Un seul gestionnaire peut être
utilisé pour plusieurs noeuds et plusieurs types d'événements.
2. Enregistrement d'un gestionnaire d'événements

Pour traiter un événement, un noeud doit enregistrer un gestionnaire d'événements. Un gestionnaire


d'événements est une implémentation de l'interface EventHandler. La méthode handle () de cette
interface fournit le code qui est exécuté lorsque l'événement associé au gestionnaire est reçu par le
noeud qui a enregistré le gestionnaire. Pour enregistrer un gestionnaire, utilisez la méthode
addEventHandler de la classe javafx.scene.Node. Cette méthode prend le type d'événement et le
gestionnaire comme arguments :
objet.setOnMouseClicked(new EventHandler<MouseEvent>(){ public void handle(MouseEvent me)
{ //instructions à exécuter lors de cet événement }
});
public final <T extends Event> void addEventHandler(EventType<T> eventType, EventHandler<?
super T> eventHandler).
La méthode pratique d'enregistrement d'un seul gestionnaire de type « ActionEvent » est:
setOnAction(EventHandler<ActionEvent> value).
Une application JavaFX peut donc se résumer :
– Préparer la Scene avec les différents noeuds
– Préparer la Scene avec ses dimensions et ajouter le noeud racine de la Scene
– Préparer le Stage et y ajouter la Scene et afficher le Stage
Les convenience methods de JavaFX :
setOnXXX(EventHandler<T> event) où XXX est le type de l’événement (sans la terminaison Event)
Exemples : setOnAction(EventHandler<ActionEvent> event)
setOnKeyPressed(EventHandler<KeyEvent> event) setOnMousePressed(EventHandler<MouseEvent>
event)
3. Propagation des événements

On distingue 3 phases :
a. Target selection

Le système détermine la cible de l’événement selon des règles différentes en fonction du type
d’événement. Exemple : événements souris => noeud de plus bas niveau dans le graphe de scène
sous le pointeur de la souris.
b. Event capturing phase

L’événement est propagé en descendant le graphe de scène depuis la racine jusqu’à la cible offrant
l’opportunité au noeud de chaque niveau de réagir à l’événement. 5
c. Event bubbling phase

L’événement remonte le graphe depuis la cible jusqu’à la racine offrant une 2ème opportunité aux
noeuds de chaque niveau de réagir à l’événement
Ajouter des gestionnaires d’événements à chaque étape de la propagation des événements :
a. Sur la cible ou sur n’importe lequel de ses parents dans le graphe
b. Sur l’une ou les deux phases du cycle de propagation

Event capturing phase :


addEventFilter(EventType<T>, EventHandler<? super T>)
Event bubbling phase
addEventHandler(EventType<T>, EventHandler<? super T>)
Interrompre la propagation lorsque l’on le souhaite en appelant la méthode consume () sur
l’événement écouté dans l’EventHandler de notre choix
I VI. Liaison de données

JavaFx propose un mécanisme de binding qui permet de lier des données entre elles. Ces données
doivent être encapsulées dans une Property La modification d’une Property entraîne la modification
des Property qui lui sont associées. Les attributs des composants JavaFX sont en général des
Property.
Elles sont donc liables à d’autres Property, que ce soit celles d’un autre composant de l’API ou celles
créées par le développeur Ce mécanisme est particulièrement utile pour :
• • Coder certains comportements de l’interface

• • Lier des paramètres de l’application à des composants de l’interface


6
I VII. Property

Interface spécifiant le mécanisme nécessaire pour écouter les changements de valeur d’une donnée
Chaque déclinaison encapsule une donnée d’un type particulier :
• • SimpleBooleanProperty pour observer un booléen
• • SimpleIntegerProperty pour observer un entier
• • SimpleDoubleProperty pour observer un flottant double Etc.

On peut accéder ou modifier la valeur encapsulée dans une Property grâce à ses méthodes get() et
set(…) …mais il vaut mieux réserver ces dernières à un usage interne à la classe où la Property est
définie (ce n’est pas un attribut de classe). La Property sera donc plutôt stockée comme un attribut
privé de la classe.
On utilisera les conventions de nommage suivantes :
• • xxx étant le nom donnée à la Property
• • getXxx() permet d’obtenir la valeur encapsulée

• • setXxx(…) permet de fixer la valeur encapsulée


• • xxxProperty() permet d’obtenir la Property xxx elle-même

I VIII. Le binding
II 1. Binding et propriétés

Le binding lie les valeurs de deux Property. Cette liaison peut être unidirectionnelle ou
bidirectionnelle.
Syntaxe :
• • Liaison unidirectionnelle : prop1.bind(prop2) la valeur de prop2 est systématiquement
recopiée dans celle de prop1 en cas de changement
• • Liaison bidirectionnelle : prop1.bindBidirectional(prop2) toute nouvelle valeur de l’une des
deux Property est recopiée dans l’autre

2. Binding et opérations

Le binding permet aussi d’effectuer un certain nombre d’opérations mathématiques dépendant du


type de la valeur à recopier (add, subtract, multiply, …)
Exemple :
3. Binding et conversions de type

Si les Property n’ont pas le même type :


• • Erreurs de compilations Possibilité d’intégrer un mécanisme de conversion au binding
7
Exemples :
• • Liaison unidirectionnelle d’un Double vers un String :

Méthode asString() définie dans la classe NumberExpressionBase (dont héritent les Property
encapsulant un nombre) myStringProperty.bind(myDoubleProperty.asString());
• • Liaison bidirectionnelle : conversion dans les deux sens grâce à un StringConverter

StringConverter<Number> sc = new NumberStringConverter();


myStringProperty.bindBidirectional(myDoubleProperty, sc);
4. Listener

Pour des réactions plus complexes aux changements de valeur d’une Property (opérations complexes
ou nécessité d’effets de bord), on fait appel au mécanisme des listeners, très proche de celui des
filters/ handlers :
• • Utilisation d’un ChangeListener
• • Abonnement de ce ChangeListener sur la Property grâce à sa méthode addListener()
• 5. ChangeListener

Interface fonctionnelle décrivant la réaction à un changement de valeur. Elle comporte une unique
méthode :
changed(ObservableValue<? extends T> observable, T oldValue, T newValue)
Pour décrire la réaction : implémenter l’interface et placer le traitement à effectuer dans la méthode
changed(…). Les informations passées en paramètres permettent de récupérer une lien sur la donnée
observée, son ancienne valeur et sa nouvelle valeur.
I IX. Quelques cas pratiques
8
Éléments graphiques 2D
Parmi les noeuds du graphe de scène, on peut aussi créer des formes géométriques 2D et 3D. Pour
les formes 2D, on retrouve principalement :
Rectangle, Circle, Ellipse, Polygon, Line, Arc, etc. Tous héritent de la classe Shape.
Il est conseillé d’inclure ces formes dans un layout spécifique (généralement de type Pane) en lui
donnant une taille préférentielle pour éviter les problèmes de placement :
Exemple :
On peut appliquer toutes sortes de transformations sur chacun des noeuds du graphe de scène :
• • Translations (Translate)
• • Mises à l’échelle (Scale)
• • Rotations (Rotate)
• • Cisaillement (Shear)

Toute autre transformation affine customisée (Affine). Chaque transformation est représentée par
une matrice de transformation (matrice 4x4)
Transformations
Une transformation est une opération particulière de déplacement ou de déformation. Elle peut être
appliquée plusieurs fois sur un même noeud. Elle peut être appliquée sur plusieurs noeuds différents.
Elle peut être combinée à d’autres transformations. Elle est, par exemple, différente du
positionnement absolue d’un objet (avec les méthodes setX(…) et setY(…) ). Toute transformation sur
un noeud est répercutée sur ces enfants dans le graphe de scène.
Convenience methods héritées de la classe Node
setTranslateX(double) / setTranslateY(double) setScaleX(double) / setScaleY(double)
setRotate(double) ...
Les transformations obtenues par ces méthodes sont peu paramétrables. Par exemple, la mise à
l’échelle et la rotation ne peuvent s’effectuer qu’autour du centre de la boite englobant le noeud
Appliquer une transformation 9
Pour dépasser ces limitations, instancier directement les transformations (classes héritant de
Transform). Instancier une transformation, puis l’ajouter à la liste des transformations d’un noeud
myNode.getTransforms().add(new Scale(scaleX, scaleY, pivotX, pivotY));
Conserver une seule transformation affine sur le noeud et la modifier en place au fur et à mesure
Affine myTransforms = new Affine(); myNode.getTransforms().add(myTransforms);
myTransforms.appendScale(scaleX, scaleY, pivotX, pivotY); myTransforms.append...
Exemple :
Animations
En plus des transformations, on peut aussi appliquer des animations sur les noeuds du graphe de
scène.
Transformations géométriques animées dans le temps TranslateTransition, RotateTransition,
ScaleTransition,… Aussi sur d’autres paramètres (couleur, bordure, etc.) FadeTransition,
FillTransition, StrokeTransition,… Plusieurs paramètres peuvent être manipulés Durée :
setDuration(…),
Répétition : setCycleCount(…),… Démarrées/arrêtées avec les fonctions play() et stop() 10
I X. Expression lamda

Une expression lambda est une fonction anonyme : sa définition se fait sans déclaration explicite du
type de retour, ni de modificateurs d'accès ni de nom. C'est un raccourci syntaxique qui permet de
définir une méthode directement à l'endroit où elle est utilisée.
Une expression lambda est donc un raccourci syntaxique qui simplifie l'écriture de traitements
passés en paramètre. Elle est particulièrement utile notamment lorsque le traitement n'est utile
qu'une seule fois : elle évite d'avoir à écrire une méthode dans une classe.
Une expression lambda permet d'encapsuler un traitement pour être passé à d'autres traitements.
C'est un raccourci syntaxique aux classes anonymes internes pour une interface qui ne possède
qu'une seule méthode abstraite. Ce type d'interface est nommé interface fonctionnelle.
Lorsque l'expression lambda est évaluée par le compilateur, celui-ci infère le type vers l'interface
fonctionnelle. Cela lui permet d'obtenir des informations sur les paramètres utilisés, le type de la
valeur de retour, les exceptions qui peuvent être levées.
Elles permettent d'écrire du code plus compact et plus lisible. Elles ne réduisent pas l'aspect orienté
objet du langage qui a toujours été une force mais au contraire, rendent celui-ci plus riche et plus
élégant pour certaines fonctionnalités.
La syntaxe des expressions lambda Les avantages des expressions lambda est d'avoir une syntaxe
très simple. La syntaxe d'une expression lambda est composée de trois parties :
• • un ensemble de paramètres, d'aucun à plusieurs : l'opérateur -> le corps de la fonction

Elle peut prendre deux formes principales : (paramètres) -> expression; (paramètres) ->
{ traitements; }
L'écriture d'une expression lambda doit respecter plusieurs règles générales :
• • zéro, un ou plusieurs paramètres

• • les paramètres sont entourés par des parenthèses et séparés par des virgules. Des
parenthèses vides indiquent qu'il n'y a pas de paramètre
• • le corps de l'expression peut contenir zéro, une ou plusieurs instructions. Si le corps ne
contient d'une seule instruction, les accolades ne sont pas obligatoires et le type de retour
correspond à celui de l'instruction. Lorsqu'il y a plusieurs instructions alors elles doivent être

• • entourées avec des accolades.


11
Exemple :
comparatorLength est un objet implémentant l’interface fonctionnelle Comparator<String>.
La technique classique de création pour créer l’objet comparatorLength :
Comparator<String> comparatorLength = new Comparator<String>{ public int compare(String
chaine1, String chaine2) { Integer.compare(chaine1.length(),chaine2.length()) }}
Utilisation d’une lambda expression pour créer l’objet comparatorLength :
Comparator<String> comparatorLength = (String chaine1, String chaine2) ->
Integer.compare(chaine1.length(),chaine2.length());
l’usage d’une lambda expression anonyme : monBouton.addActionListener((ActionEvent event) ->
System.out.println("clic"));
encore plus concis - le type du paramétre est inféré (calculé par le compilateur) :
monBouton.addActionListener(event -> System.out.println("clic"));
exemple d’une lambda expression équivalente à la construction d’objet anonyme d’une classe
anonyme. Le code suivant //lambda expression
button.setOnAction ( (ActionEvent event) -> System.out.println(Thread.currentThread().getName()
+" : Hello World!") );
remplace : // objet anonyme d'une classe anonyme
button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent
event) { System.out.println(Thread.currentThread().getName()+" : Hello World!"); }} );
exemple d’une lambda expression équivalente à la construction d’un objet. Le code suivant :
EventHandler<ActionEvent> handler2 = (event) -> { String st = ((Button) event.getSource()).getText()
+"\n"; righTextArea.appendText(st); };
remplace : EventHandler<ActionEvent> handler2 = new EventHandler<ActionEvent>() { @Override
public void handle(ActionEvent event) { String st = ((Button) event.getSource()).getText()+"\n";
righTextArea.appendText(st); }}; 12
I XI. Architecture MVC.

Ce modèle à trois couches permet d’organiser, de structurer une application interactive en séparant :
• • Les données et leurs traitements : le Modèle
• • La représentation des données : la Vue
• • Le comportement de l’application : le Contrôleur

1. Le modèle

Il énumère les éléments suivants :


• • Stocke les données
• • Fournit les accès aux données
• • Fournit les traitements applicables aux données
• • Expose les fonctionnalités de l’application

2. La vue
• Expose à l’utilisateur la (ou les) représentation(s) des données du modèle

• Assure la consistance entre la (ou les) représentation(s) qu’elle donne et l’état du modèle

3. Le contrôleur
• Représente le comportement de l’application face aux actions de l’utilisateur

• Fournit la traduction des actions de l’utilisateur en actions sur le modèle


• Fournit la vue appropriée par rapport aux actions de l’utilisateur et des réactions du modèle
13
I XII. Interaction avec la base de données

1. Principes généraux d'accès à une BDD


i. Première étape

Préciser le type de driver que l'on veut utiliser. Driver permet de gérer l'accès à un type particulier de
SGBD
i ii. Deuxième étape

Récupérer un objet « Connection » en s'identifiant auprès du SGBD et en précisant la base utilisée


i iii. Etapes suivantes
ii • A partir de la connexion, créer un « statement » (état) correspondant à une requête
particulière
iii • Exécuter ce statement au niveau du SGBD
iv • Fermer le statement
v iv. Dernière étape

Se déconnecter de la base en fermant la connexion


2. Connexion au SGBD

Classe java.sql.DriverManager
Il permet de prendre la gestion du contrôle et de la connexion au SGBD. Les méthodes principales
liées à ce pilote (driver) sont :
• • static void registerDriver(Driver driver) : Enregistre le driver (objet driver) pour un type de
SGBD particulier. Le driver est dépendant du SGBD utilisé.
• • static Connection getConnection( String url, String user, String password) : Crée une
connexion permettant d'utiliser une base. url : identification de la base considérée sur le SGBD. Le
format de l'URL est dépendant du SGGB utilisé. user : nom de l'utilisateur qui se connecte à la base.
password : mot de passe de l'utilisateur
• 3. Gestion des connexions

Interface java.sql.Connection
Permet la préparation de l'exécution d'instructions sur la base, on distingue 2 types :
• • Instruction simple : classe Statement. On exécute directement et une fois l'action sur la
base
• • Instruction paramétrée : classe PreparedStatement. L'instruction est générique, des
champs sont non remplis. Cela permet une pré-compilation de l'instruction optimisant les
performances. Pour chaque exécution, on précise les champs manquants

Pour ces 2 instructions, 2 types d'ordres possibles :


• • Update : mise à jour du contenu de la base. Query : consultation (avec un select) des
données de la base. Les méthodes principales de Connection sont :
• ✓Statement createStatement(). Retourne un état permettant de réaliser une instruction
simple
14
✓PreparedStatement prepareStatement( String ordre). Retourne un état permettant de réaliser
une instruction paramétrée et pré-compilée pour un ordre ordre. Dans l'ordre, les champs libres (au
nombre quelconque) sont précisés par des « ? ».

Exemple :
''select nom from clients where ville=?''. Lors de l'exécution de l'ordre, on précisera la valeur du
champ. void close() ferme la connexion avec le SGBD.
a• a. Instruction simple.

Classe Statement
• • ResultSet executeQuery(String ordre). Exécute un ordre de type SELECT sur la base.
Retourne un objet de type ResultSet contenant tous les résultats de la requête
• • int executeUpdate(String ordre). Exécute un ordre de type INSERT, UPDATE, ou DELETE
• • void close(). Ferme l'état
• b. Instruction paramétrée

Classe PreparedStatement
Avant d'exécuter l'ordre, on remplit les champs avec :
• • void set[Type](int index, [Type] val). Remplit le champ en ième position définie par index
avec la valeur val de type [Type]. [Type] peut être : String, int, float, long ... Exemple : void
setString(int index, String val)
• • ResultSet executeQuery(). Exécute un ordre de type SELECT sur la base. Retourne un objet
de type ResultSet contenant tous les résultats de la requête

• • int executeUpdate(). Exécute un ordre de type INSERT, UPDATE, ou DELETE

4. Lecture des résultats

Classe ResultSet : Contient les résultats d'une requête SELECT. Il s’agit de plusieurs lignes contenant
plusieurs colonnes. On y accède ligne par ligne puis valeur par valeur dans la ligne. Ainsi on a les
éventuelles opérations suivantes :
a• a. Changements de ligne :
b• • boolean next() se place à la ligne suivante s'il y en a une. Retourne true si le déplacement a
été fait, false s'il n'y avait pas d'autre ligne.

c• • boolean previous() se place à la ligne précédente s'il y en a une. Retourne true si le


déplacement a été fait, false s'il n'y avait pas de ligne précédente

d• • boolean absolute(int index) se place à la ligne numérotée index. Retourne true si le


déplacement a été fait, false sinon
e• b. Accès aux colonnes/données dans une ligne

f• • [type] get[Type](int col)

g• • Retourne le contenu de la colonne col dont l'élément est de type [type] avec [type]
pouvant être String, int, float, boolean ... Exemple : String getString(int col)
h• • Fermeture du ResultSet

i• • void close()

5. Exception SQLException
15
Toutes les méthodes présentées précédemment peuvent lever l'exception SQLException. Exception
générique lors d'un problème d'accès à la base lors de la connexion, d'une requête .... Plusieurs
spécialisations sont définies
a• a. Opérations possibles sur cette exception
b• • int getErrorCode() : le code de l'erreur renvoyé par le SGBD (et dépendant du type du
SGBD)
c• • SQLException getNextException() : si plusieurs exceptions sont chaînées entre elles,
retourne la suivante ou null s'il n'y en a pas
d• • String getSQLState() : retourne « l'état SQL » associé à l'exception

Exemple : Exécution d'une instruction simple de type SELECT. Lister toutes les caractéristiques de
toutes les catégories.
Statement req;
ResultSet res;
String libelle;
int code;
req = con.createStatement();
res = req.executeQuery( ''select codcat, libellecat from categorie'');
while(res.next()) {
code = getInt(1); libelle = getString(2);
System.out.println( '' produit : ''+code +'',''+ libelle);
}
req.close();
Exemple : Exécution d'une instruction simple de type UPDATE. Ajouter une catégorie « céréales » de
code 5 dans la table catégories.
Statement req;
int nb;
req = con.createStatement();
nb = req.executeUpdate('' insert into categories values (5, 'cereales')'');
System.out.println( '' nombre de lignes modifiées : ''+nb);
req.close();
Exemple : Instruction paramétrée de type SELECT.
Retourne tous les produits de la catégorie céréales 16
PreparedStatement req;
ResultSet res;
String nom;
int code;
req = con.prepareStatement(''select codprod, nomprod from categorie c, produit p where
c.codcat=p.codcat and libellecat = ?'');
req.setString(1, ''cereales'');
res = req.executeQuery();
while(res.next()) {
code = getInt(1);
libelle = getString(2);
System.out.println( '' produit : ''+code +'',''+ libelle);
}
req.close();
Exemple : Instruction paramétrée de type UPDATE
Ajout de 2 nouvelles catégories dans la table catégorie
PreparedStatement req;
int nb;
req = con.prepareStatement( ''insert into categories values (?,?)'');
req.setInt(1, 12);
req.setString(2, ''fruits'');
nb = req.executeUpdate();
req.setInt(1, 13);
req.setString(2, ''légumes'');
nb = req.executeUpdate();
req.close();