Aller au menu - Aller au contenu

Icône Les sessions

Mise à jour : 18/02/2011
Difficulté : Facile Facile Creative Commons BY-NC-SA
10 160 visites depuis 7 jours, dont 372 sur ce chapitre classé 25/786
Le titre de ce chapitre est assez évocateur, nous parlerons des sessions.
Mais d'abord, qu'est-ce que c'est qu'une session ? À quoi ça sert ? C'est comestible ?

Ces questions doivent vous brûler les lèvres : eh bien je m'engage à y répondre, ici et maintenant.
Vous verrez que cet objet - car, oui, il s'agit d'un objet que le conteneur nous offre - est très pratique et permet à votre application d'avoir une mémoire... enfin, façon de parler. ^^
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Qu'est-ce qu'une session ?

Tout d'abord, rappelez-vous le fonctionnement du web : un client envoie une requête HTTP en direction d'un serveur, celui-ci traite l'information et renvoie la réponse au client. Voici un schéma résumant la situation :

Image utilisateur


En fait, imaginez que votre serveur n'a pas de mémoire : à chaque requête, le serveur renverra une réponse sans savoir si c'est la même personne qui redemande la page. Les sessions permettent à votre serveur de garder un certain nombre d'informations de son côté afin de pouvoir les réutiliser ultérieurement. Sans le savoir, vous naviguez sur des sites qui utilisent des sessions, vous êtes d'ailleurs sur un de ceux-ci.

Le meilleur exemple d'utilisation de session reste encore la page de connexion d'un site comme le SDZ. Vous avez pu constater qu'une fois connecté vous n'avez plus à saisir de nouveau vos identifiants. Ceux-ci sont conservés et réutilisés tout au long de votre navigation sur le site grâce aux sessions.

Ça a l'air merveilleux ton truc, mais comment ça fonctionne ?

C'est justement ce que je vous propose de voir. :)

Créer et utiliser une session

Comme je vous le disais plus tôt, les sessions s'utilisent grâce à un objet. Les méthodes les plus couramment utilisées permettent de déposer et récupérer des valeurs dans notre objet. Ces valeurs sont stockées sous la forme "clé - valeur".
En fait, nous ordonnons à notre objet session de stocker une valeur que nous allons ranger grâce à une clé, un peu comme ceci :

Image utilisateur


Dans le cas du tableau ci-dessus, nous devrons, pour récupérer la valeur "monLogin", interroger notre objet de session en lui demandant de nous fournir la valeur de la clé "login". En fait, vous pouvez voir que son utilisation est très simple : nous allons pouvoir faire un premier essai, mais avant, voici une description succincte de notre objet : HttpSession.

Image utilisateur


Je vous propose un petit exemple afin de nous faire les dents… Celui-ci sera très simple, une page HTML qui demande un "login - mot de passe" via un formulaire (jusqu'ici, rien de spécial), une servlet qui va récupérer les informations du formulaire pour les mettre en session ; enfin, cette même servlet va rediriger la requête vers une autre servlet qui aura pour rôle d'afficher le contenu de notre session et d'y ajouter un objet qui aura pour rôle compter le nombre de fois que la page a été appelée (un bête incrément, quoi ^^ ). Allez, un petit schéma s'impose. :)

Image utilisateur


Voici les codes sources utilisés.

connexion.jsp


Code : JSP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Connexion à l'application</title>
</head>
<body>
<form name="session" method="POST" action="session.do" /> 
	<table>
		<tr>
			<td>Login : </td>
			<td><input type="text" name="login" /> </td>
		</tr>
		<tr>
			<td>Mot de passe : </td>
			<td><input type="password" name="password" /> </td>
		</tr>
		<tr>
			<td colspan="2" style="text-align:center"><input type="submit" name="valider" /></td>
		</tr>
	</table>
</form>
</body>
</html>


Servlet 1 : TestSession.java


Code : Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.sdz.session;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class TestSession extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
		//On récupère les identifiants et on les stocke dans notre objet de session
		String login = req.getParameter("login");
		String password = req.getParameter("password");
		HttpSession session = req.getSession();
		session.setAttribute("login", login);
		session.setAttribute("password", password);
		
		//Maintenant, nous allons utiliser cet objet dans une autre servlet
		resp.sendRedirect("result.do");		
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
	
		doGet(req, resp);
	}
}


Servlet 2 : ResultatSession.java


