1
votes

I'm new to Spring MVC and trying to get a Post/Redirect/Get pattern working. We're trying to implement a survey where each page can display a variable number of questions. The way I'd like to implement this is a GET handler that prepares the next survey page and then hands that off to the view. In the same Controller, have a Post handler that processes the form's answers to the survey questions, submits that to the survey service, which returns the next page of questions, and then redirects that next surveyPage to the getNextPage GET handler.

Most of it is working, except the problem is that I don't know how to hand that 'next survey page' object from the POST handler to the getNextPage GET handler in the redirect. The redirect is working; it goes from the POST method to the GET method, but the surveyPage ModelAttribute is a new object in the GET method, and not the one that was set at the end of the POST method. As you can see, I've tried using ModelAttribute, but it doesn't work. I also tried using @SessionAttributes above the class, but then got a HttpSessionRequiredException.

We didn't know how to handle the dynamic form containing a variable # of questions with Spring MVC Forms, so we just did straight JSTL. It's funky but it works. That funkiness is what resulted in using the @RequestBody and SurveyPageBean coming back with the Post. Honestly, I don't know how the SurveyPageBean is populated. It looks like some Spring MVC magic, but it's working so I'm leaving it alone for now (another developer did this and then I picked it up, and we're both new to Spring MVC). Please don't get distracted by the unusual form handling, unless that is part of the problem with the empty surveyPage ModelAttribute not being redirected.

Here's the Controller snippet:

@Controller
@RequestMapping("/surveyPage")
public class SurveyPageController{

    @RequestMapping(method=RequestMethod.GET)
    public String getNextPage(@ModelAttribute("surveyPage") SurveyPage surveyPage, Model model) {
        if(surveyPage.getPageId() == null) {
            // call to surveyService (defined elsewhere) to start Survey and get first page
            surveyPage = surveyService.startSurvey("New Survey");
        }
        model.addAttribute("surveyPage", surveyPage);
        return "surveyPage";
    }


    @RequestMapping(method=RequestMethod.POST)
    public String processSubmit(@RequestBody String body, SurveyPageBean submitQuestionBean, Model model, @ModelAttribute("surveyPage") SurveyPage surveyPage) {
        // process form results, package them up and send to service, which
        // returns the next page, if any
        surveyPage = surveyService.submitPage(SurveyPageWithAnswers);
        if (results.getPageId() == null) {
            // The survey is done
            surveyPage  = surveyService.quitSurvey(surveyId);
            return "redirect:done";
        }
        model.addAttribute("surveyPage ", surveyPage );

        return "redirect:surveyPage";       
    }
2

2 Answers

2
votes

Use Flash Attributes as shown in Warlock's Thoughts.

@RequestMapping(method = RequestMethod.POST)
public String handleFormSubmission(..., final RedirectAttributes redirectAttrs) {
    ...
    redirectAttrs.addFlashAttribute("AttributeName", value);
    return "redirect:to_some_url_handled_by_BController";
}
0
votes

Your GET takes the surveyPage as a model attribute, which means it is reading it from the URL. In the POST, rather than adding the surveyPage to the model (which is lost because you are telling the client to redirect, which creates a new request and therefore a new model) you should add the surveyPage as a query parameter in your "redirect:surveyPage" You'll have to look at how the surveyPage is constructed from the query params in order to know what to put on the query string.

If, for instance, the surveyPage is constructed from a user, page number, and question count or something, I believe you could do something like "redirect:surveyPage?userId=1234&pageNumber=5678&questionCount=12 in order to pass that model attribute along.