• Aucun résultat trouvé

Action standard include

Dans le document Cours J2EE Approfondi (Page 75-79)

Une autre balise d'inclusion dite "standard" existe, et permet d'inclure du contenu de manière "dynamique". Le contenu sera ici chargé à l'exécution, et non à la compilation comme c'est le cas avec la directive précédente :

Code : JSP

<%-- L'inclusion dynamique d'une page fonctionne par URL relative : --%>

<jsp:include page="page.jsp" />

<%-- Son équivalent en code Java est : --%>

<% request.getRequestDispatcher( "page.jsp" ).include( request,

response ); %>

<%-- Et il est impossible d'inclure une page externe comme ci-dessous : --%>

<jsp:include page="http://www.siteduzero.com" />

Cela dit, ce type d'inclusion a un autre inconvénient : il ne prend pas en compte les imports et inclusions faits dans la page réceptrice. Pour clarifier, prenons un exemple. Si vous utilisez un type List dans une première page, et que vous comptez utiliser une liste dans une seconde page que vous souhaitez inclure dans cette première page, il vous faudra importer le type List dans cette seconde page…

Je vous ai perdus ? Voyons tout cela au travers d'un exemple très simple. Créez une page test_inc.jsp contenant le code suivant, sous le répertoire WebContent de votre projet Eclipse, c'est-à-dire à la racine de votre application :

Code : JSP - /test_inc.jsp

<%

ArrayList<Integer> liste = new ArrayList<Integer>();

liste.add( 12 );

out.println( liste.get( 0 ) );

%>

Ce code ne fait qu'ajouter un entier à une liste vide, puis l'affiche. Cependant cette page ne contient pas de directive d'import, et ne peut par conséquent pas fonctionner directement : l'import de la classe ArrayList doit obligatoirement être réalisé auparavant pour que nous puissions l'utiliser dans le code. Si vous tentez d'accéder directement à cette page via

http://localhost:8080/test/test_inc.jsp, vous aurez droit à une jolie exception :

Citation : Exception

org.apache.jasper.JasperException: Unable to compile class for JSP: An error occurred at line: 2 in the jsp file: /test_inc.jsp

Créez maintenant une page test_host.jsp, toujours à la racine de votre application, qui va réaliser l'import de la classe ArrayList puis inclure la page test_inc.jsp :

Code : JSP - test_host.jsp

<%@ page import="java.util.ArrayList" %> <%@ include file="test_inc.jsp" %>

Pour commencer, vous découvrez ici en première ligne une application de la directive page, utilisée ici pour importer la classe ArrayList. À la seconde ligne, comme je vous l'ai expliqué plus haut, la directive d'inclusion peut être vue comme un copier- coller : ici, le contenu de la page test_inc.jsp est copié dans la page test_host.jsp, puis la nouvelle page test_host.jsp contenant tout le code est compilée. Vous pouvez donc appeler la page test_host.jsp, et la page web finale affichera bien "12" !

Mais si maintenant nous décidons de remplacer la directive présente dans notre page test_host.jsp par la balise standard d'inclusion :

Code : JSP - test_host.jsp

<%@ page import="java.util.ArrayList" %> <jsp:include page="test_inc.jsp" />

Eh bien lorsque nous allons tenter d'accéder à la page test_host.jsp, nous retrouverons la même erreur que lorsque nous avons tenté d'accéder directement à test_inc.jsp ! La raison est la suivante : les deux pages sont compilées séparément, et l'inclusion ne se fera que lors de l’exécution. Ainsi fatalement, la compilation de la page test_inc.jsp ne peut qu'échouer, puisque l'import nécessaire au bon fonctionnement du code n'est réalisé que dans la page hôte.

Pour faire simple, les pages incluses via la balise <jsp:include ... /> doivent en quelque sorte être

"indépendantes" ; elles ne peuvent pas dépendre les unes des autres et doivent pouvoir être compilées séparément. Ce n'est pas le cas des pages incluses via la directive <%@ include ... %> .