Code : Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.sdz.session;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class ResultatSession extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		HttpSession session = req.getSession();
		PrintWriter out = resp.getWriter();
		
		//On rajoute un attribut s'il n'existe pas
		//Et s'il existe, on incrémente cet attribut
		Object increment = session.getAttribute("increment");
		if(increment == null){
			session.setAttribute("increment", new Integer(1));
		}
		else{
			int value = ((Integer)increment).intValue();
			session.setAttribute("increment", ++value);
		}
		
		//On affiche l'identifiant de session unique
		out.println("<h2>Numéro de la session en cours : " + session.getId() + "</h2>");
		
		//On parcourt maintenant le contenu de notre objet session
		Enumeration e = session.getAttributeNames();
		while(e.hasMoreElements()){
			String key = (String)e.nextElement();
			out.println("<p>Clé : " + key + " - Valeur : " + session.getAttribute(key) + "</p>");
		}
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doGet(req, resp);
	}

}


Le descripteur de déploiement : web.xml


Code : XML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<web-app>

	<servlet>
		<servlet-class>com.sdz.session.TestSession</servlet-class>
		<servlet-name>firstSession</servlet-name>
	</servlet>
	
	<servlet>
		<servlet-class>com.sdz.session.ResultatSession</servlet-class>
		<servlet-name>resultSession</servlet-name>
	</servlet>
	
			
	<servlet-mapping>
		<servlet-name>firstSession</servlet-name>
		<url-pattern>/session.do</url-pattern>
	</servlet-mapping>
	
	<servlet-mapping>
		<servlet-name>resultSession</servlet-name>
		<url-pattern>/result.do</url-pattern>
	</servlet-mapping>
	
</web-app>


Voilà ce que j'ai obtenu avec ces codes :


Image utilisateurImage utilisateur



Dans notre exemple, nous avons utilisé une servlet pour afficher le contenu de notre objet session. Vous auriez aussi pu utiliser une page JSP : votre objet est accessible directement via la variable session. Elle fait partie des variables préchargées et peut être directement utilisable depuis une page JSP.


sendRedirect ou RequestDispatcher ?



Une petite nouveauté s'est glissée ici, c'est la notion de redirection. Ceci peut s'avérer très pratique lorsqu'on souhaite réorienter une requête vers une servlet particulière ou vers une JSP. Ceci se fait via l'objet HttpResponse en invoquant la méthode sendRedirect(String urlName). Cette méthode a une petite cousine qui, elle, est à invoquer via l'objet HttpRequest, vous la connaissez déjà et vous l'avez déjà utilisée, rappelez-vous, lorsque vous faites ceci :

Code : Java
1
2
RequestDispatcher dispatch = request.getRequestDispatcher("firstJsp.jsp");
dispatch.forward(request, response);


La principale différence réside dans la façon de travailler de ces deux méthodes. Imaginez-vous sur un chantier de maçonnerie avec plusieurs ouvriers.
Utiliser la méthode sendRedirect() reviendrait à demander à quelqu'un d'autre de faire le travail à votre place alors qu'utiliser l'objet RequestDispatcher reviendrait à demander un coup de main à un collègue, vous êtes toujours en charge de la tâche mais quelqu'un vient en soutien. Lorsque l'objet RequestDispatcher fait travailler quelqu'un d'autre, sendRedirect() simule une requête de la part d'un client. D'ailleurs, il vous suffit de tester les deux méthodes ; vous verrez dans la barre d'adresse que l'URL est différente selon le cas et, donc, que la servlet en charge de traiter la requête HTTP n'est pas la même :


Image utilisateur
Avec la méthode requestDispatcher


Image utilisateur
Avec la méthode sendRedirect


Fin de l'aparté.

Vous pouvez voir qu'avec cet exemple (après plusieurs appuis sur F5 dans la page récapitulative), notre application se rappelle de vous en conservant des informations. C'est très simple d'utilisation et très pratique car ce sont des objets qui sont mémorisés : vous pouvez donc très bien mettre ce qui vous chante dans votre session.
Vous aurez aussi remarqué que l'identifiant de session, qu'on récupère avec la méthode getId(), retourne toujours la même chaîne de caractères. C'est ce qu'on appelle le sessid. C'est grâce à cet identifiant que notre serveur sait à qui il parle et qu'il retrouve les informations : en fait, ce ne sont pas vraiment vos informations, mais les informations de la session car, si vous le souhaitez, vous pouvez avoir plusieurs sessions dans une même application. Dans notre exemple, faites la même chose sous deux navigateurs différents (Firefox et IE, par exemple) avec des données différentes et vous devriez obtenir ceci :

Image utilisateur


Du coup, une question doit germer dans vos esprits : comment le conteneur fait pour reconnaître telle ou telle session ?
Allez, je suis sympa, je vais vous expliquer. ;)

Comment ça fonctionne

Lorsqu'un client émet une requête vers un serveur, ledit serveur vérifie s'il connaît l'émetteur de la demande : le navigateur du client retourne l'identifiant qui lui a été attribué automatiquement ; sinon, il n'envoie rien. Dans ce cas, le serveur crée et retourne au client un nouvel identifiant de session. Cet identifiant est envoyé par le serveur et le navigateur s'il existe, c'est par ce biais que le serveur et le client semblent se connaître.

