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

Documents pareils