web-dev-qa-db-fra.com

Printemps - Rediriger après POST (même avec des erreurs de validation)

J'essaie de comprendre comment "conserver" le BindingResult afin qu'il puisse être utilisé dans un prochain GET via la balise Spring <form:errors>. La raison pour laquelle je veux faire cela est dû aux limitations SSL de Google App Engine. J'ai un formulaire qui est affiché via HTTP et le post est à une URL HTTPS. Si je ne fais que transférer plutôt que rediriger, l'utilisateur verra l'URL https://witely.appspot.com/my/form J'essaie d'éviter cela. Des idées comment aborder cela?

Voici ce que j'aimerais faire, mais je ne vois d'erreurs de validation que lorsque j'utilise 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";
}
57
Taylor Leese

Depuis Spring 3.1, vous pouvez utiliser RedirectAttributes. Ajoutez les attributs que vous souhaitez rendre disponibles avant de procéder à la redirection. Ajoutez les deux, le BindingResult et l'objet que vous utilisez pour valider, dans ce cas, inscrivez-vous.

Pour BindingResult, vous utiliserez le nom suivant: "org.springframework.validation.BindingResult. [Nom de votre ModelAttribute]".

Pour valider l'objet que vous utilisez, vous utiliserez le nom ModelAttribute.

Pour utiliser RedirectAttributes, vous devez ajouter ceci dans votre fichier de configuration. Entre autres choses, vous dites à Spring d’utiliser de nouvelles classes: 

<mvc:annotation-driven />

Maintenant les erreurs seront affichées où que vous soyez redirigé

@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";
}
65
Oscar

En plus de la réponse sympa d'Oscar, si vous suivez cette approche RedirectAttributes, n'oubliez pas que vous passez réellement la modelAttribute à la page redirigée. Cela signifie que si vous créez une nouvelle instance de modelAttribute pour la page redirigée (dans un contrôleur), vous perdrez les erreurs de validation. Donc, si votre méthode de contrôleur POST ressemble à ceci:

@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";
}

Ensuite, vous devrez probablement faire une modification dans votre registre de création de page GET. À partir de ceci:

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

à

@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
}

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

52
Utku Özdemir

Je me demanderais pourquoi vous avez besoin de la redirection. Pourquoi ne pas simplement soumettre à la même URL et le faire répondre différemment à un POST? Néanmoins, si vous voulez vraiment faire ceci:

@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";
}

Puis dans votre méthode "create":

model.put("register",session.getAttribute("register"));
model.put("org.springframework.validation.BindingResult.register",session.getAttribute("register"));
1
rjsang

Le seul moyen de conserver les objets entre les demandes (c.-à-d. Une redirection) consiste à stocker l'objet dans un attribut de session. Vous devez donc inclure "demande HttpServletRequest" dans les paramètres de méthode pour les deux méthodes (c'est-à-dire, obtenir et poster) et récupérer l'objet via request.getAttribute ("binding"). Cela dit, et si vous n'avez pas essayé moi-même, vous devrez peut-être trouver un moyen de relier la liaison à l'objet dans la nouvelle demande. 

Une autre façon "plus agréable" consiste à changer l'URL du navigateur à l'aide de javascript.

1
klonq

Le problème est que vous redirigez vers un nouveau contrôleur, plutôt que de rendre la vue et de renvoyer la page de formulaire traitée. Vous devez faire quelque chose dans le sens de:

String FORM_VIEW = wherever_your_form_page_resides

...

if (binding.hasErrors())
    return FORM_VIEW;

Je voudrais garder les chemins en dehors de toutes les méthodes en raison de la duplication de code de chaînes.

1
Lewis

Je ne connais pas le problème exact de Google App Engine, mais l'utilisation de ForwardedHeaderFilter peut aider à préserver le schéma d'origine utilisé par le client. Ce filtre a été ajouté à Spring Framework 4.3, mais certains conteneurs Servlet fournissent des filtres similaires et le filtre est autonome, vous pouvez donc simplement récupérer le code source si nécessaire.

0
Rossen Stoyanchev