2009-08-15 11 views
21

Je suis nouveau dans le monde du J (2) EE et du développement d'applications web, mais je suis rapidement en train de naviguer et d'apprendre beaucoup. Chaque jour est un voyage fantastique de nouvelle découverte pour moi.Sauvegarder des données dans une session dans JSF

Je travaille actuellement sur un projet dans lequel j'utilise Visual JSF Woodstock sur Glassfish v2. Je suis assez nouveau à JSF aussi.

Il y a des moments où j'ai besoin de sauvegarder des objets (disons MyObject par exemple) entre les requêtes. Et à partir de ce que j'ai lu et compris jusqu'à présent, j'ai besoin d'utiliser des sessions pour enregistrer ces objets entre différentes requêtes. Jusqu'ici tout va bien.

Exactement comment faire ceci est où mon inquiétude réside. Je sais que dans JSP vous pouvez utiliser le session.setAttribute("myObj", myObject) qui enregistrerait l'objet du côté client en utilisant des cookies ou des réécritures d'URL ou des variables de formulaire masquées. En revanche, dans JSF, j'utilise des beans de session, par exemple SessionBean1, et enregistre des objets en tant que propriétés SessionBean1 (par exemple SessionBean1.setSomeOjb(myObj)). Est-ce la bonne façon de s'y prendre? J'imagine que cela se traduira par une augmentation de l'utilisation de la mémoire au niveau du serveur, car chaque requête créera une nouvelle instance du bean de session, SessionBean1, plus la mémoire utilisée par les instances myObject enregistrées dans SessionBean1.

J'ai lu que vous pouvez utiliser FacesContext.getExternalContext().getSession/getSessionMap() qui enregistrerait les variables de session du côté client.

Alors, quelle méthode suggéreriez-vous que j'utilise - le bean de session ou la carte de session pour enregistrer des objets pour l'accès entre les demandes d'une session?

Merci.

+1

"chaque requête créera une nouvelle instance de la session bean tronqué" C'EST COMPLÈTEMENT MAUVAIS –

Répondre

21

En général, les applications Web Java EE ne s'attendent généralement pas à sauvegarder le côté client des données de session. Vous avez raison de vous inquiéter de la saturation de la session côté serveur, un problème courant est d'avoir d'énormes empreintes de session qui peuvent causer des problèmes significatifs de ressources et de performances, notamment dans les environnements en cluster.

Je voudrais savoir où vous voyez

J'ai lu que vous pouvez utiliser FacesContext.getExternalContext(). GetSession/getSessionMap() qui sauverait des variables de session au côté client.

Je crois (me corriger sur ce point) que cela donne simplement accès à l'objet HttpSession, sur lequel vous pouvez ensuite utiliser le même

session.setAttribute("myObj", myObject) 

cela ne constitue pas en soi envoyer l'objet à le client, il est détenu dans le serveur et saisi par un identifiant de session, généralement passé dans un cookie. Il existe maintenant deux autres techniques: vous pouvez choisir explicitement de placer des données dans un cookie de votre propre fabrication - les API de servlet auxquelles vous pouvez accéder depuis JSF ou JSP vous le permettent, ou vous pouvez utiliser des champs cachés sur vos formulaires, et donc passer des données de session aorund.

Mais considérez ceci. Une règle de base sur le serveur d'applications que j'utilise est que HttpSession de l'ordre de 1k-4k ont ​​tendance à ne pas être un problème. Plus grand que cela (et j'ai vu des sessions mesurées en mégaoctets) mettent l'accent sur l'infrastructure.Si vous étiez préoccupé par les sessions de cette taille, attendez-vous à envoyer des mégaoctets de données dans un cookie ou un champ masqué au navigateur à chaque requête? Même 1k-2k est probablement un peu gros.

Alors recommandations:

  1. keep it simple. Utilisez l'API de session ou sa manifestation JSF.

  2. Conserve la quantité de données de la session sous contrôle.

Ajouté en réponse à la question sur le clustering:

En règle générale, dans un environnement en cluster, nous avons une affinité de session, afin que les demandes sont renvoyées au même membre du cluster. Cependant, nous devons toujours considérer le cas (peut-être si un membre du cluster échoue) lorsque la requête est envoyée à un autre serveur. Certains fournisseurs App Server proposent une réplication de session, soit via une communication directe inter-serveur, soit en conservant la session dans une base de données - il y a évidemment ici des frais généraux, pour des sessions de faible valeur, nous acceptons simplement la perte de session. d'échec. Il existe un argument selon lequel si les données de session ont une valeur élevée, elles doivent être conservées par l'application, il s'agit en fait de données métier et elles doivent être traitées comme telles. De plus en plus, des bases de données NOSQL telles que Cloudant ou MongoDb sont utilisées pour cela. Dans ce cas, nous pouvons considérer la session HTTP comme un cache, sachant que les données de la session peuvent être récupérées en cas d'erreur.