Pour terminer sur ces problématiques d'inclusions, je vous donne ici quelques informations et conseils supplémentaires. Certains serveurs d'applications sont capables de recompiler une page JSP incluant une autre page via la directive d'inclusion, et ainsi éclipser sa principale contrainte. Ce n'est toutefois pas toujours le cas, et ça reste donc à éviter si vous n'êtes pas sûrs de votre coup…

Pour inclure un même header et un même footer dans toutes les pages de votre application ou site web, il est préférable de ne pas utiliser ces techniques d'inclusion, mais de spécifier directement ces portions communes dans le fichier

web.xml de votre projet. J'en reparlerai dans un prochain chapitre.

Très bientôt, nous allons découvrir une meilleure technique d'inclusion de pages avec la JSTL !

La portée des objets

Un concept important intervient dans la gestion des objets par la technologie JSP : la portée des objets. Souvent appelée visibilité, ou scope en anglais, elle définit tout simplement leur durée de vie.

Dans le chapitre traitant de la transmission de données, nous avions découvert un premier type d'attributs : les attributs de requête. Eh bien de tels objets, qui je vous le rappelle sont accessibles via l'objet HttpServletRequest, ne sont visibles que durant le traitement d'une même requête. Ils sont créés par le conteneur lors de la réception d'une requête HTTP, et disparaissent dès lors que le traitement de la requête est terminé.

Ainsi, nous avions donc, sans le savoir, créé des objets ayant pour portée la requête !

Il existe au total quatre portées différentes dans une application :

page (JSP seulement) : les objets dans cette portée sont uniquement accessibles dans la page JSP en question ; requête : les objets dans cette portée sont uniquement accessibles durant l'existence de la requête en cours ; session : les objets dans cette portée sont accessibles durant l'existence de la session en cours ;

Pourquoi préciser "JSP seulement" pour la portée page ?

Eh bien c'est très simple : il est possible de créer et manipuler des objets de portées requête, session ou application depuis une page JSP ou depuis une servlet. Nous avions d'ailleurs dans le chapitre traitant de la transmission de données créé un objet de portée requête depuis notre servlet, puis utilisé cet objet depuis notre page JSP. En revanche, il n'est possible de créer et manipuler des objets de portée page que depuis une page JSP, ce n'est pas possible via une servlet.

Qu'est-ce qu'une session ?

Une session est un objet associé à un utilisateur en particulier. Elle existe pour la durée pendant laquelle un visiteur va utiliser

l'application, cette durée se terminant lorsque l'utilisateur ferme son navigateur, reste inactif trop longtemps, ou encore lorsqu'il se déconnecte du site.

Ainsi, il est possible de garder en mémoire des données concernant un visiteur d'une requête à l'autre, autrement dit de page en page : la session permet donc de garder une trace de la visite effectuée. Plus précisément, une session correspond en réalité à un navigateur particulier, plutôt qu'à un utilisateur : par exemple, si à un même instant vous utilisez deux navigateurs différents pour vous rendre sur le même site, le site créera deux sessions distinctes, une pour chacun des navigateurs.

Un objet session concernant un utilisateur est conservé jusqu'à ce qu'une certaine durée d’inactivité soit atteinte. Passé ce délai, le conteneur considère que ce client n'est plus en train de visiter le site, et détruit alors sa session.

Pour que vous visualisiez bien le principe, voici à la figure suivante un schéma regroupant les différentes portées existantes.

Portées des objets Remarquez bien les points suivants :

un objet de portée page n'est accessible que sur une page JSP donnée ;

un objet de portée requête n'est accessible que durant le cheminement d'une requête dans l'application, et n'existe plus dès lors qu'une réponse est renvoyée au client ;

un objet de portée session est accessible durant l'intégralité de la visite d'un client donné, à condition bien sûr que le temps d'inactivité défini par le conteneur ne soit pas dépassé durant cette visite ;

un objet de portée application est accessible durant toute l'existence de l'application et par tous les clients.

