You are on page 1of 10

Lapplication Lapplication histogramme histogramme de de notes notes

serveur Web Serveur SGBD

Consultation des Notes


Anatomie Anatomie dune dune application application web web
Histogramme des notes image gif Page HTML avec fr frquences des notes dans un tableau

Quelle architecture pour le tier web ?

Objectifs :au travers l'tude d'une application simple illustrer la mise en uvre d'approche Modle, Vue, Contrle (MVC) Technologies : Servlets JSP JDBC (utilisation de DataSources)

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010 Philippe GENOUD -Patrick REIGNIER - UJF

1
Janvier 2010

Rappel architecture MVC


Bonne sparation des diffrents composants dune application Web Modularit rutilisation volutivit Sparation des comptences
Requte HTTP Serveur Internet (Serveur HTTP + Serveur Servlet/JSP)

Rappel Architecture MVC


Serveur SGBD

Modle Model View Controler (Modle 2 pour applications JSP)


Contrle Analyse des requtes de lutilisateur Mise en place des traitements Mise en place de la prsentation
Rponse HTTP 2

Controleur Controleur (Servlet) (Servlet)


1

Construit Modifie

Transfert

Modle Modle (Java (JavaBean) Bean)

Driver JDBC

Modle Effectue les traitements couche mtier Vue Prsentation des rsultats

Vue Vue (JSP) (JSP)

Consulte

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

Lapplication Lapplication histogramme histogramme de de notes notes


Controleur Controleur (Servlet) (Servlet) (JavaBean) (JavaBean)
Histogramme Histogramme

Le modle
Modle (objet mtier) : classe qui reprsente une des entit du domaine qui pourra ensuite tre utilise par les composants Web
Par exemple ici une classe Histogramme qui reprsente un histogramme de notes
Histogramme POO 2005

Serveur SGBD

Histogramme
- String matiere - int annee - int[] freq = new int[21] + Histogramme()
0 1 2 ... 9 10 ... 18 19 20

propri proprits constructeur sans param paramtres 0 1 3 ... 12 10 ... 1 0 0

index.html
HistogramImager HistogramImager

(Servlet) (Servlet)
Tableau.jsp Tableau.jsp

+ String getMatiere() + void setMatiere(String m) + int getAnnee() + void setAnnee(int a) + int getFreq(int n) + void setFreq(int n, int freq) + int notePlusFrequente() + double moyenne() + double ecartType()

(JSP) (JSP)

accesseurs (getters) et modifieurs (setters) pour les diff diffrentes propri proprits que l'on veut exposer

Des m mthodes sp spcifiques (m (mtier)

Pour faciliter son utilisation par les composants web (en particulier pages JSP via EL) le modle doit tre sous la forme d'un java bean
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

Le modle
Aller chercher dans la Bd les frquences des notes pour une matire et une anne donne
Histogramme POO 2008 matire="poo" anne=2008 Anne 2003 2003 ... 2008 ... 2008 2008 2008 ... 2005 select note, count(*) count(*) from notes where annee= annee=2005 and matiere= matiere='poo' poo' group by note 2 1
note 1 2 9 18 count 1 3 12 1 0 1 2 ... 9 10 ... 18 19 20

Le modle
Aller chercher dans la Bd les frquences des notes pour une matire et une anne donne
Histogramme Serveur SGBD

Serveur SGBD

notes POO 2008 matire="poo" anne=2008 Anne 2003 2003 ... 2008 ... 2008 2008 2008 ... 2005 note 7 14 ... 10 ... 12 11 8 ... 16 Matire bd ihm ... poo ... ihm bd poo ... poo noEtud 20234 20014 ... 21345 ... 20014 20234 20234 ... 21417 0 1 3 ... 12 10 ... 1 0 0 1) Faire requte SQL via JDBC

notes

0 1 2 ... 9 10 ... 18 19 20

0 1 3 ... 12 10 ... 1 0 0 Construire un tableau des fr frquences qui pourra ensuite tre consult consult par les composants web note 7 14 ... 10 ... 12 11 8 ... 16 2) Parcourir le ResultSet pour remplir le tableau des fr frquences
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010 Philippe GENOUD -Patrick REIGNIER - UJF

Matire bd ihm ... poo ... ihm bd poo ... poo

noEtud 20234 20014 ... 21345 ... 20014 20234 20234 ... 21417

7
Janvier 2010

Le modle
Aller chercher dans la Bd les frquences des notes pour une matire et une anne donne
Servlets Client Histogramme POO 2008 matire="poo" anne=2008 notes Pages JSP Compte Serveur SGBD prsentation mtier Accs aux donnes ClientDAO

Architecture en couches
JDBC
CompteDAO

Navigateur Serveur d'application Java


Anne 2003 2003 ... 2008 ... 2008 2008 2008 ... 2005 note 7 14 ... 10 ... 12 11 8 ... 16 Matire bd ihm ... poo ... ihm bd poo ... poo noEtud 20234 20014 ... 21345 ... 20014 20234 20234 ... 21417

SGBD Relationnel

0 1 2 ... 9 10 ... 18 19 20

0 1 3 ... 12 10 ... 1 0 0

code JDBC

O mettre ce code JDBC ?


dans le code qui utilise le modle (ici la Servlet) ?

dans le modle ? ailleurs ?


Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