Notre serveur conserve en mémoire les identifiants qu'il génère. Il envoie vers chaque client leurs identifiants de session ; ainsi, lorsqu'un client renvoie un identifiant, le conteneur arrive à retrouver les informations qui lui étaient affectées.
Voici un petit schéma résumant la situation, vous y verrez plus clair je pense :

Image utilisateur


Mais comment le navigateur retourne l'identifiant ? Via les entêtes HTTP ?

Il y a deux cas de figure. Par défaut, les navigateurs acceptent ce qu'on appelle vulgairement des cookies. Un cookie est un petit fichier texte contenant différentes informations, dont votre identifiant de session. Si vous souhaitez voir le contenu de votre cookie, Firefox propose un module complémentaire, Edit Cookie qui permet de voir et d'éditer les cookies de votre navigateur. Pour l'installer, cliquez sur "Outils, Modules complémentaires" et recherchez ledit module dans le catalogue. Installez-le et redémarrez le navigateur.
Maintenant, un nouveau point de menu est disponible dans Firefox, dans le menu "Outils". Il ne vous reste plus qu'à chercher les cookies du site localhost et vous devriez tomber dessus.

Lorsque votre navigateur accepte les cookies, le contenu de ceux-ci est automatiquement encapsulé dans les entêtes HTTP par votre navigateur, l'id de session est donc retourné automatiquement vers le serveur. Par contre, il arrive que les cookies ne soient pas acceptés ; dans ce cas, vous pouvez faire quelque chose côté serveur afin d'encoder l'id de session dans l'URL de votre site. Ceci fait, l'id de session transitera dans les entêtes HTTP en tant que paramètre GET, le conteneur saura retrouver la session attachée.

Pour ce faire, il vous suffit d'utiliser la méthode encodeURL(String url) de l'objet HttpResponse. Ainsi, si dans notre servlet TestSession.java nous remplaçons la ligne resp.sendRedirect("result.do"); par celle-ci : resp.sendRedirect(resp.encodeURL("result.do"));, lorsque vous testerez à nouveau notre code, l'URL aura cette forme :

Image utilisateur


Voilà, vous savez maintenant comment votre conteneur préféré arrive à communiquer avec votre navigateur et vice et versa.
Je vous propose à présent de voir quelques listeners qui peuvent être utilisés sur les sessions.

Encore des listeners

Comme je vous l'avais mentionné dans un précédent chapitre, il existe des écouteurs qui ont pour rôle de surveiller vos sessions. Pour rappel, les voici :

Image utilisateur


  • HttpSessionListener : c'est un écouteur au niveau de l'application. Il peut servir à contrôler les créations ou destructions de sessions afin de connaître le nombre d'utilisateurs actuellement connectés par exemple ;
  • HttpSessionAttributeListener : sert à contrôler les éléments qui sont ajoutés, modifiés ou retirés de nos sessions ;
  • HttpSessionBindingListener : est utilisé par un objet souhaitant être averti lorsqu'il est inséré dans une session. En fait, c'est un objet qui implémente cette interface, objet qui doit nécessiter une action particulière lorsqu'il est mis en session ;
  • HttpSessionActivateListener : dans des environnements d'entreprise, il n'est pas rare d'avoir ce qu'on appelle un répartiteur de charge. Celui-ci s'occupe d'envoyer les requêtes HTTP vers tels ou tels serveurs ; dans ce cas, il peut y avoir plusieurs JVM utilisées pour gérer une application : cet écouteur est appelé lorsqu'une session est envoyée d'une JVM à une autre.


Voici deux classes vous montrant comment utiliser deux des listeners mentionnés ci-dessus, les plus utilisés en réalité. Nous avons rajouté à notre exemple deux classes écouteurs codées par nos soins…

Fichier SessionCounter.java


Code : Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package com.sdz.session;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class SessionCounter implements HttpSessionListener{

	private int countSession = 0;
	
	public void sessionCreated(HttpSessionEvent event) {
		System.out.println("Nombre de session(s) " + (++countSession));
	}

	public void sessionDestroyed(HttpSessionEvent event) {
		System.out.println("Nombre de session(s) " + (--countSession));
	}
}


Fichier SessionAttribute.java


Code : Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package com.sdz.session;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class SessionAttribute implements HttpSessionAttributeListener{

	public void attributeAdded(HttpSessionBindingEvent event) {
		System.out.println("L'attribut " + event.getName() + " qui a pour valeur " + event.getValue() + " a été rajouté dans une session");
	}

	public void attributeRemoved(HttpSessionBindingEvent event) {
		System.out.println("L'attribut " + event.getName() + " qui a pour valeur " + event.getValue() + " a été retiré dans une session");
	}

	public void attributeReplaced(HttpSessionBindingEvent event) {
		System.out.println("L'attribut " + event.getName() + " qui a pour valeur " + event.getValue() + " a été remplacé dans une session");
	}
}




