2009-09-30 9 views
25

J'ai une servlet qui gère un poste de forme multipart. La publication est en fait effectuée par un composant de téléchargement de fichier Flash intégré dans la page. Dans certains navigateurs, le POST généré par Flash n'inclut pas le JSESSIONID qui me rend impossible de charger certaines informations de la session pendant la publication.Comment charger manuellement une session Java à l'aide d'un JSESSIONID?

Le composant de téléchargement flash inclut des informations de cookie et de session dans un champ de formulaire spécial. En utilisant ce champ de formulaire, je peux réellement récupérer la valeur JSESSIONID. Le problème est, je ne sais pas comment utiliser cette valeur JSESSIONID pour charger manuellement cette session spécifique.

Edition - Sur la base de la solution de ChssPly76, j'ai créé le suivant HttpSessionListener mise en œuvre:

@Override 
    public void sessionCreated(final HttpSessionEvent se) { 
     final HttpSession session = se.getSession(); 
     final ServletContext context = session.getServletContext(); 
     context.setAttribute(session.getId(), session); 
    } 

    @Override 
    public void sessionDestroyed(final HttpSessionEvent se) { 
     final HttpSession session = se.getSession(); 
     final ServletContext context = session.getServletContext(); 
     context.removeAttribute(session.getId()); 
    } 

Ce qui ajoute à toutes les séances au ServletContext comme attributs cartographiés par leurs ids uniques. Je pourrais plutôt mettre une carte de sessions dans le contexte, mais cela semble redondant. S'il vous plaît poster des réflexions sur cette décision. Ensuite, ajouter la méthode suivante à mon servlet pour résoudre la session par ID:

private HttpSession getSession(final String sessionId) { 
     final ServletContext context = getServletContext(); 
     final HttpSession session = (HttpSession) context.getAttribute(sessionId); 
     return session; 
    } 
+0

+1 .. très belle question – peakit

Répondre

21

Il n'y a pas d'API pour récupérer la session par identifiant. Toutefois, vous pouvez implémenter un session listener dans votre application Web et gérer manuellement une carte de sessions avec un ID (l'ID de session peut être récupéré via session.getId()). Vous serez alors en mesure de récupérer une session que vous voulez (par opposition à tricher conteneur dans le remplacement de votre session actuelle avec comme d'autres suggéré)

+0

C'est intelligent. –

+1

Ma seule préoccupation à ce sujet est la partie erreur humaine où vous aurez un développeur introduire du code en utilisant request.getSession() plutôt que d'utiliser la carte des ID de session. Je crois que la solution "plus simple" est de construire l'URL de manière appropriée. –

+0

Deux façons je peux imaginer le servlet demandant à l'auditeur pour la carte de session: listener est un singleton, ou placer la carte dans le ServletContext – rcampbell

1

Il n'y a aucun moyen au sein de la spécification de servlet, mais vous pouvez essayer:

  • réglage manuel du cookie la demande faite par Flash

  • ou en faisant comme Taylor L juste suggéré comme je tapais et en ajoutant le paramètre jsessionid le chemin de l'URI.

Les deux méthodes lieront votre application à l'exécution sur un conteneur de servlet qui se comporte comme Tomcat; Je pense que la plupart d'entre eux le font. Les deux auront également besoin de votre applet Flash demandant la page pour ses cookies, ce qui peut imposer une dépendance JavaScript.

0

Ceci est un très bon message. Un problème potentiel que je vois avec l'utilisation de l'écouteur de session pour continuer à ajouter des sessions au contexte est qu'il peut devenir assez gros en fonction du nombre de sessions simultanées que vous avez. Et puis tout le travail supplémentaire pour la configuration du serveur web pour l'auditeur.

Alors que diriez-vous de ceci pour une solution beaucoup plus simple. J'ai implémenté cela et ça marche plutôt bien. Ainsi, sur la page qui charge l'objet de téléchargement flash, stockez la session et l'ID de session en tant que paire valeur/clé dans l'objet application, puis transmettez cet ID de session à la page de téléchargement en tant que paramètre de publication. Le sur la page de téléchargement, voir si ce sessionid est déjà dans l'application, est donc utiliser cette session, sinon, obtenir celui de la demande. Aussi, alors allez-y et supprimez cette clé de l'application pour garder tout propre.

Sur la page swf:

application.setAttribute(session.getId(), session); 

ensuite sur la page de téléchargement:

Very nice guys solution. Merci pour cela.

+5

"assez gros"? Avez-vous mesuré? Connaissez-vous Java? C'est juste une référence, pas une copie de la valeur ... – BalusC

+0

Oups, vous avez raison. Je n'ai pas pensé ça. Encore, plus facile à mettre en œuvre que la suggestion originale. Aussi, depuis que j'ai entièrement testé ce code maintenant, j'ai trouvé ce qui suit. Si l'affiche originale faisait spécifiquement référence à SWFUpload, alors lorsque vous téléchargez plus d'un fichier, SWFUpload affichera chaque fichier individuellement, pas tous dans un seul article. Ainsi, en supprimant la session de l'objet application après le premier téléchargement, tous les autres ont échoué. FYI. – Garfield

2

Un moyen sûr de le faire est de définir l'ID jsession dans le cookie - c'est beaucoup plus sûr que de le définir dans l'URL.

Une fois qu'il est défini comme un cookie, vous pouvez alors récupérer la session de façon normale en utilisant

request.getSession(); 

method.setRequestHeader("Cookie", "JSESSIONID=88640D6279B80F3E34B9A529D9494E09"); 
0

Si vous utilisez Tomcat, demandez-vous tomcat directement (mais il est laid). Je parie qu'il existe d'autres solutions hacky pour d'autres serveurs Web.

Il utilise une instance de l'interface "Manager" pour gérer les sessions. Ce qui le rend laid, c'est que je n'ai pas trouvé une interface publique sympa pour pouvoir me connecter, donc nous devons utiliser la réflexion pour obtenir le manager. Ci-dessous est un écouteur de contexte qui saisit ce gestionnaire au démarrage du contexte, puis peut être utilisé pour obtenir la session Tomcat.

public class SessionManagerShim implements ServletContextListener { 
    static Manager manager; 

    @Override 
    public void contextInitialized(ServletContextEvent sce) { 
     try { 
      manager = getManagerFromServletContextEvent(sce); 
     } catch (NoSuchFieldException | IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent sce) { 
     manager = null; 
    } 

    private static Manager getManagerFromServletContextEvent(ServletContextEvent sce) throws NoSuchFieldException, IllegalAccessException { 
     // Step one - get the ApplicationContextFacade (Tomcat loves facades) 
     ApplicationContextFacade contextFacade = (ApplicationContextFacade)sce.getSource(); 

     // Step two - get the ApplicationContext the facade wraps 
     Field appContextField = ApplicationContextFacade.class.getDeclaredField("context"); 
     appContextField.setAccessible(true); 
     ApplicationContext applicationContext = (ApplicationContext) 
       appContextField.get(contextFacade); 

     // Step three - get the Context (a tomcat context class) from the facade 
     Field contextField = ApplicationContext.class.getDeclaredField("context"); 
     contextField.setAccessible(true); 
     Context context = (Context) contextField.get(applicationContext); 

     // Step four - get the Manager. This is the class Tomcat uses to manage sessions 
     return context.getManager(); 
    } 

    public static Session getSession(String sessionID) throws IOException { 
     return manager.findSession(sessionID); 
    } 
} 

Vous pouvez ajouter ceci comme écouteur dans votre fichier web.xml et cela devrait fonctionner.

Ensuite, vous pouvez le faire pour obtenir une session.

Questions connexes