Vous devez bien réaliser que l'utilisation dans votre code d'objets ayant pour portée l'application est délicate. Rendez- vous compte : ces objets sont accessibles partout, tout le temps et par tout le monde ! Afin d'éviter notamment des problèmes de modifications concurrentes, si vous avez besoin de mettre en place de tels objets, il est recommandé de les initialiser dès le chargement de l'application, puis de ne plus toucher à leur contenu et d'y accéder depuis vos classes et pages uniquement en lecture seule. Nous étudierons ce scénario dans un prochain chapitre.

Nous reviendrons au cas par cas sur chacune de ces portées dans certains exemples des chapitres à venir.

Les actions standard

Autant vous prévenir tout de suite, le déroulement de ce chapitre peut vous perturber : je vais dans cette partie du chapitre vous présenter une certaine manière de faire pour accéder à des objets depuis une page JSP. Ensuite, je vais vous expliquer dans la partie suivante qu'il existe un autre moyen, plus simple et plus propre, et que nous n'utiliserons alors plus jamais cette première façon de faire…

Maintenant que vous connaissez les beans et les portées, vous avez presque tout en main pour constituer le modèle de votre application (le M de MVC) ! C'est lui et uniquement lui qui va contenir les données de votre application, et les traitements à y appliquer. La seule chose qui vous manque encore, c'est la manipulation de ces beans depuis une page JSP.

Vous avez déjà fait connaissance avec l'action standard <jsp:include>, je vais vous en présenter quatre autres :

<jsp:useBean>, <jsp:getProperty>, <jsp:setProperty> et enfin <jsp:forward>.

L'action standard useBean

Voici pour commencer l'action standard permettant d'utiliser un bean, ou de le créer s'il n'existe pas, depuis une page JSP :

Code : JSP

<%-- L'action suivante récupère un bean de type Coyote et nommé

"coyote" dans

la portée requête s'il existe, ou en crée un sinon. --%> <jsp:useBean id="coyote" class="com.sdzee.beans.Coyote" scope="request" />

<%-- Elle a le même effet que le code Java suivant : --%> <%

com.sdzee.beans.Coyote coyote = (com.sdzee.beans.Coyote)

request.getAttribute( "coyote" );

if ( coyote == null ){

coyote = new com.sdzee.beans.Coyote();

request.setAttribute( "coyote", coyote ); }

%>

Étudions les différents attributs de cette action.

La valeur de l'attribut id est le nom du bean à récupérer, ou le nom que vous souhaitez donner au bean à créer.

L'attribut class correspond logiquement à la classe du bean. Il doit obligatoirement être spécifié si vous souhaitez créer un bean, mais pas si vous souhaitez simplement récupérer un bean existant.

L'attribut optionnel scope correspond à la portée de l'objet. Si un bean du nom spécifié en id existe déjà dans ce scope, et qu'il est du type ou de la classe précisé(e), alors il est récupéré, sinon une erreur survient. Si aucun bean de ce nom n'existe dans ce scope, alors un nouveau bean est créé. Enfin, si cet attribut n'est pas renseigné, alors le scope par

défaut sera limité à la page en cours.

une interface implémentée par le bean. Cet attribut doit être spécifié si class ne l'est pas, et vice-versa.

En résumé, cette action permet de stocker un bean (nouveau ou existant) dans une variable, qui sera identifiée par la valeur saisie dans l'attribut id.

Il est également possible de donner un corps à cette balise, qui ne sera exécuté que si le bean est créé :

Code : JSP

<jsp:useBean id="coyote" class="com.sdzee.beans.Coyote">

<%-- Ici, vous pouvez placer ce que vous voulez :

définir des propriétés, créer d'autres objets, etc. --%>

<p>Nouveau bean !</p> </jsp:useBean>

Ici, le texte qui est présent entre les balises ne sera affiché que si un bean est bel et bien créé, autrement dit si la balise

<jsp:useBean> est appelée avec succès. À l'inverse, si un bean du même nom existe déjà dans cette page, alors le bean sera simplement récupéré et le texte ne sera pas affiché.

Dans le document Cours J2EE Approfondi (Page 75-79)