2010-03-30 15 views
50

Estoy tratando de averiguar cómo "preservar" el BindingResult para que pueda ser utilizado en un GET posterior a través de la etiqueta Spring <form:errors>. El motivo por el que quiero hacer esto es debido a las limitaciones de SSL de Google App Engine. Tengo un formulario que se muestra a través de HTTP y la publicación es a una URL HTTPS. Si solo reenvio en lugar de redirigir, el usuario vería la URL https://whatever.appspot.com/my/form. Estoy tratando de evitar esto. ¿Alguna idea de cómo abordar esto?Spring - Redirigir después de POST (incluso con errores de validación)

A continuación se muestra lo que me gustaría hacer, pero solo veo errores de validación cuando uso return "create".

@RequestMapping(value = "/submit", method = RequestMethod.POST) 
public final String submit(
    @ModelAttribute("register") @Valid final Register register, 
    final BindingResult binding) { 

    if (binding.hasErrors()) { 
     return "redirect:/register/create"; 
    } 

    return "redirect:/register/success"; 
} 

Respuesta

-1

Quizás esto es un poco simple, pero ¿ha intentado agregarlo a su Modelo? Es decir, incluya el Modelo en los argumentos de su método, luego agregue BindingResult a él, que luego estará disponible en su vista.

model.addAttribute("binding",binding); 

creo que puede tener que utilizar un delantero en lugar de una redirección (en mi cabeza que no puedo recordar si una redirección pierde la sesión o no — podría estar equivocado acerca de esto como que no tengo cualquier documentación a la mano, es decir, si no obtiene el BindingResult después de agregarlo al Modelo, intente utilizar un reenvío para confirmarlo).

+0

Voy a intentarlo más tarde hoy, pero ya funciona bien si lo reenvío. Intento que funcione cuando redirecciono. –

+0

Entendido, solo sugería el avance si después de agregar el BindingResult no lo ves realmente. –

+0

Lo probé y todavía no funciona en un redireccionamiento. –

1

El problema es que está redirigiendo a un nuevo controlador, en lugar de representar la vista y devolver la página del formulario procesado. Que tiene que hacer algo en la línea de:

String FORM_VIEW = wherever_your_form_page_resides 

... 

if (binding.hasErrors()) 
    return FORM_VIEW; 

Me gustaría mantener los caminos fuera de cualquier método debido a la duplicación de código de cadenas.

+2

El punto es que quiero hacer la redirección y aún mostrar los errores de formulario. Sé que funcionará bien si lo reenvío a una vista directamente. –

+0

@Lewis: gracias hombre. Esta solución me ayudó con mi problema. Tuve una "publicación" que devuelve una lista de elementos y al usuario se le redirige a una página diferente (detalles) al hacer clic en líneas de artículos individuales. Quería redirigir a la página anterior desde la página de detalles. Agregué un GET en el controlador y pasé el modelo procesado previamente a la vista inicial como usted indicó. –

1

La única manera de persistir objetos entre solicitudes (es decir, una redirección) es almacenar el objeto en un atributo de sesión. Por lo tanto, debe incluir "solicitud HttpServletRequest" en los parámetros del método para ambos métodos (es decir, get y post) y recuperar el objeto a través de request.getAttribute ("binding"). Dicho esto, y no lo he intentado por mí mismo, es posible que deba resolver cómo volver a vincular el enlace al objeto en la nueva solicitud.

Otra forma de "no-más agradable" es simplemente cambiar la URL del navegador con javascript

+0

su forma propuesta es interesante; sin embargo, creo que sería aún mejor si puede incluir algún código de muestra –

1

cuestionaría por qué necesita la redirección. ¿Por qué no simplemente enviar a la misma URL y hacer que responda de manera diferente a un POST? Sin embargo, si realmente quiere hacer esto:

@RequestMapping(value = "/submit", method = RequestMethod.POST) 
public final String submit(
    @ModelAttribute("register") @Valid final Register register, 
    final BindingResult binding, 
    HttpSession session) { 

    if (binding.hasErrors()) { 
     session.setAttribute("register",register); 
     session.setAttribute("binding",binding); 
     return "redirect:/register/create"; 
    } 

    return "redirect:/register/success"; 
} 

Luego, en el método de "crear":

model.put("register",session.getAttribute("register")); 
model.put("org.springframework.validation.BindingResult.register",session.getAttribute("register")); 
+0

Probado su método, se lanza una excepción: "Ni BindingResult ni el objeto de destino simple para el nombre de bean 'xxxx' disponible como atributo de solicitud" – user979051

+0

Muy probablemente un error en su JSP. http://www.mkyong.com/spring-mvc/spring-mvc-neither-bindingresult-nor-plain-target-object-for-bean-name-xxx-available-as-request-attribute/ – rjsang

