2012-07-23 32 views
9

Tengo un objeto User almacenado en la sesión con @SessionAttributes. Y un método directo decorado con @ModelAttribute para inicializarlo cuando el valor de la sesión sea nulo.Valores de @PathVariable y @ModelAttribute superposición

clase

usuario:

@Entity 
@Table(name="USER") 
public class User implements java.io.Serializable { 

    private Long id; 
    private String username; 
    private String password; 
    .... 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name ="ID") 
    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 
    ... 

controlador:

@RequestMapping("/item") 
@Controller 
@SessionAttributes({"user"}) 
public class MyController { 

método @ModelAttribute:

@ModelAttribute("user") 
    public User createUser(Principal principal) { 
     return userService.findByUsername(principal.getName()); 
    } 

Todo parece funcionar como se esperaba, excepto en este método particular:

@RequestMapping(value = "/{id}", method = RequestMethod.GET) 
    public String showItem(@PathVariable("id") Long id, @ModelAttribute("user") User user, 
      Model uiModel) { 
    ...  
} 

El problema es que User.id se está configurando con @PathVariable("id"). Creo que me encontré con esto también con @RequestParam. Supongo que es porque ambos tienen el mismo nombre y tipo. Después de leer Spring's documentation (ver a continuación), supongo que se espera que este comportamiento:

El siguiente paso es el enlace de datos. La clase WebDataBinder coincide con los nombres de parámetros de solicitud, incluidos los parámetros de cadena de consulta y los campos de formulario, para modelar los campos de atributo por nombre. Los campos coincidentes se rellenan después de que se haya aplicado la conversión de tipo (desde String al tipo de campo de destino) cuando sea necesario.

Sin embargo, creo que este escenario es bastante común, ¿cómo lo están manejando otras personas? Si mis hallazgos son correctos y este es el comportamiento esperado (o error), esto parece ser muy propenso a errores.

soluciones posibles:

  1. Cambio @PathVariable("id") a @PathVariable("somethingElse"). Funciona, pero no es tan sencillo con @RequestParam (por ejemplo, no sé cómo cambiar el ID del parámetro de solicitud de jqgrid a otra cosa, pero este es otro problema).
  2. Cambiar @PathVariable("id") tipo de Long a Int. Esto hará que los tipos User.id y id difieran, pero el modelo a Largo se ve feo :)
  3. No utilice @ModelAttribute aquí y consulte DB nuevamente para User. No es coherente con otros métodos e implica llamadas DB redundantes.

¿Alguna sugerencia?

+0

un hack cuarta opción, lo que si se cambia el orden - '@ ModelAttribute' primero y luego' @ PathVariable' . –

+0

El resultado fue el mismo, valió la pena intentarlo. – Ulises

+0

Sí, en realidad se dio cuenta más tarde de que las propiedades coincidentes del usuario se compararán con las variables uri. Sus enfoques se ven bien, he agregado uno más como respuesta. –

Respuesta

5

¿Qué hay de este enfoque -

@RequestMapping(value = "/{id}", method = RequestMethod.GET) 
public String showItem(@PathVariable("id") Long id, 
      Model uiModel) { 
     User user = (User)uiModel.asMap().get("user"); 
    ...  
} 
+0

No está mal. Es un pequeño cambio y funciona. Pregunta rápida, no vi 'getAttribute()' en 'Model', ¿debería hacer' (User) uiModel.asMap(). Get ("user") '? – Ulises

+0

Sí, mi error! déjame editar la respuesta para cambiar esto. –

+0

+1 Me gusta su respuesta, antes de marcarla, aunque me gustaría ver si escucho más. Muchas gracias por su ayuda. – Ulises

0

uso @SessionAttribute

@RequestMapping(value = "/{id}", method = RequestMethod.GET) 
    public String showItem(@PathVariable("id") Long id, @SessionAttribute("user") User user, 
      Model uiModel) { 
    ...  
} 
Cuestiones relacionadas