2009-09-30 16 views
25

Tengo un servlet que maneja una publicación de formulario multiparte. La publicación en realidad está siendo realizada por un componente de carga de archivos Flash incrustado en la página. En algunos navegadores, el POST generado por Flash no incluye el JSESSIONID, lo que me imposibilita cargar cierta información de la sesión durante la publicación.¿Cómo puedo cargar manualmente una sesión Java usando un JSESSIONID?

El componente de carga de flash incluye cookies e información de sesión dentro de un campo de formulario especial. Usando este campo de formulario, puedo recuperar el valor de JSESSIONID. El problema es que no sé cómo usar este valor de JSESSIONID para cargar manualmente esa sesión específica.

Editar - Sobre la base de la solución de ChssPly76, he creado la siguiente HttpSessionListener aplicación:

@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()); 
    } 

que se suma a todas las sesiones del ServletContext como atributos mapeados por sus identificadores únicos. Podría poner un Mapa de sesiones en el contexto, pero parece redundante. Por favor, publique cualquier pensamiento sobre esta decisión. A continuación, agregue el método siguiente a mi servlet para resolver la sesión id:

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

+1 .. muy buena pregunta – peakit

Respuesta

21

No hay API para recuperar sesión por id.

Lo que puede hacer, sin embargo, es implementar un session listener en su aplicación web y mantener manualmente un mapa de sesiones con la ID (ID de sesión se puede recuperar a través de session.getId()). Luego podrá recuperar cualquier sesión que desee (en lugar de engañar al contenedor para que reemplace su sesión actual con la que otros sugirieron)

+0

Esto es inteligente. –

+1

Mi única preocupación con esto es la porción de error humano donde tendrá un desarrollador introducir un código utilizando request.getSession() en lugar de utilizar el mapa de identificación de la sesión. Creo que la solución "más simple" es construir la URL de manera adecuada. –

+0

dos maneras en que puedo imaginar el servlet pidiendo a la escucha para el mapa de sesión: oyente es un producto único, o colocar el mapa en el ServletContext – rcampbell

1

No hay manera dentro de la especificación servlet, pero se puede probar:

  • configuración manual de la galleta en la solicitud hecha por Flash

  • o haciendo lo que Taylor L acaba de sugerir mientras escribía y agregaba el parámetro jsessionid a la ruta del URI.

Ambos métodos vincularán su aplicación a la ejecución en un contenedor de servlet que se comporta como Tomcat; Creo que la mayoría de ellos lo hacen. Ambos también requerirán que su applet de Flash solicite a la página sus cookies, lo que puede imponer una dependencia de JavaScript.

0

Esta es una publicación realmente buena. Un problema potencial que veo al usar el oyente de la sesión para seguir agregando sesiones al contexto es que puede engordar bastante dependiendo de la cantidad de sesiones simultáneas que tenga. Y luego todo el trabajo adicional para la configuración del servidor web para el oyente.

Entonces, ¿qué tal esto para una solución mucho más simple. Implementé esto y funciona bastante bien. Por lo tanto, en la página que carga el objeto de carga de flash, almacene la sesión y sessionid como un par de clave-valor en el objeto de la aplicación y luego pase el ID de la sesión a la página de carga como un parámetro de publicación. En la página de carga, vea si ese sessionid ya está en la aplicación, es así que use esa sesión, de lo contrario, obtenga la de la solicitud. Además, continúe y elimine esa clave de la aplicación para mantener todo limpio.

En la página SWF:

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

A continuación, en la página de carga:

Muy buenos chicos solución. Gracias por esto.

+5

"bastante gordo"? ¿Lo has medido? ¿Estás familiarizado con Java? Es solo una referencia, no una copia del valor ... – BalusC

+0

Vaya, tienes razón. No pensé eso a través de. Aún así, más fácil de implementar que la sugerencia original. Además, dado que ahora he probado completamente este código, he encontrado lo siguiente. Si el póster original se refería específicamente a SWFUpload, cuando cargue más de un archivo, SWFUpload publicará cada archivo individualmente, no todos en una sola publicación. Por lo tanto, al eliminar la sesión del objeto de la aplicación después de la primera carga, todas las demás fallaron. FYI. – Garfield

2

Una forma segura de hacerlo es establecer el id jsession en la cookie - esto es mucho más seguro que colocarlo en la URL.

Una vez que se establece como una galleta, a continuación, se puede recuperar la sesión de la forma habitual utilizando

request.getSession(); 

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

Si está utilizando Tomcat, Tomcat le preguntas directamente (pero es feo). Apuesto a que hay otras soluciones hacky para otros servidores web.

Utiliza una instancia de la interfaz "Administrador" para gestionar las sesiones. Lo que lo hace feo es que no he encontrado una buena interfaz pública para poder conectarme, así que tenemos que usar la reflexión para obtener el administrador.

A continuación se muestra un oyente contexto que agarra ese gestor de arranque en contexto y, a continuación, se puede utilizar para obtener la Sesión 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); 
    } 
} 

puede agregar a este como oyente en su web.xml y debería funcionar.

Luego puede hacer esto para obtener una sesión.

Cuestiones relacionadas