Donc, je dirais qu'un panier d'achat peut avoir une valeur considérable pour l'entreprise; il représente l'accumulation réfléchie des clients sur les objets pour lesquels ils veulent dépenser de l'argent. Donc, il devrait être persisté, plutôt que juste gardé dans la session. Une fois que nous décidons de le persister, nous constatons qu'il conduit à d'autres scénarios intéressants, tels qu'une expérience consolidée sur de nombreux périphériques clients. Le client commence à faire des achats à la maison sur un ordinateur de bureau, mais achève l'achat en ligne.

Donc un autre principe:

3). N'utilisez pas trop la session HTTP juste parce qu'elle est là. Considérez la valeur commerciale des données et si elles devraient être conservées.

+0

Vous avez raison. J'ai compris par erreur que tous les objets de la session sont enregistrés dans la carte de session et que la carte de session est ensuite envoyée au client où elle est stockée sous forme de cookies ou de champ masqué. Au lieu de cela, c'est l'identifiant de session qui est envoyé au client. Si je comprends bien, cet identifiant de session peut être utilisé pour récupérer l'instance de HttpSession qui stocke tous les attributs pour cette session Web particulière, n'est-ce pas? Merci d'avoir signalé mon malentendu. – SibzTer

+0

Salut, je sais qu'il ya longtemps que vous répondez à la question, mais vous avez dit quelque chose d'intéressant à propos de l'environnement en cluster. Comment puis-je conserver la session dans ce type d'architecture si la session est enregistrée sur le serveur qui répond à la requête? – kavain

+1

@Kavain: Les bons serveurs Java-EE offrent la possibilité d'optimiser la réplication de session dans les clusters pour le basculement. Ils permettent aux serveurs d'être configurés en groupes, de sorte que tous les serveurs n'obtiennent pas toutes les informations de session. Seulement ceux qui sont dans le même groupe. Mieux pour les performances dans la réplication elle-même et dans l'utilisation de la mémoire. Ainsi, par exemple avoir 1.000.000 utilisateurs avec une taille de session de 100k sur 100 serveurs ne signifie pas que chaque serveur aura besoin de 100GB de mémoire. Distrubuted dans les groupes de 3, exigera que chaque serveur ait juste 3 GB. Et une taille de session de 100k est grande ... – Kukeltje

2

Alors, quelle méthode suggéreriez-vous que j'utilise - le bean de session ou la carte de session pour enregistrer des objets pour l'accès entre les demandes d'une session?

Ces deux éléments stockent les données exactement au même endroit.

<managed-bean> 
    <managed-bean-class>foo.Bar</managed-bean-class> 
    <managed-bean-name>bar</managed-bean-name> 
    <managed-bean-scope>session</managed-bean-scope> 
</managed-bean> 

Une fois référencé dans une expression, vous pouvez rechercher "bar" via le programme external context.

Pour votre information: en JSF2, la déclaration peut être retirée et remplacée par des annotations:

@ManagedBean(name="bar") @SessionScoped 
public class Bar { 
... 
+0

Doit admettre que c'est environ 3 ans depuis que j'ai touché JSF. À l'époque, j'utiliserais simplement un haricot géré par une session, à peu près comme vous le montrez. Je n'ai pas considéré d'alternative à l'époque. Je pense que l'une des questions pourrait être de savoir comment nous assurer que nous conservons ce rang, ne voulons pas acuumuler progressivement beaucoup de beans gérés par la session. Cela peut être dû à des noms de haricots soigneusement choisis. – djna

14

Je travaille sur un projet de l'université avec mes collègues, est une toile comme GoogleImage Labeler. Eh bien, nous avons donc un UserController, avec ses méthodes login, logout, etc ...et nous étendons la session comme ceci:

@ManagedBean(name = "userController") 
@SessionScoped 

Ok, c'est ce que l'assistant de NetBeans crée pour vous.

Notre façon de créer et de gérer la session est:

A la méthode de registre (dont nous utilisons les attributs de la forme dans le XHTML ...) nous persistons l'utilisateur dans le DB puis nous ajoutons les valeurs dans la session:

FacesContext context = FacesContext.getCurrentInstance(); 
context.getExternalContext().getSessionMap().put("user", current); 

Où "courant" est un utilisateur (l'utilisateur connecté, bien sûr). Nous avons le même à la méthode de connexion.

à la méthode logout nous avons:

FacesContext.getCurrentInstance().getExternalContext().invalidateSession(); 

J'espère que cela vous aide.

+2

C'est maladroit. Affectez juste le 'current' comme propriété de' UserController' (comme c'est * déjà * dans la portée de la session!) Et réglez le sur 'null' lors de la déconnexion (ou mieux, faites' ExternalContext # invalidateSession() '. //stackoverflow.com/questions/3841361/jsf-http-session-login/3842060#3842060 – BalusC

+0

J'ai modifié le post pour remplacer mon code par celui que @BalusC a dit J'ai changé 'FacesContext context = FacesContext.getCurrentInstance ( context.getExternalContext(). GetSessionMap(). Remove ("user"); 'pour' FacesContext.getCurrentInstance(). GetExternalContext(). InvalidateSession(); ' –

Questions connexes