I'm trying to implement P/R/G (POST/Redirect/GET) pattern in my Spring MVC application in order to avoid duplicate form submissions, only instead of showing some success view (GET), I'm redirecting to another URL (redirect:/essays/main/student/{studentId}/activity/add/existing
) for which I need to pass the complete model too. Spring docs for org.springframework.web.servlet.view.RedirectView
says:
"View that redirects to an absolute, context relative, or current request relative URL, exposing all model attributes as HTTP query parameters."
so I can retrieve serialized objects from the request and it works fine with Strings, but it does not work if I want to pass more complex objects, like in my case, couple of lists of objects (activityList
, courseList
, teacherList
).
This is how it's suppose to work:
First I show my searchActivity
view and this works fine:
@RequestMapping(value="/{studentId}/activity/search", method = RequestMethod.GET)
public String getSearchActivity(@PathVariable Integer studentId, Model model) {
StudentActivityDTO studentActivityDTO = new StudentActivityDTO();
Student student = studentService.get(studentId);
studentActivityDTO.setStudent(student);
model.addAttribute("studentActivityDTO", studentActivityDTO);
return "searchActivity";
}
This is the important part of my searchActivity
view:
<c:url var="studentUrl" value="/essays/main/student/${studentActivityDTO.student.studentId}/activity/search" />
<form:form modelAttribute="studentActivityDTO" id="myForm" method="POST" action="${studentUrl}">
...
<label for="activityDescription">Eneter search string:</label>
<input type="text" id="activityDescription" name="activityDescription">
<input type="submit" value="Submit" id="submit"/>
...
</form:form>
Then I enter a searching string (activityDescription
) and submit my form to do the actual searching (POST), which also works fine, except for the last line of code (the redirecting part):
@RequestMapping(value="/{studentId}/activity/search", method = RequestMethod.POST)
public String postSearchActivity(@PathVariable Integer studentId,
@RequestParam(value="activityDescription") String activityDescription,
@ModelAttribute("studentActivityDTO") StudentActivityDTO studentActivityDTO,
Model model) {
List<Activity> activityList = activityService.search(activityDescription);
model.addAttribute("activityList", activityList);
Student student = studentService.get(studentId);
studentActivityDTO.setStudent(student);
model.addAttribute("studentActivityDTO", studentActivityDTO);
model.addAttribute("activityDescription", activityDescription);
model.addAttribute("courseList", courseService.getAll());
model.addAttribute("teacherList", teacherService.getAll());
return "redirect:/essays/main/student/{studentId}/activity/add/existing";
// return "addExistingActivity"; <-- If I use this it works fine!
}
Now I need to pass model to some controller GET method:
@RequestMapping(value="/{studentId}/activity/add/existing", method = RequestMethod.GET)
public String getAddExistingActivity(@PathVariable Integer studentId, Model model) {
// some stuff
return "addExistingActivity";
}
The important part of addExistingActivity
view:
<c:url var="studentUrl" value="/essays/main/student/${studentActivityDTO.student.studentId}/activity/add/existing" />
<form:form modelAttribute="studentActivityDTO" id="myForm" method="POST" action="${studentUrl}">
...
<label for="activityId">Activity Id:</label>
<input type="text" id="activityId" name="activityId">
<input type="submit" id="submit" value="Submit"/>
<c:if test="${!empty activityList}">
...
</c:if>
<c:if test="${empty activityList}">
<div style="color: #ff0000">No results!</div>
</c:if>
...
</form:form>
But my lists (activityList
, courseList
, teacherList
) are not present and I always get message "No results!". I only get this in my stack trace:
[DEBUG] [http-bio-8080-exec-7 08:32:44] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'studentId' of type [java.lang.Integer] to request in view with name 'addExistingActivity'
[DEBUG] [http-bio-8080-exec-7 08:32:44] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'studentActivityDTO' of type [rs.ac.uns.tfzr.zpupin.dto.StudentActivityDTO] to request in view with name 'addExistingActivity'
[DEBUG] [http-bio-8080-exec-7 08:32:44] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'org.springframework.validation.BindingResult.studentActivityDTO' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'addExistingActivity'
But if I use return "addExistingActivity"
instead of redirect:...
everything works fine and I have this in my stack trace:
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'studentId' of type [java.lang.Integer] to request in view with name 'addExistingActivity'
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'studentActivityDTO' of type [rs.ac.uns.tfzr.zpupin.dto.StudentActivityDTO] to request in view with name 'addExistingActivity'
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'org.springframework.validation.BindingResult.studentActivityDTO' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'addExistingActivity'
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'activityList' of type [java.util.Collections$CheckedRandomAccessList] to request in view with name 'addExistingActivity'
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'activityDescription' of type [java.lang.String] to request in view with name 'addExistingActivity'
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'courseList' of type [java.util.Collections$CheckedRandomAccessList] to request in view with name 'addExistingActivity'
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'teacherList' of type [java.util.Collections$CheckedRandomAccessList] to request in view with name 'addExistingActivity'
All lists present and accounted for!
What kind of custom implementation would I need in order for this to work? Any help will be much appreciated!
Also, I know I can use flash attributes for this, but won't they disappear after hitting F5?