Programmation d`Applications Web Avancées Cours 3 Modèle MVC

publicité
Programmation d'Applications Web Avancées
Cours 3 Modèle MVC JSP (2)
Plan
1 XSLT ✔
2 DOM/Jaxp/JSP ✔
3 Modèle MVC/JSP (2)
3.1 Modèle MVC
3.2 Modèle : Rappels sur JDBC
3.3 Contrôleur : HttpServlet
2/20
Qu'est-ce que le modèle MVC ?
C'est un design pattern qui permet de modéliser des applications « interactives »
:
L'application possède un état interne
Un « utilisateur » (ça peut être un programme externe) interagit avec le
programme pour modifier l'état interne
L'application affiche à l'utilisateur le résultat de son opération
Ces trois aspects sont représentés par trois composants :
Le Modèle (représentation de l'état interne)
La Vue (affichage du modèle)
Le Contrôleur (modification du modèle)
3/20
En quoi est-ce adapté aux applications Web ?
Une application Web typique :
Présente au client un formulaire permettant de passer des paramètres (C)
Effectue des opérations sur une base de donnée (M) à partir des paramètres
Affiche une page Web montrant le résultat de l'opération (V)
4/20
Avantages du Modèle MVC ?
La séparation permet d'obtenir :
Maintenance simplifiée : Le code d'une action est centralisé à un seul endroit
Séparation des privilèges : Pas besoin que la vue ai un accès à la base de donnée
par exemple
Test simplifié : Les composants peuvent être testés indépendamment
5/20
MVC avec JSP ?
Dans une application JSP typique, le modèle MVC peut être implémenté de la
manière suivante :
Le modèle est représenté par des classes qui encapsulent les appels à une
base de données et présentent les résultats sous forme de POJO (Plain Old Java
Objects) ou d'un autre format génériqeu (XML, Json, …).
Le contrôleur est représenté par des HttpServlets. Ce sont des classes Java
dont le but est de : récupérer les paramètres utilisateur et les valider, appeler
les opérations du Modèle avec ses paramètres, passer le résultat de l'opération
à la Vue.
La vue est un ensemble de page JSP qui affichent les résultats. Elles
contiennent le moins possible de code Java et ne doivent ce soucier que de
l'affichage.
6/20
Plan
1 XSLT ✔
2 DOM/Jaxp/JSP ✔
3 Modèle MVC/JSP (2)
3.1 Modèle MVC ✔
3.2 Modèle : Rappels sur JDBC
3.3 Contrôleur : HttpServlet
7/20
Une base de données de films
On se place dans le cadre d'une application permettant d'accéder à une base de
données de films. Le schéma logique de la base est représenté par le diagramme
UML suivant :
Un film peut avoir plusieurs réalisateurs, et au moins un;
Un film a au moins un « acteur ». Un acteur est composé d'un rôle pour ce film
et d'une personne. Attention, le Role de Luke Skywalker est différent pour les
films Starwars IV, V, VI (même si c'est le même acteur et le même nom de rôle).
8/20
Encodage « naturel » en SQL
CREATE TABLE PEOPLE (pid INTEGER, firstname VARCHAR(30),
lastname VARCHAR(30),
PRIMARY KEY(pid));
CREATE TABLE MOVIE (mid INTEGER, title VARCHAR(90) NOT NULL,
year INTEGER NOT NULL,
runtime INTEGER NOT NULL, rank INTEGER NOT NULL,
PRIMARY KEY (mid));
CREATE TABLE ROLE (mid INTEGER, pid INTEGER, name VARCHAR(70),
PRIMARY KEY(mid, pid, name),
FOREIGN KEY (mid) REFERENCES MOVIE,
FOREIGN KEY (pid) REFERENCES PEOPLE);
CREATE TABLE DIRECTOR (mid INTEGER, pid INTEGER, PRIMARY KEY (mid, pid),
FOREIGN KEY (mid) REFERENCES MOVIE,
FOREIGN KEY (pid) REFERENCES PEOPLE);
entités ⟹ tables de données
relations ⟹ tables de jointure & contraintes de clé
(économie d'une table de données pour ROLE.name)
9/20
Création du modèle
On va créer deux classes Java pour le modèle :
Person : Une classe représentant une personne, avec son nom et son prénom
PersonDB : Une classe encapsulant la connexion à la base et permettant de
renvoyer l'ensemble (Java) de toutes les personnes de la base ayant une
certaine chaîne dans son nom.
public class Person {
private final String firstname;
private final String lastname;
public Person(String f, String l) {
this.firstname = f;
this.lastname = l;
}
public String getFirstname() { return firstname; }
public String getLastname() { return lastname; }
}
10/20
Classe P
e
r
s
o
n
Doit être publique
Doit posséder des getter publiques pour les attributs qu'on veut afficher dans
la vue
Le getter pour une propriété foo est une méthode publique getFoo()
11/20
Classe P
e
r
s
o
n
D
B
et rappels JDBC
public class PersonDB {
Connection cnx;
public PersonDB() {
Class.forName("org.postgresql.Driver");
cnx = DriverManager.getConnection(
"jdbc:postgresql://host:port/base",
"username", "password");
}
public Vector<Person> getPersons (String s) throws SQLException {
Vector<Person> res = new Vector<>();
Statement st = cnx.createStatement();
ResultSet r = st.executeQuery("SELECT * FROM PEOPLE "
+ " WHERE LASTNAME LIKE "
+ " '%" + s + "%'");
while (r.next())
res.add(new Person<>(r.getString("FIRSTNAME"),
r.getString("LASTNAME")));
return res;
}
}
12/20
Connexion à une base
Class.forName("org.postgresql.Driver");
connection =
DriverManager.getConnection("jdbc:postgresql://host:port/" + base,
username, password);
On importe dans la JVM courante le classe qui code le driver vers une base de
donnée (ici Postgresql)
Le code de cette classe doit se trouver dans un .jar ou .class accessible depuis
le CLASSPATH
La classe DriverManager maintient une Map entre chaîne de caractères
("jdbc:postgresql") et classe (org.postgresql.Driver)
La méthode getConnection utilise le préfixe de l'URL de connexion pour savoir
quel driver utiliser.
13/20
Exécution de requêtes
On crée un objet Statement
L'évaluation d'une requête se fait via executeQuery sur le Statement.
Un ResultSet implémente une interface d'itérateur, initialement positionné
avant la première ligne de résultats.
La méthode next avance dans l'itérateur et renvoie vrai tant qu'on est sur un
résultat.
On accède à la colonne voulue avec getType. On doit donner le type Java
correspondant au type SQL de la colonne. On peut accéder aux colonnes par
numéro (à partir de 1) ou par nom.
Remarque : On devrait plutôt utiliser un PreparedStatement pour éviter l'injection
de code. Ici on va utiliser le contrôleur pour valider la chaîne (exemple) mais ce
n'est pas idéal
14/20
Plan
1 XSLT ✔
2 DOM/Jaxp/JSP ✔
3 Modèle MVC/JSP (2)
3.1 Modèle MVC ✔
3.2 Modèle : Rappels sur JDBC ✔
3.3 Contrôleur : HttpServlet
15/20
H
t
t
p
S
e
r
v
l
e
t
La classe HttpServlet permet d'implémenter le contrôleur. C'est vers cette
classe que son compilée les pages JSP, mais dans le contrôleur, on ne va faire
aucun affichage, mais calculer un résultat et le stocker pour que la vue puisse
l'afficher.
16/20
Le contrôleur (1)
//Cette annotation permet de dire que le Servlet sera
//associée à l'URL /APPNAME/PersonListServlet
@WebServlet("/PersonListServlet")
public class PersonListServlet extends HttpServlet {
//Tomcat se sert de l'ID Pour savoir qu'un servlet a été
//modifié et donc que la version en cache doit être invalidée
private static final long serialVersionUID = 1234L;
}
//La méthode appelée si la requête est POST
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
//La méthode appelée si la requête est GET
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
…
}
17/20
Le contrôleur (2)
Comme la classe Java ne correspond pas à un fichier JSP, il faut donner (via
une annotation) un nom de fichier/URL virtuel pour appeler cette classe
Pour chaque type de requête HTTP (POST, GET, …) redéfinit une méthode doXXX
(où XXX vaut Get, Post, …)
Les requêtes ne peuvent lever que des ServletException ou IOException
Ces méthodes prennent en argument une request (la requête HTTP que qui
nous a amené sur ce servlet) et un response (qui sera envoyé au client
Dans notre exemple on dit que si on est appelé en POST alors on fait la même
chose qu'en GET.
18/20
Le contrôleur (3) : la méthode d
o
G
e
t
try {
//On crée un Modèle et on le stocke dans la session
PersonDB db = (PersonDB) request.getSession().getAttribute("db");
if (db == null) {
db = new PersonDB();
request.getSession().setAttribute("db", db);
}
//Récupération du paramètre GET comme dans un JSP
String s = request.getParameter("s");
//Netoyage de la chaîne
String ss = s.replaceAll("([%_0-9;,]|--)+", "");
Vector<Person> v = db.getPersons(ss);
request.setAttribute("people", v);
RequestDispatcher rd =
request.getRequestDispatcher("/person_list.jsp");
rd.forward(request,response);
} catch (Exception e) { throw new ServletException(e); }
19/20
Le contrôleur (4)
L'objet request permet d'accéder à la session et à l'application
On stocke le modèle (qui contient une connexion à la base dans la session)
On récupère le modèle et on l'appelle
On stocke les résultats dans un attribut de requête (pour que la page JSP de la
vue puisse y accéder)
On récupère un RequestDispatcher qui permet de charger une pages JSP (donc
une vue) particulière à la fin de la requête GET, avec la méthode forward
On encapsule toute exception éventuelle dans un ServletException
20/20
Téléchargement