Le fichier web.xml


Code : XML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<web-app>

	<servlet>
		<servlet-class>com.sdz.session.TestSession</servlet-class>
		<servlet-name>firstSession</servlet-name>
	</servlet>
	
	<servlet>
		<servlet-class>com.sdz.session.ResultatSession</servlet-class>
		<servlet-name>resultSession</servlet-name>
	</servlet>
	
			
	<servlet-mapping>
		<servlet-name>firstSession</servlet-name>
		<url-pattern>/session.do</url-pattern>
	</servlet-mapping>
	
	<servlet-mapping>
		<servlet-name>resultSession</servlet-name>
		<url-pattern>/result.do</url-pattern>
	</servlet-mapping>
	
	<listener>
		<listener-class>
			com.sdz.session.SessionCounter
		</listener-class>
		<listener-class>
			com.sdz.session.SessionAttribute
		</listener-class>
	</listener>
	
</web-app>



Euh… tu as dû te tromper. Tu as utilisé des System.out.println(""), ça ne va s'afficher nulle part !

En fait, si. Lorsque vous contrôlez le serveur Tomcat depuis Eclipse, si vous utilisez ce genre d'instructions, elles s'afficheront dans la console EClipse. La preuve en image en testant sur deux navigateurs, comme précédemment :

Image utilisateur

Durée d'une session

Vous devez savoir une dernière chose sur les sessions : celles-ci ont une durée de vie limitée. En fait, au bout d'un certain temps d'inactivité, la session est détruite : par défaut, le temps maximum d'inactivité est de 30 minutes.

Comment sais-tu ça ?

C'est simple : Tomcat, comme beaucoup de conteneurs JEE, a un fichier de configuration qui lui permet de régler ce genre de choses. Celui-ci s'appelle aussi web.xml, mais il se trouve dans le dossier "conf" de Tomcat.

Si vous ouvrez ce fichier, avec Notepad++ par exemple, vous pourrez voir qu'après toutes les définitions de servlets de ce fichier, vous avez cette déclaration :

Code : XML
1
2
3
<session-config>
    <session-timeout>30</session-timeout>
</session-config>


Vous pouvez donc redéfinir cette durée dans le fichier web.xml de vos applications afin d'offrir à vos sessions une durée de vie qui convienne à vos besoins.

Voilà ! Je pense que les sessions n'ont plus beaucoup de secrets pour vous. Je vous propose donc, après avoir effectué le QCM, d'approfondir cette notion de cookie dont nous avons parlé auparavant. :)

Q.C.M.

À quoi sert une session ?
Par quel objet obtenons-nous une session dans une servlet ?
Comment le serveur arrive à retrouver la session à utiliser ?
La gestion des sessions côté client est-elle automatiquement autorisée ?
Une session a-t-elle une durée de vie illimitée ?

Statistiques de réponses au QCM

Voilà, encore un chapitre riche en nouveautés. J'espère que vous arrivez toujours à suivre et que je ne m'égare pas dans d'obscures explications inintelligibles…
Si vous êtes toujours d'attaque, je vous propose de voir une notion étroitement liée aux sessions : les cookies.
Chapitre précédent Sommaire Chapitre suivant

Partager

2 commentaires pour "Les sessions"
Note moyenne : 3.17 / 4 (294 votes)
Pseudo Commentaire
Hors ligne softdounia # Posté le 30/05/2011 à 00:47:32
A
Avatar

Ville : Alger
Pays : Algérie
Études : ETS Montréal

Merci cysboy pour ce tuto, mais a quand la suite promit (JSF, ..., Hibernate, ....

?

Les 40e rugissants et les 50e hurlants. o_O --> Brainstorming --> CamelCase
Image utilisateur

-------------
"je crois qu'on ne peut mieux vivre qu'en chercant à devenir meilleur, ni plus agréablement qu'en ayant pleine conscience de son amélioration"
Socrate >_<
-------------
les meilleurs peintres se sont fait dire qu’ils n’étaient pas bon, aujourd’hui ce sont des Dieux!
-------------
RTFM :-° l'expression anglaise d'argot Internet Read the fucking manual (« Lis le foutu manuel ») ;
-------------
Mon CV en ligne ici
 
Hors ligne GNUt3ll4 # Posté le 24/03/2012 à 23:13:52
Avatar

Études : IUT A Lyon 1

Je me permets de relever une petite erreur :
Dans la sous-partie :
Encore des listeners
la liste avec les nom d'objets en violet, la dernière interface :
HttpSessionActivateListener ---> il s'agit de HttpSessionActivationListener

Merci pour ce tuto'!
Bonne continuation

Voir tous les commentaires