PizzaLand Partie Java GUYENNE Jean-Baptiste, THIRUCHELVAM Bannuchan Groupe 332 PizzaLand | 2 Résumé Dans le cadre du S3 et du projet Java/BD, il nous a été demandé de concevoir la suite de la gestion du site de la pizzeria que nous avions étudiée en ACSI et Programmation Web. L’application devra permettre la gestion intere de la pizzeria, à savoir, l’affichage pour les cuisiniers des commandes à honorer, la gestion des stocks d’ingrédients,.. La gestion complète du système reposera sur un ensemble de 4 interfaces : - L’interface de cuisine, c’est la base même de la chaîne de production. Elle affichera la liste des commandes (avec leurs détails) à honorer et permettra d’indiquer qu’une commande est en cours de préparation ou prête. Les commandes y seront triées par ordre d’urgence, c’est-à-dire, les commandes effectuées il y a plus longtemps en tête de liste. L’interface devra permettre aux cuisinier de modifier l’état d’une commande : la commande passera successivement par les états ‘non préparée’, ‘en préparation’, ‘prête à être livrée’. L’interface devra également permettre aux cuisiniers de supprimer une commande (au cas où le client voudrait l’annuler). - L’interface des livreurs encore à la pizzéria. Elle permet au livreur d’être tenu au courant des commandes prêtes à être livrées ainsi que l’adresse de livraison. En saisissant un numéro de commande, le livreur verra s’afficher l’adresse de livraison ainsi que l’heure maximale à laquelle la commande doit être livrée pour ne pas être en retard. - L’interface des livreurs au moment de la livraison. Elle affichera l’adresse, le numéro de commande et indiquera également si le client avait payé sa commande à l’avance. - L’interface du gestionnaire, qui lui permettra d’avoir un historique des ingrédients consommés sur une période donnée, le chiffre d’affaire d’une période donnée, de planifier des commandes d’ingrédients,.. PizzaLand | 3 SOMMAIRE Résumé 2 Schéma relationnel 4 Analyse des séparations Java-/-Oracle 5 Diagramme des classes Java 5 Exemple d’utilisation d’accès à la base de données 6 Guide d’utilisation 7 Code de l’interface cuisinier 8 Code de l’interface livreur (encore à la pizzeria) 12 Code de l’interface livreur (en livraison) 12 Code de l’interface gestionnaire 12 Amélioration à effectuer 13 Problèmes rencontrés 13 Compte-rendu 14 PizzaLand | 4 Schéma relationnel Grâce à l’analyse préliminaire de conception que nous avions effectuée pour la partie ACSI et Programmation Web de la pizzéria, nous avons pu établir le schéma relationnel qui convenait à nos besoins : Comme indiqué lors de la Programmation Web, la gestion des boissons a été retirée afin de se concentrer sur les pizzas. La table STOCK, bien que l’utilité immédiate soit limitée, est une étape vers ce qui nous serait nécessaire pour gérer les boissons et autres produits. PizzaLand | 5 Analyse des séparations Java-/-Oracle - - - - Nous essayerons de minimiser la présence de code SQL dans le code source Java. Nous tâcherons ainsi d’utiliser au maximum la création de fonctions et procédures stockées PL/SQL. Ainsi les différentes sélections, insertions, mise à jour, suppression,.. dans la base de données se feront au possible grâce à des fonctions et procédures stockées. Les boutons de l’interface appelleront des procédures ou fonctions du modèle associé qui appelleront à leur tour des procédures ou fonctions PL/SQL (via des CallableStatement, PreparedCall,..). Pour la gestion des différentes alertes, comme par exemple la présence d’un nombre de commandes élevé (>20), nous utiliserons des triggers. L’application se chargera via un scan, régulier ou manuel, de la table d’alerte, de vérifier si une nouvelle alerte a été insérée. Dans ce cas, un message fortement visible apparaîtra à l’écran du gestionnaire et des cuisiniers. Pour l’affichage de l’heure maximale de livraison, nous ferons le calcul de cette heure via le code Java. Cela permet de libérer le serveur de la base de données d’un calcul qui pourrait être évité. Le code Java récupèrera donc l’heure de commande, lui ajoutera 30 minutes, et c’est cette nouvelle heure qui sera affichée au livreur. Au moment de la livraison, ce n’est pas le livreur qui indiquera lui-même si la commande a été livrée avec ou sans retard. Le livreur ne fera qu’indiquer l’heure de livraison, via l’interface dédiée à la livraison, et grâce à un trigger s’occupera de calculer le nouveau statut de la commande (livrée avec retard, livrée sans retard). Diagrammes des classes Java PizzaLand | 6 Exemples d’utilisation d’accès à la base de données - Mise à jour de l’état d’une commande : //Procédure qui appelle une procédure stockée pour mettre à jour l'état d'une commande //Paramètres : //int commande : numero de la commande concernée //String etat : nouvel état désirée ('en préparation', 'prête') public void updateEtat(int commande, String etat) throws SQLException { CallableStatement call = connection.prepareCall("call updateStateCommande(?,?)"); //On assigne les différents paramètres puis on exécute call.setInt(1, commande); call.setString(2, etat); call.execute(); } Avec une la commande suivante VALUES(427,1,4,8,7,1,1,SYSDATE,null,28); (1,1,4,8,7,1,1,SYSDATE,null,28) (==> (commande,panier,client,cuisinier,livreur,statut,paiement,dateCommande,dateLivraison,prix)) En appelant la procédure updateEtat(427,’livrée avec retard’), l’état de la commande va donc changé afin de faire correspondre son numéro d’état au numéro correspondant à l’état «livrée avec retardé ». La commande PizzaLand | 7 Guide d’utilisation (Le guide sera effectué sur des maquettes ressemblant au possible au résultat souhaité). Le bouton est grisé car la est déjà dans l’état ‘en préparation’. Le bouton est grisé car la commande n’est pas encore passé par l’état ‘en préparation’. Le bouton sert à indiquer que le cuisinier prend en charge cette commande. Le bouton sert à indiquer que la commande est prête à être livrée. PizzaLand | 8 Code de l’interface cuisinier a) Modèle package cuisinier.modeles; import java.sql.*; import java.util.ArrayList; import java.util.Observable; import java.awt.Toolkit; import java.util.Timer; import java.util.TimerTask; public class ModeleCuisinier extends Observable{ Connection connection; //Connexion à la base de données ArrayList<String[]> listeCommande; //Liste qui stockera les différentes commandes int cuisinier=-999; //Servira à dire quel cuisinier est sur le poste Toolkit toolkit; //Nécessaire pour le timer d'actualisation de la liste des commandes Timer timer; //Nécessaire pour le timer d'actualisation de la liste des commandes //Instanciation du modèle des cuisiniers //Connexion à la base de données ModeleCuisinier() throws SQLException{ listeCommande = new ArrayList<String[]>(); try{ Class.forName("oracle.jdbc.OracleDriver"); String url ="jdbc:oracle:thin:jguyenn/[email protected]:1521:etudom"; connection = DriverManager.getConnection(url); }catch(ClassNotFoundException cnfe){ System.out.println("La classe JDBC n'a pas été trouvée"); cnfe.printStackTrace(); } } //Procédure qui met à jour la liste des commande à honorer //Sera appelée via un bouton "Rafraîchir" et à chaque tick du timer public void updateListeCommande() throws SQLException{ listeCommande.clear(); //On vide la liste actuel String[] commande=new String[5]; //Création du tableau de String qui va contenir toutes les commandes en cours // commande[0] Numéro de commande // commande[1] Numéro de client // commande[2] Date de commande // commande[3] Montant total de la commande // commande[4] Liste des pizzas de la commande sous la forme // quantitex taille-type Aucun suppléments \n // quantitex taille-type Supplément(s) : supplement1 (, supplement2) (, supplement3) commande[0]=""; commande[1]=""; PizzaLand | 9 commande[2]=""; commande[3]=""; commande[4]=""; //Sélection des commandes à honorer et tri par priorité de date de commande Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery( "SELECT DISTINCT numCommande,client,dateCommande,COMMANDE.prixTotal FROM COMMANDE,STATUT" +" WHERE statut=STATUT.numStatut AND libelleStatut IN ('non préparée','en préparation') ORDER BY dateCommande DESC"); while(rs.next()){ commande[0]=rs.getString(1);//Stockage du numéro de commande commande[1]=rs.getString(2);//Stockage du numéro de client commande[2]=rs.getString(3);//Stockage de la date de commande commande[3]=rs.getString(4);//Stockate du montant total de la commande commande[4]=""; //Pour chaque commande trouvée, on recherche les différentes pizzas associées à cette commande Statement statement2 = connection.createStatement(); ResultSet rs2 = statement2.executeQuery( "SELECT quantite, libelleFormat,libelleType,supple1,supple2,supple3" +" FROM COMMANDE,PANIER,LIGNEPANIER,FORMATPIZZA,TYPEPIZZA,PIZZA" +" WHERE COMMANDE.numPanier=PANIER.numPanier" +" AND PANIER.numPanier=LIGNEPANIER.numPanier" +" AND LIGNEPANIER.numPizza=PIZZA.numPizza" +" AND PIZZA.numFormat=FORMATPIZZA.numFormat" +" AND PIZZA.numType=TYPEPIZZA.numType" +" AND numGarniture=supple1" +" AND numGarniture=supple2" +" AND numGarniture=supple3" +" AND COMMANDE.numCommande="+commande[0]); while(rs2.next()){ //Pour chaque pizza différente trouvée, on l'ajoute aux pizzas de la commande commande[4]=commande[4]+rs2.getString(1) + "x " + rs2.getString(2) + "-" +rs2.getString(3); //On regarde si elle en a au moins 1 //On concatène les suppléments trouvés à la pizza if(rs2.getInt(4)==0) { commande[4]=commande[4] + " Aucun suppléments"; } else { commande[4]=commande[4] + "Supplément(s) : "+ rs2.getString(4); if(rs2.getInt(5)!=0) { commande[4]=commande[4] + ", "+ rs2.getString(5); if(rs2.getInt(6)!=0) { commande[4]=commande[4] + ", "+ rs2.getString(6); } } } commande[4]=commande[4]+" \n "; }//fin sélection pizza d'une commande listeCommande.add(commande);//On ajoute la commande à la liste des commandes PizzaLand | 10 }//fin sélection liste commandes } //Procédure qui appelle une procédure stockée pour mettre à jour l'état d'une commande //Paramètres : //int commande : numero de la commande concernée //String etat : nouvel état désirée ('en préparation', 'prête') public void updateEtat(int commande, String etat) throws SQLException { CallableStatement call = connection.prepareCall("call updateStateCommande(?,?)"); //On assigne les différents paramètres puis on exécute call.setInt(1, commande); call.setString(2, etat); call.execute(); } //Fonction qui appelle un fonction stockée pour savoir si l'utilisateur de l'interface a bien rentré ses identifiants //et vérifie si il est membre du personnel //Paramètres : //String login : login rentré par l'utilisateur //String password : mot de passe rentré par l'utilisateur //Retour : "OK" || "Pas OK" //En fonction du résultat, on passera (ou non) de l'interface d'identification à l'interface des pizzaiolos //et on gardera le numéro du cuisinier en mémoire public String connection(String login, String password) throws SQLException { CallableStatement call = connection.prepareCall("{? = call identification(?,?) }"); //On identifie le type de retour call.registerOutParameter(1,Types.VARCHAR); //On assigne les différents paramètres puis on exécute call.setString(2, login); call.setString(3, password); call.execute(); return call.getString(1); } //Programme main de tests au développement public static void main(String[] args) throws SQLException { ModeleCuisinier modele=new ModeleCuisinier(); //Instanciation du modèle modele.updateListeCommande(); //mise à jour de la liste des commandes à honorer //Push::faudra faire un refresh de la liste //genre jtablecomm.clean() //for int i=0, i<arraylistcomm.size(), i++ // arraylistcomm.getitem(i); // for int j=0, j<5, j++ // jtablecomm.ligne(i).subitem(j)=arraylistcomm.getitem(i)[j]; // //faut trouver les vraies méthodes par contre //test rafraichissement auto sur timer :: } } PizzaLand | 11 b) Vue package cuisinier.vues; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.border.MatteBorder; public class VueCuisinier extends JFrame{ public static void main(String[] args) { //Création de la fenêtre JFrame mainFrame = new JFrame("PIZZALAND DE PONEYCITY"); //Création de la JTable qui va contenir la liste des commandes à honorer JTable tableCommande = new JTable(15,8); Color test=new Color(150,100,150); tableCommande.setGridColor(test); tableCommande.setRowHeight(75); //Ajout de la liste à la fenêtre mainFrame.add(tableCommande); ///////////////////////////////////// //tests // JLabel label = new JLabel(new String("test") ); mainFrame.add(label,BorderLayout.NORTH ); ///////////////////////////////////// //Paramètres de la fenêtre mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainFrame.setSize(1000,800); mainFrame.setLocationRelativeTo(null); mainFrame.setVisible(true); } } PizzaLand | 12 c) Contrôleur package cuisinier.controleurs; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class ControleurCuisinier implements ActionListener{ @Override public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub //agr0 cest le bouton qui lance l'actionperformed //if arg0.gettext()= "en prépa" then modele.updateEtat(JTableCommandes.getSelectedLine().getItem(0) <correspondant numCommande>> ,'en préparation') //if arg0.gettext()= "pret" then modele.updateEtat(JTableCommandes.getSelectedLine().getItem(0) <correspondant numCommande>> ,'prête à être livrée') } } Code de l’interface livreur (encore à la pizzeria) Code de l’interface livreur (en livraison) Code de l’interface gestionnaire PizzaLand | 13 Problèmes rencontrés - Malgré une configuration inchangée, SQLDeveloper ne voulait plus se connecter au serveur distant. Nous remercions le CCRI pour l’aide apportée pour résoudre ce problème. - Pour une même requête, Eclipse et SQLDeveloper ne nous retournait pas le même résultat. Par exemple le plus souvent, Eclipse nous afficher des doublons alors qu’il n’était pas censé y en avoir. - La transition de notre ancienne base de données de la partie Programmation Web, en mysql, à la nouvelle base, sous Oracle, a entrainé des pertes de temps importantes , notamment pour tout les changements de types non supportés, la syntaxe des contraintes,.. - Eclipse plante encore plus souvent qu’à l’IUT > perte de temps mineures mais présentes tout de même. - Parfois, au bout d’un moment, Eclipse n’affiche absolument aucun résultat quelle que soit la requête exécutée (ex : SELECT * FROM XX) Améliorations à effectuer - Partie BD : La création de packetages distincts, gérant chacun des aspects spécifiques de la pizzeria, serait utile. Création d’une fonction PL/SQL pour sélectionner toutes les commandes, plutôt que de le faire dans le code Java. Partie Java : Le projet n’ayant pas suffisamment avancé, nous ne pouvons pas dire quelles améliorations seraient à apporter. PizzaLand | 14 Compte-rendu Suite à une très mauvaise organisation, nous nous retrouvons avec très peu de travail effectué ; ce qui est dommage car nous nous faisions une joie à l’avance de travailler sur un projet concret en Java, qui nécessitait toutes nos connaissances en BD, et qui était la continuité du projet Pizzeria que nous avions déjà commencé. C’est dans ces moments que l’on se rend compte l’importance de la contrainte de temps dans la réalisation d’un projet.