Les objets DAO (Data Access Object) isolent tout le code li la persistance des donnes Quand l'application a besoin d'effectuer une opration lie la persistance elle fait appel un objet DAO L'interface des objets DAO est indpendante du support de persistance Le reste de l'application utilise les DAO uniquement au travers de leur interface abstraite Par exemple si on change d'implmentation de DAO pour passer d'une base Oracle des fichiers XML le reste de l'application demeure inchang. Chaque classe d'objet mtier a son propre type de DAO (IClientDAO, ICompteDAO) Le mme objet DAO peut tre utilis pour les objets d'une mme classe d'objet mtier

souvent on rajoute une couche DAO(Data Acces Objects)


9
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

10

Lapplication Lapplication histogramme histogramme de de notes notes


l'objet NotesDAO construit l'objet Histogramme
JDBC Controleur Controleur (Servlet) (Servlet) (JavaBean) (JavaBean)
Histogramme Histogramme

ex : objet DAO pour les notes


<interface> INotesDAO
void createNote(Note n)

NotesDAO NotesDAO

Op Oprations CRUD Create


Note getNote(int numEtud, int annee, String matiere) Histogramme getHistogramme(int annee, String matiere) Collection<Note> notesEtudiant(int numEtud) Collection<Note> notesEtudiant(int numEtud, int annee)

Serveur SGBD

Retreive
Collection<Note> notesEtudiant(int numEtud, String matiere)

index.html
HistogramImager HistogramImager

(Servlet) (Servlet)
Tableau.jsp Tableau.jsp

void updateNote(Note n) void deleteNote(Note n)

(JSP) (JSP)

Update Delete

OracleNotesDAO

MySQLNotesDAO

XMLNotesDAO

Des classes d'impl d'implmentation

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

11

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

12

ex : objet DAO pour les notes


