2010-02-06 19 views
20

¿Hay alguna forma en la primavera 3.0 para acceder a HttpSession sin incluirlo en la firma del método? Lo que realmente quiero hacer es poder pasar los valores de una HttpSession que PUEDEN SER nulos.Spring MVC Session Attribute Access

Algo como esto:

@RequestMapping("/myHomePage") 
public ModelAndView show(UserSecurityContext ctx) {} 

en lugar de esto:

@RequestMapping("/myHomePage") 
public ModelAndView show(HttpSession session) { 
     UserSecurityContext ctx = (UserSecurityContext) session.getAttribute("userSecurityCtx"); 
} 
+1

relacionado: http://stackoverflow.com/questions/3621266/how-to-pass-a-session-attribute-as-method-argument-parameter-with-spring-mvc – Bozho

+0

Aquí está el boleto de primavera [# SPR- 4452] (https: //jira.springsource.org/browse/SPR-4452) para ello. Boleto upvote para una resolución más rápida. –

Respuesta

25

El @SessionAttribute anotación mencionada por @uthark no es adecuado para esta tarea - pensé que era también, pero un bit of reading sh flujos de otro modo: los atributos

sesión como se indica mediante esta anotación se corresponden con los atributos de modelo de un controlador específico , siendo almacenados de forma transparente en una sesión de conversación . Esos atributos se eliminarán una vez que el controlador indique que se ha completado su sesión conversacional . Por lo tanto, use esta facilidad para tales atributos de conversación que se supone que son almacenados temporalmente en la sesión durante el transcurso de una conversación específica con el manejador .

Para atributos de sesión permanentes, p. un objeto de autenticación de usuario, utilice el método tradicional session.setAttribute en su lugar. Alternativamente, considere usar el atributo capacidades de administración de la interfaz genérica WebRequest.

En otras palabras, es @SessionAttribute para almacenar objetos conversación MVC-modelo en la sesión (en contraposición a almacenarlos como atributos de petición). No está diseñado para usar con atributos de sesión arbitrarios. Como descubriste, solo funciona si el atributo de sesión siempre está ahí.

No estoy al tanto de cualquier otra alternativa, creo que está pegado con HttpSession.getAttribute()

+0

De hecho terminé usando parte de la solución @uthark. Para protegerse de las excepciones causadas por un objeto de contexto de usuario nulo, puse un ServletFilter al frente para asegurarme de que se llenó. Estoy de acuerdo con esta solución para este flujo de trabajo en particular, pero parece extraño que no puedas manejar un valor nulo por ti mismo en lugar de que Spring lo solucione por ti. Gracias a todos por la ayuda y el conocimiento. – Mark

+0

@Mark: Parece extraño, sí. – skaffman

+0

@skaffman ¿Hay alguna razón por la cual los documentos no aparezcan y digan controlador en lugar de usar el término 'handler'? –

5

Sí, se puede.

@SessionAttributes("userSecurityContext") 
public class UserSecurityContext { 
} 

@RequestMapping("/myHomePage") 
public String show(@ModelAttribute("userSecurityContext") UserSecurityContext u) { 
    // code goes here. 
} 

Ver para más detalles:

  1. http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/SessionAttributes.html

  2. http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/ModelAttribute.html

+0

Gracias por la respuesta. Estoy agregando mi contexto de seguridad inicialmente con session.putAttribute(). Cuando pruebo tu código, el objeto de contexto es nulo. – Mark

+3

Lo siento, esto terminó funcionando cuando agregué @SessionAttributes ("userSecurityContext") al controlador. Simplemente agregarlo al pojo UserSecurityContext real no hizo nada por mí. Sin embargo, se lanza una excepción de Spring cuando el atributo es nulo, que es lo que intento evitar. org.springframework.web.HttpSessionRequiredException: Se requiere el atributo de sesión 'userSecurityContext' - no encontrado en la sesión – Mark

+0

@Mark Si esta respuesta no es apropiada, mueva la bandera aceptada (o elimínela), como lo sugiere la respuesta a continuación (por * skaffman *). Esto es engañoso ya que muchas personas solo leen la respuesta aceptada. (¡Simplemente lea su comentario a continuación - ¡su llamada!) –

8

Se puede utilizar un RequestContextHolder:

class SecurityContextHolder { 
    public static UserSecurityContext currentSecurityContext() { 
     return (UserSecurityContext) 
      RequestContextHolder.currentRequestAttributes() 
      .getAttribute("userSecurityCtx", RequestAttributes.SCOPE_SESSION)); 
    } 
} 
... 
@RequestMapping("/myHomePage")   
public ModelAndView show() {   
    UserSecurityContext ctx = SecurityContextHolder.currentSecurityContext(); 
} 

Por cuestiones transversales tales como la seguridad de este enfoque es mejor porque no necesita modificar las firmas de su controlador.

+0

Me gusta esta solución también. Es algo similar a un patrón ThreadLocal. ¡Gracias! – Mark