Utilisation de JDBC pour la gestion d'images en base de donnéesDate de publication : 3/06/2004 , Date de mise à jour : 18/11/2004 niveau : intermédiaire Le but de ce tutoriel est de vous présenter une manière de faire pour stocker et extraire une image dans une base de données ne reposant que sur JDBC. Pour illustrer ceci, nous allons construire autour du coeur de ce tutoriel, à savoir la communication avec la base de données, une petite application permettant d'illustrer plus facilement l'interaction avec la base de données. Avant-propos Remerciements 1. Le stockage volumineux de données en base de données 2. Création de la table 2.1. Base de données MySQL 2.2. Base de données PostgreSQL 3. Interaction avec la base de données 3.1. Connexion/Déconnexion 3.2. Enregistrement d'une image 3.3. Chargement d'une image 3.4. Liste des noms d'images 4. Mise en place d'une application graphique 4.1. JFileChooser et gestion des extensions 4.2. Boîte de dialogue simple avec JOptionPane 4.3. La classe ImageFrame 5. Utilisation d'un jar 5.1. Rassembler les librairies 5.2. Création d'un manifest 5.3. Création du jar 5.4. Exécution du jar 6. Quelques liens utiles Avant-proposL'idée première de ce tutoriel est de vous proposer un exemple de code s'appuyant uniquement sur JDBC (en n'utilisant que des classes du paquet java.sql) permettant de réaliser les opérations de sauvegarde ou de chargement d'images sur différents SGBDR (ceux qui sont compatibles avec JDBC) sans avoir à personnaliser le code selon la base de données cible. Il est par exemple possible de réaliser une telle opération pour un SGBDR comme ORACLE, mais on est obligé de recourir à un ResultSet Oracle, ce qui empêche l'utilisation d'un code portable sur une autre base de données. RemerciementsJe tiens avant tout à remercier la section Java, et plus particulièrement request pour ses remarques et ses conseils, ainsi que Rmotte pour les corrections orthographiques. 1. Le stockage volumineux de données en base de donnéesLe but n'est pas ici de débattre ou de donner une opinion concernant le stockage de données volumineuses (selon la norme SQL, le type LOB pour Large OBject) dans une base de données. Pour ceux qui ne le savent pas, des SGBDR comme ORACLE permettent par exemple de stocker des fichiers dans le système de fichier du système d'exploitation (ce qu'on appelle les BFILE chez ORACLE). Il existe, selon les SGBDR, différentes catégories de LOB. Nous nous concentrerons ici sur les BLOB (Binary Large OBject) qui sont dédiés aux données binaires, et donc notamment aux images. Compte tenu des objectifs rappelés en préambule, je me suis donc concentré sur les 2 SGBDR suivants pour lesquels cela est possible et que je pouvais tester : MySQL et PostgreSQL. Nous allons dans la suite présenter comment sont géré les LOB et traiter la création d'une table pour chacune de ces bases de données. Les versions sur lesquelles se base le contenu de ce tutoriel sont les suivantes :
2. Création de la tableAprès avoir créé votre base de données (ici j'ai pris "toto" et "titi" pour nom d'utilisateur / mot de passe), nous allons créer une table contenant 2 colonnes : une colonne name, et une colonne img. Appelons cette table images. 2.1. Base de données MySQLPour MySQL, nous disposons de 4 variantes du type BLOB :
Le choix du type à utiliser dépend donc du type d'informations à stocker. Pour notre exemple, nous pourrons nous contenter du type MEDIUMBLOB. Voici l'ordre SQL de création :
A noter qu'il est important de bien définir la variable max_allowed_packet pour ne pas avoir d'erreurs lors du transfert de données. 2.2. Base de données PostgreSQLLe type utilisé au niveau de PostgreSQL est BYTEA qui permet de stocker des données binaires allant jusqu'à 1 Go. Voici l'ordre SQL de création :
3. Interaction avec la base de donnéesNous avons donc la possibilité d'utiliser une base de données MySQL ou PostgreSQL. Je vous propose pour cela d'utiliser un fichier de configuration pour gérer les paramètres de connexion propres à chaque base de données. Nous pourrions bien entendu ajouter des informations sur le nom de la table ainsi que les noms des champs, mais le but principal est d'y mettre à la fois des données comme "url" et "driver" propres à chaque SGBDR, ainsi que les données utilisateur/mot de passe sur lesquelles le lecteur ne pourra peut-être pas agir s'il cherche à mettre en pratique le contenu de ce tutoriel. Appelons ces fichiers respectivement proprieteMysqlBLOB.dat et proprietePostgresqlBLOB.dat :
On notera l'utilisation d'anti slash \ pour échapper les double points dans les chaînes. Il convient bien entendu d'adapter les paramètres en fonction de votre configuration. Notamment le nom de la base de données (blob) pour MySQL ou Postgresql. 3.1. Connexion/DéconnexionNous pouvons dès lors utiliser ces fichiers de configuration pour définir une méthode d'initialisation de la connexion. Nous allons donc entamer la partie JAVA de ce tutoriel, en créant un package images et une première classe Bdd. Pour récupérer les informations présentes dans un fichier de configuration, nous aurons besoin d'utiliser java.util.Properties. Voici donc le contenu de la classe Bdd pour permettre d'établir une connexion :
3.2. Enregistrement d'une imagePour enregistrer une image, nous allons suivre le processus suivant : on insère une nouvelle ligne avec pour contenu le nom qu'on souhaite donner à l'image, puis on fait une mise à jour pour insérer l'image. Pour cela, nous allons nous reposer sur le paquetage java.sql et notamment la classe PreparedStatement (pour une requête paramétrée).
Les paramètres dans un PreparedStatement se matérialisent par un point d'interrogation. L'affectation du contenu du paramètre se fait par la méthode setXXX (ici par exemple setString) dont le premier argument est la position du paramètre dans la requête. Les requêtes de sélection s'exécutent en général avec la méthode executeQuery(), les requêtes de mise à jour s'exécutent elles à l'aide de executeUpdate(). Il est néanmoins possible, lorsqu'on cherche à exécuter une requête qu'on ne connaît pas, d'utiliser la méthode execute(). Concernant la partie spécifique à la copie des informations extraites du fichier à la base de données, on s'appuie sur des composants gérant un flux binaire. On commence donc par définir le fichier à consulter et on lui associe un flux entrant. Le flux est ensuite affecté à la colonne img de la table à l'aide de la méthode setBinaryStream dont les second et troisième paramètres correspondent respectivement au flux entrant et à la taille à extraire.
3.3. Chargement d'une imageNous allons également réaliser l'opération inverse, c'est à dire enregistrer sur notre disque dur une image contenue dans la base de données.
Le principe du transfert des données est identique à ce qui est utilisé dans la méthode de sauvegarde. On notera l'utilisation d'une variante dans la méthode getBinaryStream() pour laquelle on peut également fournir comme paramètre le nom de la colonne cible. Le transfert se fait quant à lui à l'aide d'un buffer intermédiaire et permet de lire morceaux par morceaux le contenu en base pour le recopier dans le flux de sortie relié à un fichier. 3.4. Liste des noms d'images
4. Mise en place d'une application graphiqueLa classe que nous venons de réaliser est bien entendu opérationnelle et vous pouvez très bien là tester en écrivant une méthode main. Néanmoins, il est plus agréable de bénéficier d'une petite interface graphique permettant de gérer les différentes opérations. Pour cela, nous allons nous appuyer sur le composant JFileChooser (voir la FAQ JAVA) pour la sélection d'un fichier, ainsi qu'une boîte de dialogue très simple pour la saisie d'un nom, le tout exploité par une JFrame avec un menu. 4.1. JFileChooser et gestion des extensionsPour pouvoir filtrer suivant des extensions, nous devons définir une classe particulière que nous appellerons ExtensionFileFilter héritant de javax.swing.filechooser.FileFilter. Voici le contenu de la classe utilisée :
Il sera ainsi possible de définir un filtre pour une boîte de dialogue de sélection de fichier. 4.2. Boîte de dialogue simple avec JOptionPaneIl nous faut également demander à l'utilisateur de saisir un nom identifiant l'image en base de données. Pour cela nous utiliserons une boîte de dialogue assez simple dont voici un exemple.
Il y a bien sûr des variantes possibles, se référer à la doc sur le site de sun pour plus d'informations. 4.3. La classe ImageFrameAprès avoir précisé les quelques éléments spécifiques utilisés pour notre Frame, nous pouvons désormais nous occuper de la classe principale qui va correspondre à notre interface graphique. ![]()
5. Utilisation d'un jarNotre application est maintenant utilisable. Il ne reste plus qu'à se préoccuper du déploiement afin que n'importe qui puisse l'utiliser sans avoir à se préoccuper des librairies nécessaires. Pour cela, nous allons réaliser un jar, plus agréable à exécuter, et évitant à l'utilisateur de devoir traîner les différentes classes que nous avons définies. Après avoir compilé et créé vos .class dans le répertoire classes/images/, vous êtes prêt à préparer votre jar. 5.1. Rassembler les librairiesNous avons choisi de faciliter l'utilisation de notre petite application en fournissant les librairies nécessaires, ce qui veut dire qu'une fois notre jar créé, il ira rechercher les classes nécessaires dans une liste de librairies que nous lui auront donné. Nous allons donc créer (dans classes/ par exemple) un répertoire lib qui va contenir nos différents jar, à savoir pour ce qui a été utilisé :
Les deux premiers jar m'ont été nécessaires pour la base de données PostgreSQL. Libre à vous de rajouter d'autres jar si vous avez d'autres besoins. 5.2. Création d'un manifestLorsque vous créez un jar, sa structure est la suivante :
Le répertoire META-INF contient entre autres un fichier nommé MANIFEST.MF dans lequel sont notamment recensées des informations sur le package et sur les librairies utilisées. Le but est donc de définir un tel fichier permettant de fournir les informations nécessaires au bon fonctionnement de notre application. Compte tenu des jar qui risquent d'être nécessaires à l'exécution, il faudra recenser ceux-ci, mais il faudra également définir quelle est la classe à exécuter (c'est à dire celle dont on va exécuter la méthode main lors de l'exécution du jar). Pour ce faire, nous allons créer un fichier "manifest.txt" (toujours dans classes/) où nous allons mettre les informations suivantes :
Les informations pour Class-Path sont sur une même ligne et chaque jar est séparé du précédent par un espace. 5.3. Création du jarTous est maintenant en place pour créer le jar.
Plaçons-nous en ligne de commande dans le répertoire classes et tapons la commande suivante :
Nous venons de créer notre jar sous le nom de images.jar. 5.4. Exécution du jarLa principale obligation pour pouvoir lancer notre jar et travailler sur les 2 bases de données mentionnées dans ce tutoriel est d'avoir dans le répertoire où images.jar sera placé également présent le répertoire lib créé précédemment. En effet, les informations présentes dans le manifest indiquent où chercher les librairies, et nous avons indiqué des adresses relatives au jar. Il suffit ensuite de lancer notre petite application par :
6. Quelques liens utilesVous pouvez bien entendu télécharger les sources et l'application sous forme de jar.
|
Les sources présentées sur cette page sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2004 Ricky81. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.