I. Introduction▲
Dans ce petit tutoriel, nous allons lire des données depuis un fichier CSV et depuis une base MySql. Nous allons fusionner ces données puis les afficher dans un tableau en Swing. Enfin, nous utiliserons les données pour générer des graphiques.
L'application que nous allons développer (en quelques étapes simples) permet d'afficher les notes qu'un groupe d'étudiants a obtenues au dernier examen. Nous allons considérer que la liste des étudiants, contenant des informations personnelles (prénom, nom, adresse, date de naissance, etc.), est stockée dans la base de données MySql de l'école. La liste des notes est, quant à elle, envoyée par le professeur vacataire par email, sous la forme d'un fichier CSV (initialement créé/exporté avec Excel). L'application doit donc fusionner ces deux sources de données avant de les afficher.
I-A. À propos▲
Découvrir une technologie n'est pas chose facile. En aborder plusieurs d'un coup l'est encore moins. Partant de ce constat, cet article a été écrit pour aller à l'essentiel. Les points importants sont présentés dans le corps de l'article et les éléments secondaires sont expliqués en annexe.
I-B. Avant de commencer▲
Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :
- Java JDK 1.6.0_24-b07 ;
- Eclipse Indigo 3.7 JEE 64b ;
- Maven 3.0.3 ;
- Open CSV 2.3 ;
- jFreeChart 1.0.14.
Pour réaliser ce document, je me suis servi des tutoriels de la série « en 5 minutes »La série en 5 minutes. J'ai tout simplement suivi les tutoriels, les uns après les autres, en ajoutant un peu de glu lorsqu'il y en avait besoin. En particulier, et dans cet ordre, j'ai utilisé les articles suivants :
- tutoriel « Afficher un tableau avec un Table Model en 5 minutes » ;
- tutoriel « Charger des données depuis une base MySql en 5 minutes » ;
- tutoriel « Charger des données depuis un fichier CSV simple en 5 minutes » ;
- tutoriel « Charger des données depuis une base MySql en 5 minutes ».
Ce document est donc, en quelque sorte, la compilation de ces différents tutoriels. En réalité, il faudra donc un peu plus de cinq minutes pour réaliser toutes les étapes, car il est nécessaire de lire les tutoriels indiqués avant de continuer.
II. Découverte du projet d'exemple▲
II-A. Télécharger, installer et importer le projet d'exemple▲
Pour commencer, je vous propose de télécharger le fichier Zip « notes5.zip », contenant un projet Java-Maven d'exemple.
Compilez le projet d'exemple et importez-le dans Eclipse (comme expliqué dans le tutoriel « Importer un projet Maven dans Eclipse en 5 minutes ») ou dans l'IDE de votre choix.
Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexe) et de vous repérer à l'aide des captures d'écran.
II-B. Ce que fait déjà le projet▲
Les codes proposés (et déjà en partie assemblés) dans ce projet proviennent des autres tutoriels de la série « en 5 minutes » et réalisent les fonctionnalités suivantes :
- affichage de données dans un tableau à l'aide d'un « Table model » (cf. capture) ;
- génération et affichage de graphes à l'aide de jfreechart (cf. captures) ;
- lecture de données depuis un fichier CSV simple à l'aide d'Open CSV ;
- chargement de données depuis une base MySql à l'aide de JDBC.
La liste des élèves vient d'une base MySql, alimentée à l'aide du script SQL présenté dans le tutoriel « Charger des données depuis une base MySql en 5 minutes », dont le contenu est le suivant :
INSERT INTO `eleve` (`id`, `nom`, `prenom`, `classe`, `date_naissance`, `adresse`, `sexe`) VALUES
(1, 'Durand', 'Marie', 3, '1992-01-02 00:00:00', '15 rue du Lac 75001 Paris', 'FEMME'),
(2, 'Alesi', 'Julie', 3, '1992-01-08 00:00:00', '72 av. Jean Dupont 75003 Paris', 'FEMME'),
(3, 'Martini', 'Carine', 3, '1992-01-17 00:00:00', '2 rue du Moulin 92230 Neullavy', 'FEMME'),
(4, 'Varola', 'Sophie', 3, '1992-01-21 00:00:00', '15 rue du Lac 75001 Paris', 'FEMME'),
...
(48, 'Valegin', 'Jean', 3, '1992-11-28 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(49, 'Eto', 'Gabin', 3, '1992-11-18 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(50, 'Fivolini', 'Kevin', 3, '1992-12-06 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(51, 'Laferme', 'Martin', 3, '1992-12-07 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(52, 'Dupuis', 'Vincent', 3, '1992-12-15 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(53, 'Lagrange', 'Alexandre', 3, '1992-12-28 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME');Il faut donc créer la base de données correspondante comme indiqué dans le tutoriel si ce n'est pas déjà fait.
La liste des notes provient du fichier CSV présenté dans le tutoriel « Charger des données depuis un fichier CSV simple en 5 minutes », dont le contenu est le suivant :
# Nom;Prénom;Note
Durand;Marie;5
Alesi;Julie;8
Martini;Carine;10,5
Varola;Sophie;12
Labiche;Lelou;12
Dujardin;Anne;13
Laventure;Martine;14
...
Fivolini;Kevin;19
Laferme;Martin;20
Dupuis;Vincent;20Pour l'instant, les données affichées dans le tableau sont indépendantes de celles qui sont chargées en base. Le « Table model » utilise un « bouchon » pour charger les données. Ceci est présenté dans les tutoriels « Afficher un tableau avec un Table Model en 5 minutes » et « Afficher un graphe jfreechart en 5 minutes ». Un des enjeux du tutoriel est justement de ne plus utiliser ce « bouchon ».
public class NoteService {
private List<NoteEleve> notes;
...
public synchronized List<NoteEleve> findLastNotes() {
doBouchon(); // ici le bouchon
return notes;
}
private void doBouchon() {
if (notes != null) {
return;
}
notes = new ArrayList<NoteEleve>();
// Filles (nom, prenom, annee, sexe, note)
addEleveEtNote("Durand", "Marie", 3, FEMME, 5);
addEleveEtNote("Alesi", "Julie", 3, FEMME, 8);
addEleveEtNote("Martini", "Carine", 3, FEMME, 10);
...
addEleveEtNote("Baladini", "Mathilde", 3, FEMME, 17);
// Garcons (nom, prenom, annee, sexe, note)
addEleveEtNote("Michelet", "Jean", 3, HOMME, 0);
addEleveEtNote("Dupond", "Pierre", 3, HOMME, 2);
addEleveEtNote("Timberot", "Martin", 3, HOMME, 4);
...
addEleveEtNote("Fivolini", "Kevin", 3, HOMME, 19);
addEleveEtNote("Laferme", "Martin", 3, HOMME, 20);
addEleveEtNote("Dupuis", "Vincent", 3, HOMME, 20);
}
private void addEleveEtNote(String nom, String prenom, Integer annee, Sexe sexe, int note) {
addEleveEtNote(nom, prenom, annee, sexe, new Double(note));
}
private void addEleveEtNote(String nom, String prenom, Integer annee, Sexe sexe, Double note) {
final Eleve eleve = new Eleve(nom, prenom, annee, sexe);
final NoteEleve noteEleve = new NoteEleve(eleve, note);
notes.add(noteEleve);
}II-C. Les objets du modèle▲
Le modèle est constitué de trois classes : Eleve.java, Sexe.java et NoteEleve.java
public class Eleve {
private Integer id;
private String nom;
private String prenom;
private Integer annee;
private Sexe sexe;
private Date dateNaissance;
private String adresse;
public Eleve(String nom, String prenom, Integer annee, Sexe sexe, Date dateNaissance, String adresse) {
...
}
public Eleve(Integer id, String nom, String prenom, Integer annee, Sexe sexe, Date dateNaissance, String adresse) {
...
}
// + getter et setter
}La classe Eleve.java comporte un attribut « id » qui correspond à l'identifiant technique en base de données. Ceci est expliqué dans le tutoriel « Charger des données depuis une base MySql en 5 minutes ».
public enum Sexe {
HOMME("Garçon"),
FEMME("Fille");
private final String label;
Sexe(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}public class NoteEleve {
private Eleve eleve;
private Double note;
public NoteEleve(Eleve eleve, Double note) {
...
}
// + getter et setterII-D. Quelques classes importantes▲
On a déjà vu plus haut une partie de « NoteService.java », qui se présente sous la forme d'un singleton.
public class NoteService {
private static NoteService instance;
private List<NoteEleve> notes;
private NoteService() {
...
}
public synchronized List<NoteEleve> findLastNotes() {
doBouchon(); // ici le bouchon
return notes;
}
private void doBouchon() {
...
}
}Ce service est appelé par le « Table model ».
public class NotesModele extends AbstractTableModel {
private final String[] entetes = { "Nom", "Prénom", "Année", "Sexe", "Note" };
private NoteService noteService;
private List<NoteEleve> notes;
public NotesModele() {
noteService = NoteService.getInstance();
notes = noteService.findLastNotes();
}
...
public List<NoteEleve> getNotes() {
return notes;
}
}Le tableau et les boutons visibles dans l'IHM sont déjà connectés au « table model ».
Enfin, les interfaces des DAO sont les suivantes.
public interface EleveDao {
List<Eleve> findEleves();
List<Eleve> findElevesByClasse(Integer classe);
}public interface NoteDao {
Map<String, Double> findNotesDernierExam();
}Les implémentations (de ces DAO) qui nous intéressent (dans le cadre de ce tutoriel) sont NoteDao.java et CsvNoteDao.java.
III. Action▲
III-A. Désactivation du bouchon▲
Durée estimée : 1 minute.
Pour commencer, nous allons supprimer le « bouchon » utilisé dans le service.
public class NoteService {
private static NoteService instance;
private List<NoteEleve> notes;
private NoteService() {
...
}
public synchronized List<NoteEleve> findLastNotes() {
notes = new ArrayList<NoteEleve>();
return notes;
}
// Suppression du bouchon.
// private void doBouchon() {
// ...
// }
}Ici je retourne une liste vide. Je préfère éviter de renvoyer null pour ne pas avoir à gérer le cas de la nullité dans le reste du code.
Sans surprise, le tableau ne contient aucune donnée.
III-B. Charger les données à l'aide des DAO▲
Durée estimée : 2 minutes.
Nous allons maintenant utiliser les DAO pour obtenir la liste des élèves et leurs notes. Tout d'abord, on doit donc déclarer les bonnes implémentations.
public class NoteService {
...
private NoteDao noteDao;
private EleveDao eleveDao;
/**
* Constructeur prive
*/
private NoteService() {
super();
noteDao = new CsvNoteDao();
eleveDao = new DbEleveDao();
}
...On peut ensuite lancer le chargement des données dans la méthode « find ».
public synchronized List<NoteEleve> findLastNotes() {
notes = new ArrayList<NoteEleve>();
// 1) Chargement de la liste des eleves en base
List<Eleve> eleves = eleveDao.findEleves();
// 2) Chargement des notes depuis le fichier CSV
Map<String, Double> map = noteDao.findNotesDernierExam();
return notes;
}
...Petite subtilité : puisqu'on connaît le nombre d'élèves, on peut directement initialiser la liste de retour avec la bonne taille.
public synchronized List<NoteEleve> findLastNotes() {
// 1) Chargement de la liste des eleves en base
List<Eleve> eleves = eleveDao.findEleves();
// 2) Chargement des notes depuis le fichier CSV
Map<String, Double> map = noteDao.findNotesDernierExam();
// 3) Init avec la bonne taille
notes = new ArrayList<NoteEleve>( eleves.size() );
return notes;
...Pendant qu'on y est, on peut faire de même dans la méthode dataToMap de CsvNoteDao.java puisqu'elle doit renvoyer le même nombre d'éléments qu'elle en reçoit. Elle se contente de les convertir.
private Map<String, Double> dataToMap(List<String[] > data) {
//final Map<String, Double> map = new HashMap<String, Double>();
final Map<String, Double> map = new HashMap<String, Double>( data.size() ); // init avec la bonne tailleIII-C. Fusionner les données▲
Durée estimée : 1 minute.
Il ne reste plus qu'à réunir les données fournies par chaque DAO. On peut partir du principe que tous les élèves doivent avoir une note. Si la note n'est pas indiquée dans le fichier CSV, alors on en déduit que l'étudiant était absent à l'examen et doit donc recevoir un zéro.
La méthode findNotesDernierExam de CsvNoteDao retourne une map dont les clés sont constituées de la concaténation du nom et du prénom de l'étudiant.
public synchronized List<NoteEleve> findLastNotes() {
// 1) Chargement de la liste des eleves en base
List<Eleve> eleves = eleveDao.findEleves();
// 2) Chargement des notes depuis le fichier CSV
Map<String, Double> map = noteDao.findNotesDernierExam();
// 3) Init avec la bonne taille
notes = new ArrayList<NoteEleve>( eleves.size() );
// 4) fusion des donnees
for (Eleve eleve : eleves) {
final String key = eleve.getNom() + " " + eleve.getPrenom(); // ex. "DUPONT Jean"
Double valeur = map.get(key);
if (valeur == null) {
valeur = 0.0; // Si eleve absent
}
NoteEleve noteEleve = new NoteEleve(eleve, valeur);
notes.add(noteEleve);
}
return notes;
...Et voilà…
IV. Conclusion▲
Ce petit article était encore plus court que promis puisqu'on reste vraiment sous les cinq minutes, sans forcer. Le plus gros du travail a déjà été réalisé dans les tutoriels précédents.
Pour la suite, on pourrait imaginer de nombreuses nouvelles fonctionnalités. Par exemple, on pourrait enregistrer dans la base MySQL les données lues à partir du fichier CSV. On pourrait également ajouter des menus dans l'IHM pour choisir le fichier CSV à lire. À l'inverse, on pourrait imaginer des fonctions d'export des données consolidées ou encore des fonctions de générations de documents PDF (pour le conseil de classe ou pour envoyer aux parents).
Le code final de ce tutoriel est disponible dans le fichier ZIP notes6.zip.code final
Vos retours nous aident à améliorer nos publications. N'hésitez donc pas à commenter cet article sur le forum : Commentez ![]()
Retrouvez les tutoriels de la série « en 5 minutes » sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articlesEn 5 minutes.
V. Remerciements▲
Je tiens à remercier, en tant qu'auteur de tutoriel rapide, toutes les personnes qui m'ont aidé et soutenu. Je pense tout d'abord à mes collègues qui subissent mes questions au quotidien, mais aussi à mes contacts et amis du Web, dans le domaine de l'informatique ou non, qui m'ont fait part de leurs remarques et critiques. Bien entendu, je n'oublie pas l'équipe de developpez.com qui m'a guidé dans la rédaction de cet article et m'a aidé à le corriger et le faire évoluer, principalement sur le forum.
Plus particulièrement j'adresse mes remerciements à Mickael BARON (keulkeul) et Sébastien (FirePrawn).

VI. Annexes▲
VI-A. Liens▲
Le tutoriel « Afficher un tableau avec un Table Model en 5 minutes » est disponible à l'adresse
https://thierry-leriche-dessirier.developpez.com/tutoriels/java/afficher-tableau-avec-tablemodel-5-min
Le tutoriel « Afficher un graphe jfreechart en 5 minutes » est disponible à l'adresse
https://thierry-leriche-dessirier.developpez.com/tutoriels/java/afficher-graphe-jfreechart-5-min
Le tutoriel « Charger des données depuis un fichier CSV simple en 5 minutes » est disponible à l'adresse
https://thierry-leriche-dessirier.developpez.com/tutoriels/java/charger-donnees-fichier-csv-5-min
Enfin, le tutoriel « Charger des données depuis une base MySql en 5 minutes » est disponible à l'adresse
https://thierry-leriche-dessirier.developpez.com/tutoriels/java/charger-donnees-mysql-5-min
VI-B. Les fichiers importants en entier▲
package com.thi.notes.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.thi.notes.dao.CsvNoteDao;
import com.thi.notes.dao.DbEleveDao;
import com.thi.notes.dao.EleveDao;
import com.thi.notes.dao.NoteDao;
import com.thi.notes.domain.Eleve;
import com.thi.notes.domain.NoteEleve;
public class NoteService {
private static NoteService instance;
private List<NoteEleve> notes;
private NoteDao noteDao;
private EleveDao eleveDao;
private NoteService() {
super();
noteDao = new CsvNoteDao();
eleveDao = new DbEleveDao();
}
public static synchronized NoteService getInstance() {
if (instance == null) {
instance = new NoteService();
}
return instance;
}
public synchronized List<NoteEleve> findLastNotes() {
// 1) Chargement de la liste des eleves en base
List<Eleve> eleves = eleveDao.findEleves();
// 2) Chargement des notes depuis le fichier CSV
Map<String, Double> map = noteDao.findNotesDernierExam();
// 3) Init avec la bonne taille
notes = new ArrayList<NoteEleve>(eleves.size());
// 4) fusion des donnees
for (Eleve eleve : eleves) {
final String key = eleve.getNom() + " " + eleve.getPrenom();
Double valeur = map.get(key);
if (valeur == null) {
valeur = 0.0;
}
final NoteEleve noteEleve = new NoteEleve(eleve, valeur);
notes.add(noteEleve);
}
return notes;
}
}package com.thi.notes.ihm;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import com.thi.notes.domain.NoteEleve;
import com.thi.notes.domain.Sexe;
import com.thi.notes.service.NoteService;
public class NotesModele extends AbstractTableModel {
private final String[] entetes = { "Nom", "Prénom", "Année", "Sexe", "Note" };
private NoteService noteService;
private List<NoteEleve> notes;
public NotesModele() {
super();
noteService = NoteService.getInstance();
notes = noteService.findLastNotes();
}
@Override
public int getColumnCount() {
return entetes.length;
}
@Override
public String getColumnName(int columnIndex) {
return entetes[columnIndex];
}
@Override
public int getRowCount() {
return notes.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
// Nom
return notes.get(rowIndex).getEleve().getNom();
case 1:
// Prenom
return notes.get(rowIndex).getEleve().getPrenom();
case 2:
// Annee
return notes.get(rowIndex).getEleve().getAnnee();
case 3:
// Sexe
return notes.get(rowIndex).getEleve().getSexe();
case 4:
// Note au controle
return notes.get(rowIndex).getNote();
default:
throw new IllegalArgumentException();
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
case 1:
return String.class;
case 3:
return Sexe.class;
case 2:
return Integer.class;
case 4:
return Double.class;
default:
return Object.class;
}
}
public List<NoteEleve> getNotes() {
return notes;
}
}










