Beruflich Dokumente
Kultur Dokumente
Application Web
Une application Web rpartie sur trois couches (three-tier Web application) est compose e e selon larchitecture suivante : Client mince : ralis par un fureteur Web, le client mince est linterface utilisateur e e (GUI) qui soccupe de la prsentation et la saisie des donnes. Aucun traitement des e e donnes nest fait dans cette couche. e Serveur application : soccupe de traiter les requtes provenant du client a travers le e ` rseau et sert dinterface avec la base de donnes. La logique de contrle de lapplication e e o rside dans cette couche. e Serveur BD : normalement situ sur une machine dirente au serveur application, e e le serveur BD soccupe du stockage et de la gestion des donnes. La base de donnes e e (Oracle, MySQL, PostgreSQL) rside dans cette couche et communique au serveur e application ` travers le rseau. a e Puisque le serveur BD (disjkstra.logti.etsmtl.ca) contient dj` une base de donnes ea e cre au premier laboratoire, et comme plusieurs fureteurs Web sont disponibles, votre traee vail consistera essentiellement a implmenter le serveur application. La technologie qui sera ` e utilise pour ce serveur est celle des Servlets Java. e
Servlets Java
Un servlet est une application Java qui permet de crer dynamiquement des donnes e e au sein dun serveur HTTP. Ces donnes sont le plus souvent prsentes sous le format e e e HTML, mais elles peuvent galement ltre en format XML ou tout autre format destin e e e aux fureteurs Web. Tel quillustr a la Figure 1, le processus dinvocation dun servlet, dans e` une application ` trois couches, comporte 7 tapes : a e 1. Le fureteur se connecte a ladresse du site Web de lapplication et lui envoie une requte ` e HTTP GET demandant de produire une page HTTP associe a cette adresse. e ` 2. Le serveur Web (ex : Tomcat) retourne au fureteur une page HTML comportant une saisie de donnes (FORM HTML). Cette page Web prcise que les param`tres entrs e e e e par lutilisateur seront traites par un servlet. e 3. Lutilisateur entre linformation requise par la page Web qui est ensuite envoye par le e fureteur au serveur Web sous la forme dune requte HTTP POST. e 1
4. Le serveur Web dl`gue la requte au conteneur de servlet qui... ee e 5. ...dmarre un l du servlet correspondant. e 6. Le servlet dcode les param`tres provenant du client, tablit une connexion au serveur e e e BD et traite la requte a laide des donnes de la BD. e ` e 7. Le servlet produit une rponse a la requte sous la forme dune page HTML qui est e ` e retourne au client. e
Fig. 1 Invocation dun servlet Java ( c Robert Godin) Pour dvelopper une servlet HTTP, il faut crer une classe Java spcialisant la classe e e e javax.servlet.http.HttpServlet et rednir les mthodes doGet et doPost de la classe e e HttpServlet. Ces mthodes, produisant toutes les deux une page HTML en rponse a une e e ` requte HTTP, di`rent par la mani`re avec laquelle les param`tres sont transmis au serveur. e e e e Ainsi, dans la mthode doGet, les param`tres sont envoys directement dans lURL, sans e e e encryption. Cette mthode est souvent utilise pour demander une information au serveur. e e En revanche, la mthode doPost ins`re les param`tres de faon encrypte dans le corps de e e e c e la requte, et est utilise pour mettre a jour linformation du serveur. Dans le cadre de ce e e ` laboratoire, nous ne ferons pas la distinction entre ces deux types de requte et aurons une e mme implmentation pour les mthodes doGet et doPost. e e e
Exemple de servlet
Voici un exemple de servlet Java pour obtenir la liste des lms dont le titre renferme une certaine cha de caract`res : ne e
// Classe Java: ServletWebflix.java package webflix; import import import import import import import import java.io.IOException; java.io.OutputStreamWriter; java.io.PrintWriter; java.io.StringWriter; java.sql.Connection; javax.servlet.*; oracle.jdbc.pool.*; javax.naming.Context;
import javax.naming.InitialContext; public class ServletWebflix extends HttpServlet { // Initialisation du parent public void init(ServletConfig config) throws ServletException { super.init(config); } // Methode doGet: on utilise limplementation de doPost public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } // Traitement de la requete: // On recoit une chaine de charactere et on retourne un page HTML // contenant le titre des films de la BD contenant cette chaine // dans leur titre. public void doPost(HttpServletRequest requete, HttpServletResponse reponse) throws ServletException, IOException { // Specifier le type et lencodage des donnees reponse.setContentType("text/html"); reponse.setCharacterEncoding("utf-8"); // Creer un PrintWriter pour imprimer la page Web de la reponse OutputStreamWriter osw = new OutputStreamWriter(reponse.getOutputStream()); PrintWriter out = new PrintWriter(osw); // Entete de la page out.println("<html>"); out.println("<head><title>Reponse du Servlet Webflix</title></head>"); out.println("<body>"); String chaineRecherche = ""; Connection conn = null; PreparedStatement ps = null; try { // Recuperer le parametre provenant de la page HTML dentree chaineRecherche = requete.getParameter("chaineRecherche"); if (chaineRecherche != null) { // Ouvrir une connexion en passant par un DataSource Context initContext = new InitialContext(); Context envContext = (Context) initContext.lookup("java:/comp/env"); OracleDataSource ds = (OracleDataSource) envContext.lookup("jdbc/webflix"); conn = ds.getConnection(); // Creer une requete au serveur BD ps = conn.prepareStatement(
"SELECT * " + "FROM Film " + "WHERE titre like ?"); ps.setString(1,"%" + chaineRecherche + "%"); // Decoder les resultats ResultSet rs = ps.executeQuery(); while (rs.next()) out.println(rs.getString("titre") + " (" + rs.getInt("annee") + ")<br>"); } } catch (Exception e) { // Debug: afficher la trace derreur directement dans la page StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); out.println("<p>" + sw.string() + "</p>"); } finally{ try{ // Liberer les connections et resources out.println("</body></html>"); out.close(); ps.close(); conn.close(); } catch(Exception lException){ lException.printStackTrace(); } } } }
Tel quillustr dans cet exemple, le traitement dune requte par un servlet, dans la e e mthode doPost comporte plusieurs tapes : e e 1. Congurer le type et lencodage des donnes de la rponse. Dans notre cas, les donnes e e e sont de type HTML et lencodage utilis est celui de la base de donnes (UTF-8). e e 2. Crer un PrintWriter an dimprimer la page HTML de la rponse. e e 3. Rcuprer les param`tres de la requte a laide de la fonction getParameter. e e e e ` 4. Crer une connexion ` la base donnes. Lors du laboratoire 1, les param`tres de la e a e e connexion (URL, ID et mot de passe pour la BD) taient entrs directement dans le e e code Java. Cette approche comporte plusieurs probl`mes, principalement au niveau de e la scurit et de la exibilit. Ainsi, si ladresse du serveur BD ou lID/mot de passe du e e e compte de la BD change, il faut modier et redployer le servlet. Dans ce laboratoire, e nous utiliserons une meilleure approche base sur les DataSource. Cette approche sera e explique plus en dtails dans lnonc. e e e e 5. Une fois la connexion a la BD tablit, utiliser un ou plusieurs PreparedStatement ` e pour faire une requte ou mettre ` jour les donnes de la BD. e a e 4
6. Imprimer sous la forme dune page HTML la rponse a la requte du client ` laide du e ` e a PrintWriter. 7. Dans tous les cas, librer les resources en fermant le PrintWriter, le PreparedStatement e ainsi que la connexion ` la BD. a Pour saisir et envoyer les donnes au servlet, il est ncessaire davoir une page HTML e e faisant rfrence au servlet : ee
<!-- Page HTML FormWebflixServlet.html --> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Recherche de films dans la BD Webflix</title> </head> <body> <form action = "servlet-webflix" method = "post"> <p>Entrer une cha^ne de caract`res contenue dans le titre du film</p> e <table> <tr> <td>Cha^ne de recherche: </td> <td><input type = "text" name = "chaineRecherche" /></td> </tr> </table> <input type = "submit" value = "Soumettre" /> </form> </body> </html>
` A noter les lments action="servlet-webflix" et method="post" de la balise form. ee Le premier indique que le servlet qui recevra les donnes est situ ` lURL (virtuelle) : e ea
<adresse application Web>/servlet-webflix.
Nous verrons plus loin comment associer cette adresse virtuelle avec une classe Java (ex : ServletWebflix.class). Le second lment spcie que la requte sera envoye par un POST ee e e e HTTP et que la mthode doPost du servlet sera appele. e e
</head> <body> <form action = "somme1" method = "post"> <table> <tr> <td>Entrer un premier nombre: </td> <td><input type = "text" name = "premierNombre" /></td> </tr> </table> <input type = "submit" value = "Soumettre" /> </form> </body> </html>
Ensuite, dans le premier servlet, il faut rcuprer le param`tre envoy par cette page, le e e e e sauver dans un HttpSession, et imprimer dans la rponse une page Web demander e
// Classe Java: SommeServlet1.java ... public void doPost(HttpServletRequest requete, HttpServletResponse reponse) throws ServletException, IOException { ... // Creer une session HttpSession session = requete.getSession(true); try { // Recuperer le premier nombre String premierNombre = requete.getParameter("premierNombre"); // Sauver le premier parametre dans la session session.setAttribute("premierNombre", premierNombre); // Afficher la seconde page out.println("<html>"); out.println("<head><title>Somme de deux nombres (2)</title></head>"); out.println("<body>"); out.println("<form action = \"somme2\" method = \"post\">"); out.println("<table><tr>"); out.println("<td>Entrer un deuxi`me nombre: </td>"); e out.println("<td><input type = \"text\" name = \"deuxiemeNombre\" /></td>"); out.println("</tr></table>"); out.println("<input type = \"submit\" value = \"Soumettre\" />"); out.println("</form></body></html>"); } ... }
Puisque que la session est cre dans ce servlet, il faut donner le valeur true au param`tre ee e de la mthode getSession. Lorsque lon veut rcuprer une session dj` cre, on emploie e e e e a ee plutt la valeur false. Ensuite, il faut crer un second servlet qui va rcuprer les deux o e e e nombre et produire une page HTML donnant leur somme :
// Classe Java: SommeServlet2.java ...
public void doPost(HttpServletRequest requete, HttpServletResponse reponse) throws ServletException, IOException { ... // Creer une session HttpSession session = requete.getSession(false); try { // Recuperer le premier nombre String premierNombre = session.getAttribute("premierNombre"); // Recuperer le second nombre String deuxiemeNombre = requete.getParameter("deuxiemeNombre"); // Afficher la page contenant la somme out.println("<html>"); out.println("<head><title>Somme de deux nombres (3)</title></head>"); out.println("<body>"); out.println("<p>La somme des deux nombres est: </p>"); out.println(Integer.parseInt(premierNombre) + Integer.parseInt(deuxiemeNombre)); out.println("</body></html>"); } ... }
<mon app>/WEB-INF/web.xml : Dcrit les servlets de lapplication, leur association avec une e URL virtuelle, leurs param`tres, ainsi que les ressources utie lises par ces servlets. Par exemple. cest dans ce chier e que la classe Java ServletWebflix.class est associe avec e lURL virtuelle servlet-webflix rfrence dans le chier ee e FormWebflixServlet.html. <mon app>/WEB-INF/classes/ : Contient tous les classes Java (chiers .class) requis par lapplication, incluant ` la fois les classes a ` des servlets et celles utilises par ces servlets. A noe ter que lemplacement des classes doit respecter la position de la classe dans son paquetage Java. Par exemple, comme la classe ServletWebflix.java renferme la ligne package webflix ;, le chier ServletWebflix.class doit se trouver dans le sous-rpertoire e <mon app>/WEB-INF/classes/webflix/.
: Contient toutes les libraires JAR requises par votre applica` tion. A noter que certaines JAR, comme celles renfermant les pilotes JDBC se trouvent dj` dans un rpertoire partag les ea e e rendant disponibles ` toutes les applications Web dans Toma cat. e <mon app>/META-INF/context.xml : Dnit les resources disponibles dans le contexte de lapplication Web. Cest dans ce chier que lon dnit les param`tres e e de la connexion JDBC ` la BD Oracle. a <mon app>/WEB-INF/lib/
La description du dploiement de lapplication se fait dans le chier web.xml situ dans e e le rpertoire <mon app>/WEB-INF. Pour chacun des servlets de lapplication ce chier doit e avoir une balise
<servlet> <servlet-name> nom_servlet </servlet-name> <servlet-class> classe_servlet </servlet-class> </servlet>
Ici, nom servlet est un identiant choisit pour le servlet, classe servlet est la classe du servlet correspondant, incluant le prxe du paquetage Java, et url servlet est lURL e virtuelle associe au servlet, soit url serveur tomcat/url servlet. Par ailleurs, ce chier e peut galement dnir certaines ressources utilises par lapplication, avec une balise : e e e
<resource-ref> <description> texte_descriptif </description> <res-ref-name> nom_ressource </res-ref-name> <res-type> classe_ressource </res-type> <res-auth>Container</res-auth> </resource-ref>
<extension>html</extension> <mime-type>text/html</mime-type> </mime-mapping> <mime-mapping> <extension>txt</extension> <mime-type>text/plain</mime-type> </mime-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> <welcome-file>index.html</welcome-file> </welcome-file-list> <resource-ref> <description>JDBC connexion datasource</description> <res-ref-name>jdbc/webflix</res-ref-name> <res-type>oracle.jdbc.pool.OracleDataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app>
La ressource dcrite dans cet exemple est une data source Oracle permettant de se connece ter a la BD Webix. Les param`tres de cette ressource doivent tre dnis dans le chier ` e e e context.xml :
<?xml version=1.0 encoding=utf-8?> <Context reloadable="true"> <Resource name="jdbc/webflix" auth="Container" type="oracle.jdbc.pool.OracleDataSource" factory="oracle.jdbc.pool.OracleDataSourceFactory" maxActive="30" maxIdle="2" maxWait="1000" user="nomLogin" password="motDePasseLogin" driverClassName="oracle.jdbc.driver.OracleDriver" url="jdbc:oracle:thin:@dijkstra.logti.etsmtl.ca:1521:log660" /> </Context>
Evidemment, les valeurs des param`tres user et password doivent correspondre ` ceux e a utiliss pour se connecter a la BD. e `
Rfrences ee
Documentation Tomcat6 : http://tomcat.apache.org/tomcat-6.0-doc/index.html