Java intensif Programmation Web Serge Rosmorduc 2013-2014 Serge Rosmorduc Java intensifProgrammation Web 2013-2014 1 / 29 Plan Rappel : L’architecture web : client, serveur, serveur applicatif ; Une application java ; notion de servlet ; limites des servlets ; notion de jsp ; expression language ; beans request ; combinaison jsp/servlets, forwarding ; architecture du traitement d’un formulaire (détaillé) ; Serge Rosmorduc Java intensifProgrammation Web 2013-2014 2 / 29 Rappels sur l’architecture Web Pour HTML, formulaires... voir supports du cours NFA016 sur deptinfo. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 3 / 29 L’écosystème J2EE Serveurs applicatifs à géométrie variable ; nombreux modules. Couche web : Servlets/JSP ; Wicket, JSF ; + annuaire de services (JNDI) ; + gestion de transactions (JTA) ; gestion de persistence (JTA) ; + load balancing... serveurs simples : Tomcat, Jetty... serveurs complets : JBoss, Glassfish... EJB3 vs. Spring : convergence des approches Ce cours : on reste simple, Servlets, JSP, un peu d’archi. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 4 / 29 Organisation d’une application Web Serge Rosmorduc Java intensifProgrammation Web 2013-2014 5 / 29 Organisation d’une application Web L’application est typiquement compressée dans un fichier .war la racine de l’application contient : des resources directement accessibles (pages web, images, jsp) ; un dossier nommé WEB-INF qui contient : I I I I un fichier de configuration web.xml ; un dossier classes contenant des classes java (.class) ; un dossier lib contenant des bibliothèques java (.jar) ; ... WEB-INF n’est pas visible depuis l’extérieur : on y range souvent des ressources qu’on veut cacher. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 6 / 29 Remarque sur Netbeans Serge Rosmorduc Java intensifProgrammation Web 2013-2014 7 / 29 Rappel sur la méthode GET Les données sont passées dans l’URL : http://www.google.com/search?q=cnam&sourceid=chrome protocole et serveur http://www.google.com page : search variable(s) : I I q qui vaut cnam ; sourceid qui vaut chrome . Une requête en mode get est simple à construire sur un navigateur web. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 8 / 29 Rappel sur la méthode POST Autre système : les données de la requête sont envoyées dans le corps de la requête http. elles ne sont pas visibles. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 9 / 29 Notion de Servlet classe java qui étend HttpServlet ; associée à une URL ; fournit deux méthodes : doGet() et doPost() ; ces méthodes sont supposées récupérer les requêtes et y répondre. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 10 / 29 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 Hello World en Servlet @WebServlet ( name = ” H e l l o S e r v l e t ” , u r l P a t t e r n s = { ” / h e l l o ” } ) public class H e l l o S e r v l e t extends H t t p S e r v l e t { protected void doGet ( H t t p S e r v l e t R e q u e s t request , HttpServletResponse response ) throws S e r v l e t E x c e p t i o n , IOException { response . setContentType ( ” t e x t / h t m l ; c h a r s e t =UTF−8” ) ; P r i n t W r i t e r o u t = response . g e t W r i t e r ( ) ; try { o u t . p r i n t l n ( ” <!DOCTYPE html>” ) ; o u t . p r i n t l n ( ”<html>” ) ; o u t . p r i n t l n ( ”<body>” ) ; o u t . p r i n t l n ( ” Bonjour ” + r e q u e s t . getParameter ( ”nom” ) ) ; o u t . p r i n t l n ( ” </body>” ) ; o u t . p r i n t l n ( ” </ html>” ) ; } finally { out . close ( ) ; } } } Serge Rosmorduc Java intensifProgrammation Web 2013-2014 11 / 29 Servlets Annotation : @WebServlet(name = "HelloServlet", urlPatterns = "/hello") Dis que la servlet est associée à l’URL /hello objet request : représente la requête. Permet de récupérer les données de formulaire ; méthodes utiles : I I String getParameter(String) : retourne la valeur d’un paramètre String[] getParameterValues(String) : retourne les valeurs d’un paramètre (pour les listes, etc...) objet réponse : ici, permet de fixer le type et le codage de la réponse, ainsi que son contenu. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 12 / 29 Limitation des servlets Génération de HTML très lourde ; Le HTML est mélangé au java : I I mauvaise séparation affichage/traitements ; pas adapté à une séparation des tâches Serge Rosmorduc Java intensifProgrammation Web 2013-2014 13 / 29 Les JSP En gros, HTML avec des vrais morceaux de java dedans. Balises spécifiques <% ...%> : introduit des instructions java ; <%= ... %> : introduit des expressions java, dont le résultat est affiché. ; Objets disponibles out : permet d’écrire (JspWriter) request : objet requête ; response : objet réponse ; session : objet représentant la session ; application : représente l’application web. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 14 / 29 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 JSP, exemple <!DOCTYPE html> <html> <head> <meta c h a r s e t = ” UTF−8”> < t i t l e >JSP</ t i t l e > </head> <body> <p>Bonjour <%= r e q u e s t . getParameter ( ”nom” ) %></p> <p> <% f o r ( i n t i = 0 ; i < 100; i ++) { o u t . p r i n t ( ”−” ) ; } %> </body> </ html> Serge Rosmorduc Java intensifProgrammation Web 2013-2014 15 / 29 Utilisation propre de tout ça La servlet : I I I I c’est du java (chic !) reçoit la requête ; délègue le traitement à des classes métier (parce que le web c’est l’enfer) ; délègue l’affichage à une JSP La JSP : I I I mélange du HTML et du code ; ne calcule rien du tout. se contente d’afficher les données transmises par la servlet. avantages : éléments développables séparément, testables séparéments. En pratique... Serge Rosmorduc Java intensifProgrammation Web 2013-2014 16 / 29 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 Transmettre la main à une JSP depuis une servlet Exemple : affichage du nom d’une personne capitalisé. On utilise un RequestDispatcher dans la servlet.... public class H e l l o 2 extends H t t p S e r v l e t { protected void doGet ( H t t p S e r v l e t R e q u e s t request , HttpServletResponse response ) throws S e r v l e t E x c e p t i o n , IOException { / / R écup ération des param ètres S t r i n g nom = r e q u e s t . getParameter ( ”nom” ) ; / / T r a i t e m e n t : une c l a s s e m é t i e r . . . S t r i n g nomCap= NomHelper . c a p i t a l i s e r (nom ) ; / / On t r a n s m e t l e s donn ées / / à a f f i c h e r comme ” beans r e q u e s t ” r e q u e s t . s e t A t t r i b u t e ( ” n o m C a p i t a l i s e ” , nomCap ) ; / / On cr ée l e d i s p a t c h e r RequestDispatcher r = r e q u e s t . g e t R e q u e s t D i s p a t c h e r ( ” /WEB−INF / j s p / h e l l o 2 . j s p ” ) ; / / On passe l a main à l a s e r v l e t r . f o r w a r d ( request , response ) ; } } Serge Rosmorduc Java intensifProgrammation Web 2013-2014 17 / 29 Commentaires La capitalisation n’est pas si simple (nom null, nom de taille 0 ou 1)... on la sort de la servlet, qui doit être le moins intelligente possible → création d’une classe NomHelper la méthode est statique, mais c’est juste parce que l’exemple est simple ; séparée de la servlet, elle peut être testée seule ; on calcule les données à afficher (ici nomCap), et on les transmet à la jsp comme beans request à l’aide de la méthode request.setAttribute(ident, valeur) I I ident est un identifiant pour désigner l’attribut ; valeur est un objet quelconque (pas forcément une String) Serge Rosmorduc Java intensifProgrammation Web 2013-2014 18 / 29 1 2 3 4 RequestDispatcher Sert à demander à une JSP de terminer le traitement de la requête. Utilisation S t r i n g chemin= ” /WEB−INF / j s p / h e l l o 2 . j s p ” ; RequestDispatcher r = r e q u e s t . g e t R e q u e s t D i s p a t c h e r ( chemin ) ; r . f o r w a r d ( request , response ) ; chemin : page qui traite l’affichage. Très souvent une JSP, placée dans WEB-INF. r.forward(request,response) expédie la requête courante à cette nouvelle page. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 19 / 29 L’expression language (première approche) Dans la JSP, on peut écrire : 1 <%= r e q u e s t . g e t A t t r i b u t e ( ” n o m C a p i t a l i s e ” ) %> Mais c’est long et peu lisible. de plus, on souhaite éliminer le code java des JSP : la JSP ne fait que de l’affichage. Un langage spécial est disponible : ${nomCapitalise} affiche la valeur du bean. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 20 / 29 Propriétés des beans Quand un bean est un objet avec des accesseurs... ; par exemple un bean personne de classe Personne avec les accesseurs getNom() et getPrenom() ; alors ${personne.nom} affiche le nom de la personne en appelant personne.getNom() Serge Rosmorduc Java intensifProgrammation Web 2013-2014 21 / 29 1 2 3 4 5 6 7 8 9 hello2.jsp <!DOCTYPE html> <html> <head> < t i t l e >JSP Page</ t i t l e > </head> <body> Bonjour ${ n o m C a p i t a l i s e } </body> </ html> Serge Rosmorduc Java intensifProgrammation Web 2013-2014 22 / 29 Récapitulation la servlet reçoit une requête, extrait les arguments, et décide quoi faire ; elle délègue le traitement effectif à des classes métiers, qui ne connaissent rien du web ; puis elle range les valeurs à afficher dans des beans request, enfin, elle passe la main à une JSP. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 23 / 29 Deuxième partie II Du traitement des formulaires Serge Rosmorduc Java intensifProgrammation Web 2013-2014 24 / 29 Formulaire, exemple Application qui I I I I I saisit le nom et le prénom d’une personne ; vérifie que les champs sont remplis ; calcule le texte de la salutation ; l’affiche avec une jsp ; réaffiche le formulaire avec des messsages d’erreur et les données erronées en cas de problème. C’est la même servlet qui affiche le formulaire et le traite. deux jsp : le formulaire et le résultat. souvent, doGet() est appelé pour le premier affichage, et doPost pour les traitements. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 25 / 29 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 Servlet public class S a l u e r extends H t t p S e r v l e t { protected void doGet ( . . . . . . . . . ) { / / A p r i o r i , p r e m i e r appel . . . req . g e t R e q u e s t D i s p a t c h e r ( ” /WEB−INF / j s p / saluerForm . j s p ” ) . f o r w a r d ( req , resp ) ; } protected void doPost ( . . . . . . . . . . ) { String jsp ; S t r i n g nom= req . getParameter ( ”nom” ) ; S t r i n g prenom= req . getParameter ( ” prenom ” ) ; i f (nom == n u l l | | prenom == n u l l | | ” ” . equals (nom) | | ” ” . equals ( prenom ) ) { req . s e t A t t r i b u t e ( ” message ” , ” l e s champs d o i v e n t ê t r e r e m p l i s ” ) ; j s p = ” /WEB−INF / j s p / saluerForm . j s p ” ; } else { req . s e t A t t r i b u t e ( ”nom” , nom . toUpperCase ( ) ) ; req . s e t A t t r i b u t e ( ” prenom ” , prenom ) ; j s p = ” /WEB−INF / j s p / s a l u e r . j s p ” ; } req . g e t R e q u e s t D i s p a t c h e r ( j s p ) . f o r w a r d ( req , resp ) ; } } Serge Rosmorduc Java intensifProgrammation Web 2013-2014 26 / 29 JSP formulaire 1 <%@page contentType= ” t e x t / h t m l ” pageEncoding= ” UTF−8”%> 2 <!DOCTYPE html> 3 <html> 4 <head> 5 < t i t l e >Saluer </ t i t l e > 6 </head> 7 <body> 8 <p s t y l e = ” c o l o r : red ”>${message}</p> 9 <form method= ”POST”> 0 <p>nom : 1 <i n p u t t y p e = ” t e x t ” name= ”nom” v a l u e = ” ${param . nom} ” /></p> 2 <p>prenom : 3 <i n p u t t y p e = ” t e x t ” name= ” prenom ” v a l u e = ” ${param . prenom} ” /></p> 4 <p><i n p u t t y p e = ” submit ” /></p> 5 </form> 6 </body> 7 </ html> Noter que quand ${message} est absent, ça ne pose pas de problème... ${param.nom} : valeur du paramètre nom (et non de l’attribut) : valeur provenant du formulaire qu’on traite. Serge Rosmorduc Java intensifProgrammation Web 2013-2014 27 / 29 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 Amélioration : gestion des erreurs par tableau protected void doPost ( . . . . ) { String jsp ; HashMap<S t r i n g , S t r i n g > e r r e u r s = new HashMap<S t r i n g , S t r i n g > ( ) ; S t r i n g nom= req . getParameter ( ”nom” ) ; S t r i n g prenom= req . getParameter ( ” prenom ” ) ; i f (nom == n u l l | | ” ” . equals (nom ) ) { e r r e u r s . p u t ( ”nom” , ” ce champ d o i t ê t r e r e m p l i ” ) ; } i f ( prenom == n u l l | | ” ” . equals ( prenom ) ) { e r r e u r s . p u t ( ” prenom ” , ” ce champ d o i t ê t r e r e m p l i ” ) ; } i f ( ! e r r e u r s . isEmpty ( ) ) { req . s e t A t t r i b u t e ( ” e r r e u r s ” , e r r e u r s ) ; j s p = ” /WEB−INF / j s p / saluerForm1 . j s p ” ; } else { req . s e t A t t r i b u t e ( ”nom” , nom . toUpperCase ( ) ) ; req . s e t A t t r i b u t e ( ” prenom ” , prenom ) ; j s p = ” /WEB−INF / j s p / s a l u e r . j s p ” ; } req . g e t R e q u e s t D i s p a t c h e r ( j s p ) . f o r w a r d ( req , resp ) ; Serge Rosmorduc Java intensifProgrammation Web 2013-2014 28 / 29 Nouvelle version de la JSP 1 <%@page contentType= ” t e x t / h t m l ” pageEncoding= ” UTF−8”%> 2 <!DOCTYPE html> 3 <html> 4 <head> 5 <meta c h a r s e t = ” UTF−8”> 6 < t i t l e >Saluer </ t i t l e > 7 <s t y l e > 8 . e r r e u r { c o l o r : red ; } 9 </ s t y l e > 0 </head> 1 <body> 2 <form method= ”POST”> 3 <p>nom : <i n p u t t y p e = ” t e x t ” name= ”nom” v a l u e = ” ${param . nom} ” /> 4 <span class= ” e r r e u r ”> ${ e r r e u r s . nom}</span> 5 </p> 6 <p>prenom : <i n p u t t y p e = ” t e x t ” name= ” prenom ” 7 v a l u e = ” ${param . prenom} ” /> 8 <span class= ” e r r e u r ”> ${ e r r e u r s . prenom}</span> 9 </p> 0 <p><i n p u t t y p e = ” submit ” /></p> 1 </form> 2 </body> 3 </ html> Serge Rosmorduc Java intensifProgrammation Web 2013-2014 29 / 29