<interface> INotesDAO
void createNote(Note n) Note getNote(int numEtud, int annee, String matiere) Histogramme getHistogramme(int annee, String matiere) Collection<Note> notesEtudiant(int numEtud) Collection<Note> notesEtudiant(int numEtud, int annee) Collection<Note> notesEtudiant(int numEtud, String matiere) void updateNote(Note n) void deleteNote(Note n) try { peuvent lancer des SQLException public Histogramme getHistogramme(int annee, public Histogramme getHistogramme(int annee, String matiere) throws DAOException String matiere) { {

ex : objet DAO pour les notes


cration d'une classe d'exception indpendante du type de DAO (DAOException) les mthodes d'implmentation des DAO attrapent les exceptions particulires (par exemple SQLException) et relancent des DAOException les exceptions d'origine sont chanes aux DAOException
OracleNotesDAO.java

Op Oprations CRUD Create

Retreive

Update Delete
parcours du r rsultat de la requte pour remplir le tableau des fr frquences de l'objet Histogramme retourne l'objet Histogramme } catch (SQLException (SQLException e) { } } } throw new DAOException(" DAOException("pb ("pb recup recupration histogramme" , e); cr cration d'un objet Histogramme

fait requte JDBC

le code d'implmentation de ces mthodes effectue des entres/sorties (dans il peut donc lever des exceptions (SQLException) notre cas accs la BD) Que faire de ces exceptions ?
Les attraper ? try { } catch (SQLException e) { } Les faire remonter ? throws SQLException mais si on veut pouvoir changer facilement de DAO il ne faut pas lier les exceptions un type de DAO particulier
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010 Philippe GENOUD -Patrick REIGNIER - UJF

13
Janvier 2010

14

ex : objet DAO pour les notes


<interface> INotesDAO
public Histogramme void createNote(Note n) throws DAOException try {

ex : objet DAO pour les notes


getHistogramme(int annee, String matiere) throws DAOException {

connexion JDBC la BD

Note getNote(int numEtud, int annee, String matiere) throws DAOException Histogramme getHistogramme(int annee, String matiere) throws DAOException Collection<Note> notesEtudiant(int numEtud) throws DAOException Collection<Note> notesEtudiant(int numEtud, int annee) throws DAOException Collection<Note> notesEtudiant(int numEtud, Strin matiere) throws DAOException void updateNote(Note n) throws DAOException void deleteNote(Note n) throws DAOException

fait requte JDBC

stmt = conn.createStatement() ;

O et quand crer (ouvrir) la connexion ? Quand la librer (fermer) ?

result = stmt.executeQuery("select note, count(*) from notes" + " where annee = " + annee + " and matiere='" + matiere + "' group by note") ;

Histogramme hist = new Histogramme(); cration d'un objet Histogramme hist.setMatiere(matiere); hist.setAnnee(annee);

Dans le code qui utilise les objets DAO ? moyen ce code doit tre le plus

Pour les classes d'implmentation assurant la persistence avec une BD toutes ces mthodes ont besoin d'une connexion JDBC la base de donne O et quand crer (ouvrir) la connexion ? Quand la librer (fermer) ?

while (result.next()) parcours du rsultat de { la requte pour remplir le tableau indpendant possible des DAO note = result.getInt(1); des frquences de l'objet Histogramme hist.setFreq(i,result.getInt(2)); Dans le code des DAO ? } rs.close(); stmt.close(); au dbut et la fin de chaque mthode return hist; retourne l'objet Histogramme

ncessitant une connexion ? connexion attribut de l'objet DAO, accessible

} depuis toutes les mthodes ? catch (SQLException e) { throw new DAOException("pb histogramme ", e); } }
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

15

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

16

DAO : connexion connexion la la BD BD


Connexion / dconnexion chaque requte (dbut et la fin de chaque mthode)
public Histogramme Connection conn = null; try { conn = DriverManager.getConnection(url , user, passwd); stmt = conn.createStatement() ; getHistogramme(int annee, String matiere) throws DAOException {

DAO : connexion connexion la la BD BD


Connexion attribut du DAO partag par toutes les requtes (mthodes) du DAO
public class OracleNotesDAO implements INotesDAO Connection conn = null; connexion initialise dans le constructeur public OracleNoteDAO() throws DAOException { ... Class.forName("oracle.jdbc.OracleDriver); conn = DriverManager.getConnection(url , user, passwd);
public Histogramme getHistogramme(int annee, String matiere)throws DAOException { ... try { stmt = conn.createStatement() ;

Opration coteuse Approche peu efficace

result = stmt.executeQuery("select note, count(*) from notes" + " where annee = " + annee + " and matiere='" + matiere + "' group by note") ; Histogramme hist = new Histogramme(); hist.setMatiere(matiere); hist.setAnnee(annee); // parcours du rsultat de la requete et pour chaque note // on reporte son nombre d'occurences dans le tableau freq while (result.next()) { note = result.getInt(1); hist.setFreq(i,result.getInt(2)); } finally { rs.close(); stmt.close(); if (conn != null) { return hist; try { } conn.close(); catch (SQLException e) { } catch (SQLException e) { throw new DAOException("pb histogramme ", e); throw new DAOException(e); } } }
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

result = stmt.executeQuery("select note, count(*) from notes" + " where annee = " + annee + " and matiere='" + matiere + "' group by note") ; Histogramme hist = new Histogramme(); hist.setMatiere(matiere); hist.setAnnee(annee); // parcours du rsultat de la requete et pour chaque note // on reporte son nombre d'occurences dans le tableau freq while (result.next()) { connexion ferme lorsque l'objet note = result.getInt(1); DAO n'est plus utilis hist.setFreq(i,result.getInt(2)); } public void finalize() { rs.close(); stmt.close(); return hist; if (conn != null) { } try { catch (SQLException e) { conn.close(); throw new DAOException("pb histogramme ", e); } }

} catch (SQLException e) { // que faire ???? } } 17 ... }


Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

} 18

DAO : connexion connexion la la BD BD


Rappel Rappel : : Cycle Cycle de de vie vie des des Servlets Servlets
Moteur de servlets Thread Thread Thread Crer un pool de threads Instancier la servlet Servlet Appeler init() initialisation Requte HTTP 1 Appeler service() Appeler service() Excuter le service Requte HTTP 2 Affecter une requte un thread Rponse HTTP 1 Excuter le service Rponse HTTP 2 Terminer le pool de threads Appeler destroy() Affecter une requte un thread

Connexion attribut du DAO partag par toutes les requtes (mthodes) du DAO Nombreux problmes possibles : Timeout : la connexion peut tre ferme automatiquement (par exemple si l'utilisateur a cess momentanment son activit sans quitter l'application). Passage l'chelle si pour chaque utilisateur (session) un objet DAO avec une connexion est cre nombre d'utilisateur limit par le nombre de connexions pouvant tre ouverte simultanment Risques d'incohrences si mme objet DAO donc mme objet connexion partag par plusieurs utilisateurs ne pas oublier que les servlets sont multithreads : la mme instance sert toutes les requtes

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010 Philippe GENOUD -Patrick REIGNIER - UJF

19
Janvier 2010

20

pb pb du du partage partage d'une d'une connexion connexion


temps t1

Pool Pool de de connexions connexions


Utilisation dune liste (cache) de connexions disponibles : Pool de connexions Lors de laccs la base de donnes : Demande dune connexion disponible au Pool de connexions vite la cration de nouvelles connexions (ce qui est coteux) Accs la BD travers cette connexion Restitution de la connexion au Pool de connexions Au niveau du Pool de connexions gestion de liste des connexions : Cration de nouvelles connexions si ncessaire Fermeture des connexions inactives depuis trop longtemps javax.sql package dextension standard de JDBC Pour les applications JEE (Java Entreprise Edition) Inclus en standard dans JSE (Java Standard Edition) depuis version 1.4 interface javax.sql.DataSource pour une source de donnes grant un pool de connexions

noitcasnart al etubd 1t noitcasnart enu reutceffe ruop noixennoc al erugifnoc 1t 1 ruetasilitu ruop 1t daerht nu'd noitarC
La connexion est en mode autoCommit La mise jour de la table est immdiatement effective ! } ... Une partie du code ex excut cut par la m mthode service d'un servlet ... try { con.setAutoCommit(false); // excuter les instructions // qui constituent la transaction stmt.executeUpdate(...); stmt.executeUpdate(...); // valide la transaction con.commit(); con.setAutoCommit(true); } catch (SQLException e) { con.rollback(); // annule // les oprations de la transaction t2
noitcasnart enu reutceffe ruop noixennoc al erugifnoc 2t

timmoCotua edom el eutitser 1t )evitceffe tse selbat sed ruoj esim al( noitcasnart al edilav 1t

2 ruetasilitu ruop 2t daerht nu'd noitarc

javax.sql package dextension standard de JDBC Pour les applications JEE (Java Entreprise Edition) Inclus en standard dans JSE (Java Standard Edition) depuis version 1.4 DataSource : Obtention du nom de la base partir de serveurs de noms plutt que davoir le nom de la base de donnes cod en dur dans lapplication. Utilisation de JNDI (Java Naming and Directory Interface) pour connexion une base de donne PooledConnection : support pour gestion dun pool de connexion gestion dun cache des connexion ouvertes vite la cration de nouvelles connexions (ce qui est coteux) Quand un code a besoin d'accder la base de donnes, il obtient une connexion en s'adressant la DataSource
DataSource

noitcasnart al etubd 2t

noitcasnart al tiusruop 1t
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

21

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

22

javax.sql

javax.sql.DataSource
L'objet DataSource avec pooling de connexions maintient un ensemble de connexions la BD prtes l'emploi (pool ou cache de connexions).

Connection En fait PooledConnection DataSource ds; ... Connection c = ds.getConnnection(); ...

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

23

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

24

javax.sql.DataSource
L'objet DataSource avec pooling de connexions maintient un ensemble de connexions la BD prtes l'emploi (pool ou cache de connexions).
DataSource DataSource

javax.sql.DataSource
L'objet DataSource avec pooling de connexions maintient un ensemble de connexions la BD prtes l'emploi (pool ou cache de connexions).

Connection En fait PooledConnection DataSource ds; ... Connection c = ds.getConnnection(); ... c = c.close(); c = c.close(); DataSource ds; ... Connection c = ds.getConnnection(); ...

Connection En fait PooledConnection

Quand un code a besoin d'accder la base de donnes, il obtient une connexion en s'adressant la DataSource. Il conserve la connexion jusqu' sa fermeture explicite.
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010 Philippe GENOUD -Patrick REIGNIER - UJF

Quand un code a besoin d'accder la base de donnes, il obtient une connexion en s'adressant la DataSource. Il conserve la connexion jusqu' sa fermeture explicite. Lorsqu'une connexion est "ferme", elle est en fait relche et remise dans le pool.
25
Janvier 2010

26

DAO : connexion connexion la la BD BD


utilisation d'une DataSource pour acqurir les connexions
public class OracleNotesDAO implements INotesDAO private DataSource ds = null; initialise dans le constructeur du DAO ou par une mthode set }
public Histogramme getHistogramme(int annee, String matiere)throws DAOException { try { stmt = conn.createStatement() ; conn = ds.getConnection(); result = stmt.executeQuery("select note, count(*) from notes" + " where annee = " + annee + " and matiere='" + matiere + "' group by note") ; Histogramme hist = new Histogramme(); hist.setMatiere(matiere); hist.setAnnee(annee); // parcours du rsultat de la requete et pour chaque note // on reporte son nombre d'occurences dans le tableau freq while (result.next()) { note = result.getInt(1); hist.setFreq(i,result.getInt(2)); } finally { rs.close(); stmt.close(); if (conn != null) { return hist; try { } catch (SQLException e) { conn.close(); throw new DAOException("pb histogramme ", e); } catch (SQLException e) {

DAO : connexion connexion la la BD BD


Pattern "Singleton" : un DAO pour une data source donne (viter de crer des instances inutiles)
public class OracleNotesDAO implements INotesDAO private DataSource ds = null;

public OracleNotesDAO(DataSource ds) { this.ds = ds;

Connection conn = null;

private static Map<DataSource,OracleNotesDAO> daoInstances = new HashMap<DataSource,OracleNotesDAO>(); public synchronized static OracleNotesDAO getInstance(DataSource ds) { OracleNotesDAO inst = daoInstances.get(ds); if (inst == null) { inst = new OracleNotesDAO(ds); daoInstances.put(ds,inst); } return inst; } private public OracleNotesDAO(DataSource ds) { this.ds = ds; }

throw new DAOException(e); } } }


Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

... } 27

public Histogramme getHistogramme(int annee, String matiere)throws DAOException { ... ... }


Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

28

Dfinir Dfinir un un pool pool de de connexions connexions avec avec TomCat TomCat
javax.sql.DataSource = pool de connexions Interface dans javax.sql.DataSource Objet DataSource pris en charge par le serveur TomCat org.apache.commons.dbcp.BasicDataSource Cr par le serveur Tomcat partir de paramtres de configuration ressource globale un contexte (ressource partage par toutes les sessions d'une mme application) description dans le fichier context.xml de l'application ressource globale partage par tous les contextes description dans le fichier server.xml

Dfinir Dfinir un un pool pool de de connexions connexions avec avec Tomcat Tomcat
Dfinition d'une ressource de type DataSource pour le contexte de l'application dans le fichier de configuration context.xml de l'application Dsignation cette ressource dans le fichier de dploiement de l'application dans le fichier web.xml de l'application Installer le pilote JDBC dans le rpertoire lib de Tomcat
Voir dans la documentation de Tomcat http://tomcat.apache.org/tomcat-x.x-doc/index.html

Mis disposition des applications par un serveur dobjets : on rcupre l'objet DataSource cr et gr par le conteneur au travers d'un identificateur (API JNDI (Java Naming Directory Interface))
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

jndi-datasource-examples-howto.html

29

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

30

Dfinir Dfinir un un pool pool de de connexions connexions avec avec TomCat TomCat
Dfinir Dfinir un un pool pool de de connexions connexions avec avec Tomcat Tomcat
1

Dfinition d'une ressource de type DataSource pour le contexte de l'application dans le fichier de configuration context.xml de l'application Dsignation cette ressource dans le fichier de dploiement de l'application dans le fichier web.xml de l'application Installer le pilote JDBC dans le rpertoire lib de Tomcat
context.xml <Context path="/HistogramMVC"> <Context path="/HistogramMVC">

Plus de rfrence explicite dans le code Au driver jdbc A lurl daccs la base Au nom de lutilisateur A son mot de passe Possibilit de changer de base lors du dploiement sans avoir besoin de recompiler lapplication. Il suffit de modifier les fichiers de configuration
Paramtrage de la connexion JDBC <Resource name="jdbc/Notes" <Resource name="jdbc/Notes" auth="Container" auth="Container" type="javax.sql.DataSource" type="javax.sql.DataSource" Paramtrage du maxActive="10" maxActive="10" pool de connexion maxIdle="3" maxIdle="3" maxWait="10000" maxWait="10000" username="genoud" username="genoud" password="xxxxxxx" password="xxxxxxx" driverClassName="oracle.jdbc.OracleDriver" driverClassName="oracle.jdbc.OracleDriver" url="jdbc:oracle:thin:@hopper.e.ujf-grenoble.fr:1521:ufrima"/> url="jdbc:oracle:thin:@hopper.e.ujf-grenoble.fr:1521:ufrima"/> </Context> </Context>

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010 Philippe GENOUD -Patrick REIGNIER - UJF

31
Janvier 2010

32

Dfinir Dfinir un un pool pool de de connexions connexions avec avec Tomcat Tomcat
Dfinition d'une ressource de type DataSource pour le contexte de l'application dans le fichier de configuration context.xml de l'application
2

Dfinir Dfinir un un pool pool de de connexions connexions avec avec Tomcat Tomcat
Dfinition d'une ressource de type DataSource pour le contexte de l'application dans le fichier de configuration context.xml de l'application Dsignation cette ressource dans le fichier de dploiement de l'application dans le fichier web.xml de l'application
3

Dsignation cette ressource dans le fichier de dploiement de l'application dans le fichier web.xml de l'application Installer le pilote JDBC dans le rpertoire lib de Tomcat
web.xml ... <servlet-mapping> ... </servlet-mapping>

Installer le pilote JDBC dans le rpertoire lib de Tomcat

Si vous lancez Tomcat depuis Netbeans et que vous n'avez pas le droit d'criture dans le rpertoire d'installation de Tomcat vous pouvez configurer l'instance de Tomcat que vous utilisez l'aide des fichiers contenus dans le fichier .netbeans qui se trouve sur votre compte

<resource-ref> <res-ref-name>jdbc/Notes</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>


...

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

33

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

34

Dfinir Dfinir un un pool pool de de connexions connexions avec avec Tomcat Tomcat
1
<GlobalNamingResources> <Environment name="simpleValue" type="java.lang.Integer" value="30"/> <Resource auth="Container" description="User database that can be updated and saved" name="UserDatabase" type="org.apache.catalina.UserDatabase" pathname="conf/tomcat-users.xml" factory="org.apache.catalina.users.MemoryUserDatabaseFactory"/> <Resource name="jdbc/test" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" password="xyyyyyyy" maxIdle="2" maxWait="5000" username="genoud" url="jdbc:mysql://localhost/essai" maxActive="4"/> </GlobalNamingResources>

Dfinir Dfinir un un pool pool de de connexions connexions avec avec Tomcat Tomcat
Dfinition d'une ressource globale partage par tous les contextes
context.xml de l'application

Dfinition d'une ressource globale partage par tous les contextes Description dans le fichier de configuration du serveur ($CATALINA_HOME/conf/server.xml)

Dclaration d'un lien pour chaque contexte qui peut y accder (fichier context.xmldes applications concernes)
web.xml de l'application

Dsignation cette ressource dans le fichier de dploiement (web.xml)de l'application

La dfinition de la DataSource peut se faire par l'intermdiaire de la console d'administration Tomcat Au 01/02/2008 pas disponible avec Tomcat 6.
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

Ne pas oublier d'installer le pilote jdbc dans le rpertoire lib de tomcat

35

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

36

Dfinir Dfinir un un pool pool de de connexions connexions avec avec Tomcat Tomcat
Controleur Controleur (Servlet) (Servlet)
Serveur SGBD

L'application Notes
l'objet NotesDAO construit l'objet Histogramme
NotesDAO NotesDAO JDBC
revenons notre application 38 40
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

L'objet DataSource est cr par le conteneur web (par ex. le serveur Tomcat) partir des informations de configuration. Ce n'est pas le code applicatif qui instancie cet objet.
context.xml

Serveur Tomcat
org.apache.commons. dbcp.BasicDataSource
Histogramme Histogramme

<Context path="/HistogramMVC">

<Resource name="jdbc/Notes"
auth="Container" type="javax.sql.DataSource" maxActive="10" maxIdle="3" maxWait="10000" username="genoud" password="xxxxxxx" driverClassName="oracle.jdbc.OracleDriver" url="jdbc:oracle:thin:@hopper.e.ujf-grenoble.fr:1521:ufrima"/>

(JavaBean) (JavaBean)

Servlet Servlet
HistogramImager HistogramImager

index.html

</Context>

(Servlet) (Servlet)
Tableau.jsp Tableau.jsp

Comment le code applicatif accde-t-il l'objet DataSource gr par le serveur ?


import javax.naming.* import javax.sql.DataSource; DataSource dataSource = null; try { Context initialCtxt = new InitialContext(); dataSource = (DataSource) initialCtxt.lookup("java:comp/env/jdbc/Notes"); } catch (NamingException ne) { ... }
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010 Philippe GENOUD -Patrick REIGNIER - UJF

NotesDAO Histogramme

(JSP) (JSP)

Utilisation de l'API JNDI (Java Naming Directory Interface) dfinie dans le package javax.naming

37
Janvier 2010

La page index.html
notes?annee="2005"&matiere="bd" &presentation="graphic" web.xml
<web-app> <web-app> <display-name>Notes</display-name> <display-name>Notes</display-name>

Traitement d'une requte


Serveur Tomcat

<servlet> <servlet> <servlet-name>controleur</servlet-name> <servlet-name>controleur</servlet-name> <description> <description> Controleur de l'applications histogramme de notes Controleur de l'applications histogramme de notes </description> </description> <servlet-class>servlets.Controleur</servlet-class> <servlet-class>servlets.Controleur</servlet-class> </servlet> </servlet>
<servlet> <servlet> <servlet-name>graphic</servlet-name> <servlet-name>graphic</servlet-name> <description> <description> Affiche histogramme sous forme graphique Affiche histogramme sous forme graphique </description> </description> <servlet-class>servlets.view.HistogramImager</servlet-class> <servlet-class>servlets.view.HistogramImager</servlet-class> </servlet> </servlet>

Controleur

Histogram Imager

<servlet-mapping> <servlet-mapping> <servlet-name>controleur</servlet-name> <servlet-name>controleur</servlet-name> </servlet-mapping> </servlet-mapping>

<url-pattern>/notes</url-pattern> <url-pattern>/notes</url-pattern>

Le fichier de dploiement web.xml permet au serveur d'application de dterminer vers quel composant la requte doit tre adresse

notes?annee="2005"&matiere="bd"&presentation="graphic"
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

</web-app> </web-app>

39

Traitement d'une requte


notes?annee="2005"&matiere="bd" &presentation="graphic"
HttpResponse
"5002" "db"

Traitement d'une requte


notes?annee="2005"&matiere="bd" &presentation="graphic"
<html> <head> <title>Document sans titre</title> <meta http-equiv="Content-Type" content="text/html;> </head> <body>

HttpRequest

Serveur Tomcat

HttpRequest

Serveur Tomcat
HttpResponse
"5002" "db"

Cration d'un objet HttpRequest (request)


contient les informations relatives la requte

doGet( doGet(request, request, response) response) 1 Controleur Histogram Imager 2

Cration d'un objet HttpResponse (response)


permettra de construire et renvoyer une rponse au client

La servlet peut interroger l'objet HttpRequest pour rcuprer les paramtres de la requte
request.getParameter("prsentation")
Controleur

utiliser l'objet HttpResponse pour construire et envoyer un rponse au client qui a mis la requte
response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); ...
2'

Histogram Imager 2'

Envoi d'un message doGet(request,response) la servlet


pour tre plus exact : si la servlet n'a pas encore t invoque, chargement (instanciation) de la servlet cration d'un thread et excution dans ce thread de la mthode doPost du servlet

et/ou demander un autre composant de traiter la requte getServletContext().getRequestDispatcher("/histoGraphic") .forward(request, response);


Janvier 2010

Philippe GENOUD -Patrick REIGNIER - UJF

41

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

42

Contrleur
public class HistogramControleur extends HttpServlet { notes?annee="2005"&matiere="bd"
/** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //---------------------------------------------------------------------... //---------------------------------------------------------------------// Construction du modle //----------------------------------------------------------------------

Controleur : analyse analyse de de la la requte requte


notes?annee="2005"&matiere="bd" /** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //----------------------------------------------------------------------

parseInt peut lever une NumberFormatException obligation de la traiter

c'est une exception contrle

... //---------------------------------------------------------------------// Gnration de la prsentation //---------------------------------------------------------------------... }

int annee = 0 ; String matiere = null ; String presentation = null ;

... //---------------------------------------------------------------------// Rcupration des donnes (construction m.a.j. du modle) //---------------------------------------------------------------------... //---------------------------------------------------------------------// Gnration de la prsentation //----------------------------------------------------------------------

try { annee = Integer.parseInt(request.getParameter("annee")) ; matiere = request.getParameter("matiere") ; presentation = request.getParameter("presentation") ; } catch(NumberFormatException e) {

Que faire de cette exception ?


Et de manire plus gnrale que faire des exceptions dans le corps d'une servlet ?
}

... }
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010 Philippe GENOUD -Patrick REIGNIER - UJF

43
Janvier 2010

44

Controleur : analyse analyse de de la la requte requte


notes?annee="2005"&matiere="bd" /** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //---------------------------------------------------------------------... //---------------------------------------------------------------------// Construction du modle //---------------------------------------------------------------------//---------------------------------------------------------------------// Construction du modle //---------------------------------------------------------------------...

Controleur : analyse analyse de de la la requte requte


notes?annee="2005"&matiere="bd" /** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //---------------------------------------------------------------------...

parseInt peut lever une NumberFormatException obligation de la traiter


//---------------------------------------------------------------------// Gnration de la prsentation //---------------------------------------------------------------------... }

c'est une exception contrle

... //---------------------------------------------------------------------// Gnration de la prsentation //---------------------------------------------------------------------... }

int annee = 0 ; String matiere = null ; String presentation = null ;

int annee = 0 ; String matiere = null ; String presentation = null ;

cela ne dispense pas de refaire une vrification ct serveur ! par exemple au cas o l'url serait tape } directement

try { annee = Integer.parseInt(request.getParameter("annee")) ; matiere = request.getParameter("matiere") ; presentation = request.getParameter("presentation") ; } catch(NumberFormatException e) { // Normalement la vrification que l'anne est bien un nombre // devrait tre confie javascript ct client avec blocage de // l'envoi du formulaire si saisie incorrecte.

Renvoyer un code erreur

La scurit ne peut JAMAIS tre garantie ct client

try { annee = Integer.parseInt(request.getParameter("annee")) ; matiere = request.getParameter("matiere") ; presentation = request.getParameter("presentation") ; } catch(NumberFormatException e) { // Normalement la vrification que l'anne est bien un nombre // devrait tre confie javascript ct client avec blocage de // l'envoi du formulaire si saisie incorrecte. response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "L'anne demande n'est pas un nombre") ; return; }

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

45

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

46

Controleur : analyse analyse de de la la requte requte


notes?annee="2005"&matiere="bd" /** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //---------------------------------------------------------------------... //---------------------------------------------------------------------// Construction du modle //---------------------------------------------------------------------... //---------------------------------------------------------------------// Gnration de la prsentation //---------------------------------------------------------------------... }

Controleur : analyse analyse de de la la requte requte


notes?annee="2005"&matiere="bd" /** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //---------------------------------------------------------------------... //---------------------------------------------------------------------// Construction du modle //---------------------------------------------------------------------...

int annee = 0 ; String matiere = null ; String presentation = null ;


}

//---------------------------------------------------------------------// Gnration de la prsentation //---------------------------------------------------------------------...

int annee = 0 ; String matiere = null ; String presentation = null ; try { annee = Integer.parseInt(request.getParameter("annee")) ; matiere = request.getParameter("matiere") ; presentation = request.getParameter("presentation") ; } catch(NumberFormatException e) { // Normalement la vrification que l'anne est bien un nombre // devrait tre confie javascript ct client avec blocage de // l'envoi du formulaire si saisie incorrecte. response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "L'anne demande n'est pas un nombre") ;

Attention de ne pas oublier le return !!


return; }

try { annee = Integer.parseInt(request.getParameter("annee")) ; matiere = request.getParameter("matiere") ; presentation = request.getParameter("presentation") ; } catch(NumberFormatException e) { // Normalement la vrification que l'anne est bien un nombre // devrait tre confie javascript ct client avec blocage de // l'envoi du formulaire si saisie incorrecte. response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "L'anne demande n'est pas un nombre") ;

Renvoyer un code erreur

return; }

... if (presentation.equals("tableau"))
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

47

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

48

Controleur : analyse analyse de de la la requte requte


/** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //---------------------------------------------------------------------... //---------------------------------------------------------------------// Construction du modle //---------------------------------------------------------------------... //---------------------------------------------------------------------// Gnration de la prsentation //---------------------------------------------------------------------... } ... //---------------------------------------------------------------------// Construction du modle //---------------------------------------------------------------------... //---------------------------------------------------------------------// Gnration de la prsentation //---------------------------------------------------------------------...

Controleur : analyse analyse de de la la requte requte


notes?annee="2005"&matiere="bd" /** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //----------------------------------------------------------------------

int annee = 0 ; String matiere = null ; String presentation = null ;


}

int annee = 0 ; String matiere = null ; String presentation = null ;

Lancer une ServletException


return ;

try { annee = Integer.parseInt(request.getParameter("annee")) ; matiere = request.getParameter("matiere") ; presentation = request.getParameter("presentation") ; } catch(NumberFormatException e) { // Normalement la vrification que l'anne est bien un nombre // devrait tre confie javascript ct client avec blocage de // l'envoi du formulaire si saisie incorrecte. // MAIS cela ne dispense pas de refaire une vrification ct // serveur (par exemple au cas ou l'url serait tape directement) response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, demande n'est n'est pas unpas nombre") ; throw new "L'anne ServletException("Anne un nombre", e); return ;

Renvoyer une page approprie

try { annee = Integer.parseInt(request.getParameter("annee")) ; matiere = request.getParameter("matiere") ; presentation = request.getParameter("presentation") ; } catch(NumberFormatException e) { // Normalement la vrification que l'anne est bien un nombre // devrait tre confie javascript ct client avec blocage de // l'envoi du formulaire si saisie incorrecte. // MAIS cela ne dispense pas de refaire une vrification ct // serveur (par exemple au cas ou l'url serait tape directement) response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getServletContext().getRequestDispatcher( "L'anne demande n'est pas un nombre") ; "/formulaire.jsp").forward(request, response); }

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010 Philippe GENOUD -Patrick REIGNIER - UJF

49
Janvier 2010

50

Controleur Controleur :: retour retour au au formulaire formulaire


Anne doit tre un nombre
Retour au formulaire en indiquant la cause de l'chec

Controleur Controleur :: retour retour au au formulaire formulaire


Anne doit tre un nombre

formulaire.jsp
Rafficher la valeur du paramtre prcdent

notes?annee="200x"&matiere="bd"

/notes

<body> <form method="post" action="notes"> <p>Anne : <input type="text" name="annee" /> <font color="#FF0000"> (erreur != null) Le if message d'erreur si il est prsent out.println(erreur); %>
<JSP >

Ecriture lourde.

<% String erreur = (String) request.getAttribute("erreurAnnee"); Conteneur Web (Tomcat)


Message d'erreur Message d'erreur transmis avec la requte transmis avec la requte

<JSP >

HistogramControler
tableau.jsp formulaire.jsp HistogramImager.java

${requestScope.erreurAnnee} </font> </p> Simplifie par ... utilisation de EL ... <input type="submit" value="envoyer"/> (Expression Language </form>
Rafficher la valeur du paramtre prcdent

${requestScope.erreurAnnee}

introduit avec JSP 2.0)

protected void doPost(HttpServletRequest request, HttpServletResponse response) ... String erreurAnnee = "Anne doit tre un nombre";
Chane identifiant l'attribut Rfrence de l'objet valeur de l'attribut

protected void doPost(HttpServletRequest request, HttpServletResponse response)

request.setAttribute("erreurAnnee",erreurAnnee);
getServletContext().getRequestDispatcher( "/accueil.jsp").forward(request, response); Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

Transmission du message d'erreur en le plaant comme attribut dans la requte


...

<input type="text" name="annee" value=" "/> <% String annee = request.getParameter("annee"); if (annee != null) out.println(annee); %>

String erreurAnnee = "Anne doit tre un nombre"; request.setAttribute("erreurAnnee",erreurAnnee); getServletContext().getRequestDispatcher( "/accueil.jsp").forward(request, response);

${param.annee} ${param.annee}
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

EL 52

51

Controleur : construction construction du du modle modle


/** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //----------------------------------------------------------------------

connexion connexion la la BD BD
3me 3me solution solution :: pool pool de de connexions connexions
intialisation de la source de donnes au chargement du servlet contrleur
import javax.naming.* public class HistogramControleur extends HttpServlet { /** * la source de donnes qui permettra d'accder la base de donne * (c'est elle qui gre un pool de connexions, et qui fournira les * connexions aux diffrents objets en ayant l'usage). */ private DataSource dataSource;

Le contrleur demande un objet INotesDAO de lui fournir un histogramme de notes

Histogramme histoNotes = null ;

... //---------------------------------------------------------------------// Construction du modle //---------------------------------------------------------------------... //---------------------------------------------------------------------// Gnration de la prsentation //----------------------------------------------------------------------

try { INotesDAO notesDAO = OracleNotesDAO.getInstance(dataSource); notes = notesDAO.getHistogramme(annee,matiere) ;

} catch (DAOException e) { /** * A l'initialisation du servlet, cration d'un pool de connexions * qui servira fournir des connexions la base de donnes * utilise par les composants modle, et cration d'un objet INotesDAO * */ public void init() throws ServletException { try { Utilisation de l'API Context initialCtxt = new InitialContext(); JNDI DataSource dataSource = (DataSource) initialCtxt .lookup("java:comp/env/jdbc/Notes"); } catch (NamingException ne) { throw new ServletException( "problme lors de la crtion de la dataSource jdbc/Notes ", ne); }
Janvier 2010

... }

response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()) ; return; }

dataSource : rfrence vers la source de donnes dfinie dans les fichiers de configuration de l'application cette source donnes cr par le container (TomCat) et rcupre via l'API JDNI

Philippe GENOUD -Patrick REIGNIER - UJF

53

Philippe GENOUD -Patrick REIGNIER - UJF

Janvier 2010

54

Controleur : gnration gnration de de la la vue vue


/** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse if (presentation.equals("tableau")) { **/ public void doGet(HttpServletRequest request, HttpServletResponse // on redirige response) la rponse vers la page JSP de gnration throws IOException, ServletException { //---------------------------------------------------------------------// de la prsentation de type tableau // Analyse de la requte HTTP try { //---------------------------------------------------------------------getServletContext(). ... getRequestDispatcher("/tableau.jsp").forward(request, response); //---------------------------------------------------------------------} catch (Exception e) { // Construction du modle //---------------------------------------------------------------------response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ... "erreur la cration de la prsentation tableau\n" + //---------------------------------------------------------------------e.getMessage()) ; // Gnration de la prsentation return ; //---------------------------------------------------------------------} ... else } // creation de la prsentation histogramme // par la servlet Graphic (objet HistogramImager) try { getServletContext(). getRequestDispatcher("/graphic").forward(request, response); } catch (Exception e) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "erreur la cration de la prsentation graphique\n" + e.getMessage()) ; return ; /** * Rponse une requte de type <CODE>get</CODE> * @param request donnes associes la requte HTTP * @param response donnes associes la rponse **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //---------------------------------------------------------------------// Analyse de la requte HTTP //----------------------------------------------------------------------

Controleur : construction construction du du modle modle


et et transmission transmission aux aux vues vues
HistogramModel notes = null ;

...

try { //---------------------------------------------------------------------notes = notesDAO.getHistogramme(annee,matiere) ; // Construction du modle //---------------------------------------------------------------------} catch (SQLException e) {


... //---------------------------------------------------------------------// Gnration de la prsentation //---------------------------------------------------------------------... }

response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()) ;

return; } Chane identifiant l'attribut Rfrence de l'objet

Transmission de l'objet modle en le plaant comme attribut dans la requte request.setAttribute("histoNotes", notes);
Dans la page JSP tableau.jsp <%@ <%@ page page import="model.HistogramModel" import="model.HistogramModel" %> %> <jsp:useBean <jsp:useBean id="histoNotes" id="histoNotes" class="model.HistogramModel" class="model.HistogramModel" scope="request"/> scope="request"/> ... ... <%=histoNotes.getMatiere()%> <%=histoNotes.getMatiere()%> ${requestScope.histoNotes.matiere} ${requestScope.histoNotes.matiere} EL Dans la servlet HistogramImager HistogramModel HistogramModel notes notes == (HistogramModel) (HistogramModel) request.getAttribute("histoNotes"); request.getAttribute("histoNotes");
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

La page JSP (tableau.jsp) ou la servlet (HistogramImager) vont exploiter l'objet histoNotes (Histogramme) cr prcdemment Comment l'objet Contrleur leur transmet cet objet ?
56
Philippe GENOUD -Patrick REIGNIER - UJF Janvier 2010

55

You might also like