Java Edition Entreprise Introduction de qq Bases sur Programmation Web Les composants d’une application web Pages Web dynamique Une page html pourrait être générée dynamiquement par un script côté serveur, Les langages et les serveurs utilisés sont diverses, La technologie des servlets Java et page JSP fonctionnant avec différents serveurs (Tomcat, Apache,..) et sur différentes plateformes (Windows, Linux), Une page html peut également contenir des scripts qui seront exécutés par le navigateur, Les langages de script côté navigateur sont nombreux PerlScript, JavaScript,.. JavaScript côté navigateur <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page affichant l heure</title> <script language="javascript"> function réagir(){ alert ("vous avez cliqué sur le bouton ok"); } </script> </head> <body> <form action="index.jsp" method="get"> <input type="submit" value="ok" onclick="réagir()"> </form> ….. </body> </html> Un script JSP <%@ page import="java.util.*" %> <% // code java%> <% Calendar calendrier = Calendar.getInstance(); int mn= calendrier.get(Calendar.MINUTE); int h = calendrier.get(Calendar.HOUR_OF_DAY); int s = calendrier.get(Calendar.SECOND); %> <% // code html %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page affichant l heure</title> </head> <body> <h1>Il est <%=h%>:<%=mn%>:<%=s%></h1> </body> </html> Java Framework La plateforme Java est composée de trois éditions, destinées à des usages différents : Java ME : Java Micro Edition est prévu pour le développement d'applications embarquées, notamment sur des terminaux mobiles ; Java SE : anciennement Java 2 Standard Edition est destiné au développement d'applications pour ordinateurs personnels, poste de travail (Application clasique) ; Java EE : Java Enterprise Edition, destiné à des applications entreprises en fournissant un ensemble de composants sous forme d’API. Chaque édition propose un environnement complet pour le développement et l'exécution d'applications basées sur Java et comprend notamment une machine virtuelle Java (Java virtual machine) ainsi qu'un ensemble de classes. Java EE (Java Enterprise Edition) est une norme proposée par la société Sun, portée par un consortium de sociétés internationales, visant à définir un standard de développement d'applications d'entreprises multi-niveaux, basées sur des composants. On parle généralement de la plateforme JEE pour désigner les services offerts (API), les composants et l’infrastructure d’exécution. La plateforme JEE La plateforme JEE comprend: Les spécifications du serveur d'application, c'est-à-dire de l'environnement d'exécution: J2EE définit finement les rôles et les interfaces pour les applications ainsi que l'environnement dans lequel elles seront exécutées. Ces recommandations permettent ainsi à des entreprises tierces de développer des serveurs d'application conformes aux spécifications ainsi définies, sans avoir à redévelopper les principaux services. Les service, c'est-à-dire des extensions Java indépendantes permettant d'offrir en standard un certain nombre de fonctionnalités. Ils pouvent être classés par catégories : Les services d'infrastructures : JDBC,JNDI… Les services de communication : JavaMail,JAAS… Les composants, on distingue habituellement deux familles de composants : Les composants web : Servlet et JSP. Les composants métier : EJB (Enterprise Java Beans). Il s'agit de composants spécifiques chargés des traitements des données propres à un secteur d'activité (on parle de logique métier ou de logique applicative) et de l'interfaçage avec les bases de données. Architecture Java EE Architecture Java EE Typiquement c’est une architecture 3-tiers: Tiers présentation: affichage des données Tiers métier: gestion du métier de l’application Tiers donnée: persistance des données Permet une séparation claire entre: L’interface homme-machine Les traitements métiers Les données Basée sur des composants qui sont distincts, interchangeables et distribués: il est simple d'étendre l'architecture ; la maintenabilité des applications est facilitée. API Servlet un des composants de base pour le développement d'applications Web; Peut servir à créer dynamiquement des pages HTML; Bien sûr d’autres solutions existent pour les pages web dynamiques; Les servlets* peuvent servir à d’autres usages; Ecrite sur le langage Java, elle a tous les avantages du langage: Portabilité, l’accès aux APIs Java dont le JDBC… API Servlet Un programme java qui s'exécute côté serveur: la portabilité, l'accès à toutes les API de java dont JDBC pour l'accès aux bases de données, ... Elle permet de recevoir des requêtes HTTP via un serveur web, de les traiter et d’y répondre, selon le modèle requête/réponse. Autorise avec d’autres API compatibles l’accès aux bases de données. Elle fait partie des première API fondatrice de JEE. Elle a deux extensions principales: JSP (Java Server Pages) et JSTL (Java Server Tag Libraries). Une servlet peut être invoquée plusieurs fois en même temps pour répondre à plusieurs requêtes simultanées. La servlet se positionne dans une architecture Client/Serveur 3-tiers dans le tiers du milieu entre le client léger chargé de l'affichage et la source de données. La version actuelle de la spécification servlet est 4.0. API Servlet Une servlet a un cycle de vie différent de celui d’un objet classique. Elle n’est pas instanciée explicitement mais plutôt dès l’allumage du serveur, ou à la réception de la première requête. Une fois créée, elle n’est pas détruite, et reste disponible pour traiter les requêtes suivantes. Une servlet a donc une forme de persistance dans le temps. Son cycle de vie et cette forme de persistance est entièrement géré par un container (conteneur). C’est un composant logiciel système qui est capable de prendre en charge plusieurs servlets, les intancier, les initialiser en leur passant éventuellement des paramètres, les associer à des URL précises et leur transmettre les requêtes entrantes,etc. il permet également de gérer le Multithreading. API Servlet Serveur d’application: Un serveur d'application est une extension du serveur web qui a ses limites: Pas de contenu dynamique, Pas de sauvegarde de données sur le serveur Un serveur d’application est un serveur web + des containers. Notion de moduleWeb: Un servlet ne peut pas être déployé directement dans un conteneur, il doit faire partie d’un moduleWeb Un module Web est un ensemble de librairies, de fichiers de configurations, de code Java (bytecode des servlets…), … Le moduleWeb est l’unité de déploiement dans le conteneur Quelques Concepts Requête: la requête HTTP provient d'un client et porte avec elle des paramètres. Ces paramètres peuvent être techniques (les paramètres standard HTTP se trouvant dans l’entête), ou applicatifs, comme le contenu d'un formulaire. Réponse: la réponse provient du serveur, peut être une page HTML, dynamique ou non, une image, ou bien un code d'erreur HTTP, accompagné d'un message. Session: le protocole HTTP est sans mémoire. Pour garder une traçabilité entre les requêtes du client, utilisation des cookies (un petit fichier texte côté serveur avec des informations). Un cookie peut être accepté ou refusé. L'API Servlet définit un cookie : JSESSIONID, ce qui lui permet de définir la notion de session. Une session est simplement un objet côté serveur modélisant un ensemble de cycles requêtes / réponses avec un utilisateur donné. Une session est reconnue grâce à un cookie nommé JSESSIONID. Application web: un ensemble de pages web JSP JSF HTML …,d’images, de servlets, gérés par un serveur web. Elle estassociée à un point de montage dans une URL, qui est le préfixe de toutes les URL des composants qu’elle gère. Elle est portable. Contexte d'exécution Le standard des Servlet définit trois contextes d'exécution ou une portée des objets : La requête : la portée est la requête uniquement. La session : la portée est un ensemble de requêtes successives en provenance d'un même client. L'application : enfin la portée est toute l’ application web. Ces trois contextes sont gérés par les mêmes méthodes setAttribute(String, Object), getAttribute(String) et getAttributeNames(). Ces méthodes permettent d'attacher des objets Java quelconques à ces contextes, et de les récupérer. En fonction de la durée de vie de ces objets (une requête, une session ou toute l'application), on choisira le bon contexte pour sauvegarder les informations dont on a besoin. On notera cependant que l'entretien du contexte session peut être coûteux, notamment en mémoire. Certaines applications choisissent d'ailleurs de ne pas l'utiliser, pour des raisons de perfomance. D'une façon générale, on évitera de stocker trop d'information dans ce contexte. Le fonctionnement d’une servlet Le cycle de vie est géré par le container. Le chargement et l'instanciation d'une servlet se font selon le paramétrage soit au lancement du serveur soit à la première invocation de la servlet. Dès l'instanciation, la servlet est initialisée une seule et unique fois avant de pouvoir répondre aux requêtes. La servlet est associée à un mapping URL qui la désigne dans un navigateur. Si c'est la première sollicitation de la servlet, le serveur l'instancie. Les servlets sont stockées (sous forme de fichier .class) dans un répertoire particulier du serveur. Ce répertoire dépend du serveur d'application utilisé. La servlet reste en mémoire jusqu'à l'arrêt du serveur. La servlet en mémoire, peut être appelée par plusieurs threads lancés par le serveur pour chaque requête. Ce principe de fonctionnement évite d'instancier un objet de type servlet à chaque requête et permet de maintenir un ensemble de ressources actives. Dès la réception de la requête, le serveur créé un objet qui représente la requête httpServletRequest et objet qui modélise la réponse httpServletResponse et les envoie à la servlet. la servlet créé ensuite dynamiquement la réponse sous forme de page html transmise via un flux PrintWriter. Présentation générale de l'API Servlet L'API Servlet se répartit en deux packages : javax.servlet et javax.http.servlet (contient ce qui est propre aux servlets destinées à fonctionner sur le web). Servlet, GenericServlet, HttpServlet Modélise la servlet proporement dite ServletRequest et HttpServletRequest modèlisent la requête. ServletResponse et HttpServletResponse modèlisent la réponse. ServletContext modèlise l'application web. HttpSession modèlise une session HTTP. ServletConfig modèlise l'ensemble de la configuration d'une servlet, entre autres ses paramètres d'initialisation. RequestDispatcher permet de rediriger une requête vers une ressource, en général statique. Notion de Servlet Interface centrale: init(ServletConfig), destroy() service(ServletRequest req, ServletResponse res), getServletConfig(), getServletInfo() une servlet est alors La classe GenericServlet précise les choses: Des servlets pour le web Des méthodes pour chaque requête HTTP qui existe : doDelete(), doGet(), doHead(), doOption(), doPost(), doPut(), doGet() doTrace() et doLastModified() Servlet HTTP Pour programmer une servlet, il faut donc étendre la classe HTTPServlet, et fournir une implémentation qui convient à toute ou partie des méthodes doX. API Servlet Requêtes et Réponses HTTP Entêtes d’une requête GET public class ShowRequestHeaders extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { //... Méthode de type HttpServletRequest getHeaderNames(), getHeader(String name) out.println(doctype + "<html>\n<head><title>" + title + "</title></head>\n" + "<body>\n<h1>" + title + "</h1>\n" + "<b>Request Method: </b>" + request.getMethod() + "<br />\n" + "<b>Request URI: </b>" + request.getRequestURI() + "<br />\n" + "<b>Request Protocol: </b>" + request.getProtocol() + "<br />) out.println("<table>\n" +"<tr><th>Header Name</th><th>Header Value</th></tr>"); Enumeration<String> headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); out.println("<tr><td>" + headerName + "</td>"); out.println("<td>" + request.getHeader(headerName) +"</td></tr>"); } out.println("</table>\n</body></html>"); out.close(); } } Entêtes d’une requête GET (2) changer Paramètres de formulaires public class ParametresFormulaire extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse reponse) throws IOException, ServletException{ … out.println(doctype+ "<html><head><title>"+title+"</title><head>"+ "<body>"); Enumeration<?> paramètres = request.getParameterNames(); if(!paramètres.hasMoreElements()) out.println("il n'existe pas de paramètre dans la requête du client" +"</body>+</html>"); else{ out.println(request.getQueryString()+ "<br><table border=\"0\"><tr><th>Paramètre</th><th>Valeur</th></tr>"); while(paramètres.hasMoreElements()){ String param = (String) paramètres.nextElement(); out.println("<tr><td>"+param+"</td>"); String[] paramValues = request.getParameterValues(param); for(int i=0; i<paramValues.length ; i++){ out.println("<td>"+ paramValues[i]+ ";"+"</td>"); } out.println("</tr>"); } out.println("</table>"); } out.println("</body></html>"); out.close(); } Vérification de données manquantes Champ manquant dans le formulaire • getParameter retourne null Champ renvoyé vide • getParameter retourne une chaine vide (ou une chaine avec des espacements) String param = request.getParameter("someName"); if ((param == null) || (param.trim().equals(""))) { doSomethingForMissingValues(...); } else { doSomethingWithParameter(param); } Réponse HTTP (rappel) Une réponse HTTP peut contenir du HTML HTTP rajoute des (meta)informations en entête du contenu de la réponse Les méthodes pour les Status Codes response.setStatus(int statusCode) – Utiliser les constantes, pas d’entiers directement – Noms dérivés du message standard • Ex : SC_OK, SC_NOT_FOUND, etc • response.sendError(int code, String msg) – Englobe le message dans un petit document HTML • response.sendRedirect(String url) – Le code de status est alors 301 – L’attribut « Location » est également généré dans l’entête de la réponse Exemple sendError public class LogServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { String login = request.getParameter("param1") ; String password = request.getParameter("param2") ; if ((login == null) || (login.trim().equals(""))) { response.sendError(HttpServletResponse.SC_NOT_FOUND,“champs login vide"); return; } if (checkUserAndPassword(login, password)) { grantAccessTo(login); } else { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, “accès refuser au compte" + login); } } } Ou bien Générer un fichier Excel public class FichierExcel extends HttpServlet { public void doGet(HttpServletRequest requete, HttpServletResponse reponse) throws IOException,ServletException{ reponse.setContentType("application/vnd.ms-excel"); PrintWriter out = reponse.getWriter(); out.println("\tQ1\tQ2\tQ3\tQ4\tTotal"); out.println("Apples\t78\t87\t92\t29\t=SOMME(B2:E2)"); out.println("Oranges\t77\t86\t93\t30\t=SOMME(B3:E3)"); } } Upload de fichiers (avec Commons FileUpload ) Formulaire HTML – <input type="file" name="nameFile" /> – <form method="post" enctype="multipart/form-data" action="/servlet"> – Le choix du enctype impacte les autres champs du formulaire • request.getParameter("name") ne fonctionne plus Côté Servlet – utiliser une librairie Commons FileUpload du projet Jakarta (http://commons.apache.org/fileupload/) Développement – import org.apache. tomcat.util.http.fileupload.* – import org.apache. tomcat.util.http.fileupload.servlet.* Déploiement – Dans le module Web de l’application… – …dans le répertoire WEB-INF/lib • commons-fileupload-1.2.1.jar • commons-io-1.4.jar Exemple : Upload simple (½) //Télécharger un fichier txt et l’afficher dans la réponse de la servlet if ( ServletFileUpload.isMultipartContent(request) ) { // create a factory for disk-based (large) file items FileItemFactory varr = new DiskFileItemFactory() ; ((DiskFileItemFactory) fileItemFactory).setSizeThreshold(40960); //the unit is bytes // create a new file upload handler ServletFileUpload var = new ServletFileUpload(varr); servletFileUpload.setSizeMax(81920); // the unit is bytes Exemple : Upload simple (2/2) try { List<?> fileItemsList = var.parseRequest(request); // Process file items Iterator<?> it = fileItemsList.iterator(); while (it.hasNext()){ DiskFileItem fileItem = (DiskFileItem)it.next(); if (fileItem.isFormField()){ // classic form field (name=value) out.println("<b>Champs:</b><br />\n" + fileItem.getFieldName() +"=" + fileItem.getString()+ "<br/>"); } else{ // uploaded file out.println("<b>Fichier:</b><br />\n<pre>" + fileItem.getString() + "</pre><br/>"); } } } catch (FileUploadException e) { out.println("Impossible de télécharger ce fichier"); e.printStackTrace();}}