TD2 : MVC
Transcription
TD2 : MVC
Applications Web dynamiques vers une architecture MVC Daniel Hagimont IRIT/ENSEEIHT 2 rue Charles Camichel - BP 7122 31071 TOULOUSE CEDEX 7 [email protected] http://hagimont.perso.enseeiht.fr 1 Servlet - Bilan Facile à programmer Programmation en Java Manque l'insertion de code dans les pages HTML Mélange entre aspects présentation (génération HTML), code métier et code d’accès aux données persistantes (à priori pas très MVC …) But séparer ces aspects 2 Modèle MVC Model View Controler Séparation entre Le contrôleur : servlet qui aiguille les requêtes La vue : pages JSP pour l’affichage à l’écran Le Modèle : les classes (beans) qui traitent les données Requête HTTP Réponse HTTP Controler (quel traitement ? quelle page ? ) Model (traitement) View (page web) 3 JSP (Java Server Page) Langage de script (proche de Java) Générer des pages dynamiques Intégré dans des pages web Compilé dynamiquement en servlet Interaction avec des classes Java parseur JSP compilateur Page.jsp Servlet.java Servlet.class 4 Un petit exemple <%@ page language="Java" %> <html> <head> <title>First.jsp</title> </head> <body> <h1>Nombres de 1 à 10</h1> <% for(int i=1; i<=10; i++) { out.println(i + "<br>"); } %> </body> </html> 5 Les directives <%@ directive attribut1="valeur" attribut2="valeur"... %> 3 directives possibles : page : informations relatives à la page • • • • <%@ page import=”...”%> <%@ page errorPage=”...”%> <%@ page isThreadSafe=”...”%> ... include : fichiers à inclure littéralement (file) • <%@ include file=”...”%> taglib : permet d'utiliser des librairies de tags personnalisés • <%@ taglib uri=”...” prefix=”...”%> 6 Les déclarations <%! declaration %> variables et méthodes globales à la page Exemple <%! String Chaine = ”bonjour”; int Numero = 10 ; public void jspInit() { // instructions } %> 7 Les scripts Java Du code Java : <% code Java %> Des évaluations d'expression : <%= expression %> Des variables prédéfinies <%@ page language="Java" %> <html><head><title>First.jsp</title> </head><body> <h1>Nombres de 1 à 10</h1> <% for(int i=1; i<=10; i++) { %> <%= i %> <br/> <% } %> </body> </html> Variables prédéfinies HttpServletRequest request HttpServletResponse response HttpSession session ServletContext application PrintWriter out ServletConfig config ... 8 Les actions Des tags standards des JSP de la forme <jsp:tag attribut1=”valeur” attribut2=”valeur”... /> <jsp:forward page=”page2.jsp” /> Transfère le contrôle à une autre page JSP (annule l’appelante) <jsp:include page=”page2.jsp” /> Transfère le contrôle à une autre page JSP (inclusion) Peuvent prendre des paramètres avec <jsp:param name=”...” value=”...” /> (une JSP ou une Servlet) 9 Les actions <jsp:useBean id="nomAttribut" class="package.classe" scope="portéeAttribut> <%-- code executé si l'attribut est créé --%> </jsp:usebean> Importe un attribut si il existe, le crée sinon <jsp:useBean id="personne" class="testjsp.Personne" scope="session/> équivaut à <% testjsp.Personne personne = (testjsp.Personne) session.getAttribute("personne"); if (personne == null) { personne = new testjsp.Personne(); session.setAttribute("personne", personne); } %> 10 Lien HTML/Servlet/JSP Une page HTML peut référencer une servlet Dans un formulaire <form action="Action" method="post"> </form> Une servlet peut référencer une page JSP RequestDispatcher disp = request.getRequestDispatcher(”page.jsp”); disp.forward(request, response); Passage de paramètre entre le servlet et la JSP request.setAttribute("key", value); value = (ValueType)request.getAttribute("key"); // enregistrement dans la request, la session, ou le context 11 Exemple : annuaire 12 Exemple : architecture Une page JSP pour chaque écran user.jsp, person.jsp, listusers.jsp Une servlet qui aiguille les requêtes vers les pages Deux objets Java (beans) pour gérer les données Person.java, ListOfPerson.java 13 Exemple : user.jsp <%@ page language="java" %> <html> <body> <form action="Action" method="post"> User : <input type="text" name="user"/><br/><br/> <input type="submit" value="enter"/> <input type="hidden" name="form" value="user"/> </form> </body> </html> 14 Exemple : person.jsp <%@ page language="java" %> <html> <body> <jsp:useBean id="user" class="directory.Person" scope="session" /> <b> Enter a person</b> <br/><br/> User: <%= user.user %><br/> <form action="Action" method="post"> Firstname : <input type="text" name="firstname"/><br/> LastName : <input type="text" name="lastname"/><br/> Email : <input type="text" name="email"/><br/><br/> <input type="submit" value="add"/> <input type="hidden" name="form" value="person"/> </form> </body> </html> 15 Exemple : listusers.jsp <%@ page language="java" import="directory.*, java.util.*"%> <html><body> <jsp:useBean id="listOfUsers" class="directory.ListOfPerson" scope="application"/> <b> List of registered persons </b> <br/><br/> <table border="2"> <tr><th>User</th><th>Firstname</th><th>Lastname</th><th>Email</th></tr> <% Enumeration enu = listOfUsers.list.elements(); while (enu.hasMoreElements()) { Person p = (Person)enu.nextElement(); %> <tr> <td><%= p.user %></td> <td><%= p.firstname %></td> <td><%= p.lastname %></td> <td><%= p.email %></td> </tr> <% } %> </table> </body></html> 16 Exemple : action.java (servlet) public class Action extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String form = request.getParameter("form"); HttpSession session = request.getSession(); ServletContext context = getServletContext(); if (form == null) { RequestDispatcher disp = request.getRequestDispatcher("user.jsp"); disp.forward(request, response); return; } ListOfPerson listOfUsers = (ListOfPerson)context.getAttribute("listOfUsers"); if (listOfUsers == null) { listOfUsers = new ListOfPerson(); context.setAttribute("listOfUsers", listOfUsers); 17 } Exemple : action.java (servlet) if (form.equals("user")) { String u = request.getParameter("user"); if (listOfUsers.contains(u)) { RequestDispatcher disp = request.getRequestDispatcher("listusers.jsp"); disp.forward(request, response); return; } else { Person p = new Person(); p.user = request.getParameter("user"); session.setAttribute("user", p); RequestDispatcher disp = request.getRequestDispatcher("person.jsp"); disp.forward(request, response); return; } } 18 Exemple : action.java (servlet) if (form.equals("person")) { Person p = (Person)session.getAttribute("user"); p.firstname = request.getParameter("firstname"); p.lastname = request.getParameter("lastname"); p.email = request.getParameter("email"); listOfUsers.list.add(p); RequestDispatcher disp = request.getRequestDispatcher("listusers.jsp"); disp.forward(request, response); } } } 19 Exemple : les beans public class Person { public String user, firstname, lastname, email; } public class ListOfPerson { public Vector list = new Vector(); public boolean contains(String user) { Enumeration enu = list.elements(); while (enu.hasMoreElements()) { Person p = (Person)enu.nextElement(); if (p.user.equals(user)) return true; } return false; } } 20 JSTL : Java Standard Tag Library De nombreux tags Évite de développer de nombreux opérations en Java Intéressant pour les Web designers Librairie de base <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> Repose sur le Expression Language (EL) ${requestScope.data.field} • Accès au scope request (default) • Récupère l'attribut data • Accès à l'attribut field Maintenant intégré aux JSP 21 Servlet/JSP - Bilan Présentation Sous forme de pages HTML Programmation en Java dans les pages Code métier Sous forme de servlet Échange de données avec les pages sous forme de javaBeans Modèle MVC donne une séparation claire entre Présentation (page JSP) Contrôle (servlet) Métier (programmes Java) Le traitement des données récupérées de la BD peuvent être lourds (d'où les EJB) 22 Modèle MVC Model View Controler Séparation entre Le contrôleur : servlet qui aiguille les requêtes La vue : pages JSP pour l’affichage à l’écran Le Modèle : les classes (beans) qui traitent les données Requête HTTP Réponse HTTP Controler (quel traitement ? quelle page ? ) Model (traitement) View (page web) 23 Architecture souhaitée Presentation (VC) Requête HTTP Réponse HTTP Business (M) Controler servlet result Facade Data View JSP/HTML 24 Architecture souhaitée Clients Client Java Client Web Client Web service Serveur d'application (Jboss) RMI SGBD (postgresql) EJB Container HTTP Web Container SOAP Servlet JSP BD EJB Facade Entity Web Services 25 Les EJB Entity beans Représentent les données manipulées par l’application Chaque Entity est associé à une table au niveau de la base de données Session beans Accessibles à distance (via RMI et IIOP) Implémentent le code métier Stateless session beans : sans état • Une instance pour plusieurs connexions clientes (allouée à partir d'un pool) • Ne conserve aucune donnée dans son état Statefull session bean : avec état • Création d’une instance pour chaque connexion cliente • Conserve des données entre les échanges avec le client Singleton: Instance Unique • Création d’une instance unique quelque soit le nombre de connexion. Message Driven Beans : Beans de messages Un listener exécute des traitements à réception d'un message JMS 26 EJB session Interface Remote (annotation @Remote) Accessible à distance Interface Local (annotation @Local) Accessible en local uniquement (dans le serveur d'application) Si on ne définit pas d'interface, Local par défaut Classe du bean (annotations @Singleton, @Statefull, @Stateless) Peut implanter les 2 interfaces Local et Remote JNDI Les interfaces définies sont exportées dans JNDI Nom de la classe utilisée, ou nom passé en attribut du tag • @Singleton(name="monBean") Une recherche retourne une référence au bean (unique ou une copie) 27 Un exemple : application bancaire Gestion de compte Données • numero, nom, solde Méthodes • • • • • Ajouter un compte Consulter un compte Consulter tous les comptes Créditer sur un compte Débiter d'un compte 28 Les données manipulées public class Compte implements Serializable { private int num; private String nom; private int solde; public Compte() {} public Compte(int num, String nom, int solde) { this.num = num; this.nom = nom; this.solde = solde; } public String toString() { return "Compte [num="+num+", nom="+nom+", solde="+solde+"]"; } // setters and getters 29 Interface Remote / interface Local @Remote public interface IBanqueRemote { public void addCompte(Compte c); public List<Compte> consulterComptes(); public Compte consulterCompte(int num); public void debit(int num, int montant); public void credit(int num, int montant); } @Local public interface IBanqueLocal { public void addCompte(Compte c); public List<Compte> consulterComptes(); public Compte consulterCompte(int num); public void debit(int num, int montant); public void credit(int num, int montant); } 30 Implantation d'un EJB session @Singleton public class BanqueEjbImpl implements IBanqueLocal, IBanqueRemote { private Map<Integer, Compte> comptes = new Hashtable<Integer, Compte>(); public void addCompte(Compte c) { comptes.put(c.getNum(), c); } public List<Compte> consulterComptes() { return new ArrayList<Compte>(comptes.values()); } public Compte consulterCompte(int num) { Compte c = comptes.get(num); if (c == null) throw new RuntimeException("Compte introuvable"); return c; } 31 Implantation d'un EJB session public void debit(int num, int montant) { Compte c = consulterCompte(num); if (c.getSolde()<montant) throw new RuntimeException("Solde insuffisant"); c.setSolde(c.getSolde()-montant); } public void credit(int num, int montant) { Compte c = consulterCompte(num); c.setSolde(c.getSolde()+montant); } @PostConstruct public void initialisation() { addCompte(new Compte(1, "dan", 2000)); addCompte(new Compte(2, "alain", 4000)); addCompte(new Compte(3, "luc", 6000)); } } 32 Déploiement dans JBoss On déploie l'archive du projet (war) qui inclut Les 2 interfaces : IBanqueLocal et IBanqueRemote Les 2 classes : Compte et BanqueEjbImpl <project-ejb> Export → WAR File Dans JBoss On a lancé JBoss (bin/standalone.sh) On exporte le war dans standalone/deployments Le bean est exporté dans le JNDI du serveur 33 Déploiement dans JBoss 34 Un client lourd Un projet Java séparé Utilise RMI pour accéder à l'interface Remote public class ClientEjb { public static void main(String args[]) { try { String appName=""; String moduleName="bank"; String distinctName="BanqueEjbImpl"; String viewClassName=IBanqueRemote.class.getName(); Context ctx = new InitialContext(); String jndiName = "ejb:"+appName+"/"+moduleName+"/"+distinctName +"!"+viewClassName; System.out.println(jndiName); IBanqueRemote stub = (IBanqueRemote)ctx.lookup(jndiName); System.out.println("affichage de tous les comptes"); List<Compte> cptes = stub.consulterComptes(); for(Compte cp:cptes) System.out.println(cp); } catch (Exception ex) {ex.printStackTrace();} } } 35 Un client web (servlet) Soit la servlet est dans une JVM séparée Configuration comme un client lourd Soit la servlet est dans le serveur d'application (avec les EJB) Injection de dépendance @EJB private IBanqueLocal facade; Au déploiement, variable initialisée avec une instance • de stateless, statefull ou singleton 36 Un client web (servlet) @WebServlet("/Controller") public class Controller extends HttpServlet { private static final long serialVersionUID = 1L; @EJB private IBanqueLocal facade; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { String action=request.getParameter("action"); if (action.equals("consulter")) { int num=Integer.parseInt(request.getParameter("num")); request.setAttribute("num", num); request.setAttribute("compte", facade.consulterCompte(num)); } else if (action.equals("consultertous")) { request.setAttribute("comptes", facade.consulterComptes()); } else 37 Un client web (servlet) if ((action.equals("debit")) || (action.equals("credit"))) { int num=Integer.parseInt(request.getParameter("num")); int montant=Integer.parseInt(request.getParameter("montant")); request.setAttribute("num", num); request.setAttribute("montant", montant); if (action.equals("debit")) facade.debit(num, montant); else facade.credit(num, montant); } } catch (Exception ex) { request.setAttribute("exception", ex.getMessage()); } request.getRequestDispatcher("Banque.jsp").forward(request, response); } } 38 Une petite JSP <%@ page language="java" import="bk.*, java.util.*" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="Controller" method="get"> <table> <tr> <td> Code :</td> <td><input type="text" name="num" value="${num}"></td> <td><input type="submit" name="action" value="consulter"></td> <td><input type="submit" name="action" value="consultertous"></td> </tr> </table> </form> 39 Une petite JSP <% if (request.getAttribute("compte") != null) { %> <table> <tr><td> Num :</td><td>${compte.num}</td></tr> <tr><td> Nom :</td><td>${compte.nom}</td></tr> <tr><td> Solde :</td><td>${compte.solde}</td></tr> </table> <form action="Controller" method="get"> <table> <tr> <td><input type="hidden" name="num" value="${num}"></td> <td><input type="text" name="montant" value="${montant}"></td> <td><input type="submit" name="action" value="debit"></td> <td><input type="submit" name="action" value="credit"></td> </tr> </table> </form> <% } %> 40 Une petite JSP <% List<Compte> l = (List<Compte>)request.getAttribute("comptes"); if (l != null) { %> <table border="1" width="80%"> <tr> <th>Num</th><th>Nom</th><th>Solde</th></tr> <% for (Compte c : l) { %> <tr><td><%=c.getNum() %></td><td><%=c.getNom() %></td><td><%=c.getSolde() %></td></tr> <% } %> </table> <% } %> ${exception} </body> </html> 41 Exécution 42