+0

As Mi punto es agregar todos los atributos a la sesión incorrecta (a menos que sea necesario). Los FlashAttributes pueden usarse una vez, por lo que me gustaría usarlo más que la sesión. Pero depende de tu aspecto de desarrollo. Utilizo FlashAttributes cuando uso solo jsp para enviar formularios y Mostrar mensajes correctos o fallidos sin usar JavaScript. –

59

desde la primavera de 3,1 se puede utilizar RedirectAttributes. Agregue los atributos que desea tener disponibles antes de hacer la redirección. Agregue ambos, BindingResult y el objeto que está utilizando para validar, en este caso Register.

Para BindingResult utilizará el nombre: "org.springframework.validation.BindingResult. [Nombre de su ModelAttribute]".

Para el objeto que está utilizando para validar utilizará el nombre de ModelAttribute.

Para utilizar RedirectAttributes debe agregar esto en su archivo de configuración.Entre otras cosas le está diciendo a la primavera para usar algunas clases nuevas:

<mvc:annotation-driven /> 

Ahora se mostrarán los errores donde está redirigiendo

@RequestMapping(value = "/submit", method = RequestMethod.POST) 
public final String submit(@ModelAttribute("register") @Valid final Register register, final BindingResult binding, RedirectAttributes attr, HttpSession session) { 

if (binding.hasErrors()) { 
    attr.addFlashAttribute("org.springframework.validation.BindingResult.register", binding); 
    attr.addFlashAttribute("register", register); 
    return "redirect:/register/create"; 
} 

return "redirect:/register/success"; 
} 
+3

Vale la pena señalar que los RedirectAttributes no funcionan junto con el concepto (obsoleto?) ModelAndView. Suponen que su método devuelve una cadena simple, como lo hace el ejemplo anterior. – kevinmrohr

+0

Después de esto (en mi caso), el atributo ahora está en el modelo del controlador que maneja la redirección, pero el resultado vinculante no tiene errores. Tuve que pasar la lista de errores y agregarlos a los resultados vinculantes como este: https://gist.github.com/OscarRyz/6381954 – OscarRyz

+2

al hacer esto obtengo el error: java.io.NotSerializableException: org.springframework. formato.soporteDefaultFormattingConversionService – Jens

45

Además de buena respuesta de Oscar, si usted está siguiendo ese RedirectAttributes enfoque, no olvide que en realidad está pasando el modelAttribute a la página redirigida. Esto significa que si crea una nueva instancia de ese modeloAttribute para la página redirigida (en un controlador), , perderá los errores de validación. Por lo tanto, si tu post método controlador es algo como esto:

@RequestMapping(value = "/submit", method = RequestMethod.POST) 
public final String submit(@ModelAttribute("register") @Valid final Register register, final BindingResult binding, RedirectAttributes attr, HttpSession session) { 

if (binding.hasErrors()) { 
    attr.addFlashAttribute("org.springframework.validation.BindingResult.register", binding); 
    attr.addFlashAttribute("register", register); 
    return "redirect:/register/create"; 
} 

return "redirect:/register/success"; 
} 

entonces probablemente va a tener que hacer una modificación en su registro de crear la página GET controlador. A partir de esto:

@RequestMapping(value = "/register/create", method = RequestMethod.GET) 
public String registerCreatePage(Model model) { 
    // some stuff 
    model.addAttribute("register", new Register()); 
    // some more stuff 
} 

a

@RequestMapping(value = "/register/create", method = RequestMethod.GET) 
public String registerCreatePage(Model model) { 
    // some stuff 
    if (!model.containsAttribute("register")) { 
     model.addAttribute("register", new Register()); 
    } 
    // some more stuff 
} 

Fuente: http://gerrydevstory.com/2013/07/11/preserving-validation-error-messages-on-spring-mvc-form-post-redirect-get/

+0

Esto lo resolvió para mí. El artículo vinculado lo explica aún mejor. Gracias. – adnans

+4

Peligro común: cambie "registro" en "org.springframework.validation.BindingResult.register" al nombre de su modeloAttribute – borjab

+0

¡Este es un enfoque más correcto !!!!!!!! No vi esta respuesta y estaba luchando con @Oscar answer, una sugerencia, para oscar que por favor agregue esta respuesta a su respuesta para que su respuesta esté completa y nadie tenga dificultades como yo. :) gracias chicos ahorraron mi tiempo. –

0

No sé exactamente el problema con Google App Engine, pero utilizando el ForwardedHeaderFilter puede ayudar a preservar el esquema original que la cliente utilizado. Este filtro se agregó en Spring Framework 4.3, pero algunos contenedores Servlet proporcionan filtros similares y el filtro es autosuficiente, por lo que también puede obtener la fuente si es necesario.

Cuestiones relacionadas