I am trying to create user form in my application using Spring MVC and then validating the ModelAttribute. If my validations fail, I use the ModelAndView to return the view showing validation errors on form. My Controller code to render blank form is:
@GetMapping("/home")
public ModelAndView getUserHome(){
ModelAndView mv = new ModelAndView();
//In actual application, I have more code to put attributes in ModelAndView that will be needed
//on view form, like select box options
mv.addObject("user", new User());
mv.setViewName("user/home/userHome");
return mv;
}
Once the user form on view is filled in, and submit button clicked, I POST the request to the following Controller method:
@PostMapping("/persistUser")
public ModelAndView saveUser(@ModelAttribute("user") @Validated User user, BindingResult bindingResult, ModelMap modelMap){
ModelAndView mv = new ModelAndView();
List<ObjectError> errors = bindingResult.getAllErrors();
if(bindingResult.hasErrors() && !(errors.size() == 1 && errors.get(0).getCode().equals("user.system.mismatch"))){
mv.addObject("user", user);
//more code to put more attributes like select box options on view
mv.setViewName("user/home/userHome");
return mv;
}
//if no errors, I have code to persist user object here. At this point
//I sure can have userId and pass this as request attribute to redirect URL.
//But, I need to also pass some messages(based on business logic) about what selections were
//made on user form. I do not have the option to persist these selections on backend,
//as our database does not have supporting columns for that. Therefore, I need to send them as
//redirect attributes. And these messages would be displayed only once, right after the user
//object was created. Upon subsequent visits to this userId view, these messages would no longer
//be required. So we don't really need to persist them at backend.
RedirectView rv = new RedirectView("/user/home?userId="+user.getId(), true, true, false);
//Here user.getId() is the userId newly persisted.
modelMap.addAttribute("message", messageSource.getMessage("user.system.mismatch", null, Locale.US));
return new ModelAndView(rv, modelMap);
}
I get the "user" model object here, perform validations, and if errors, I send user back to the form via ModelAndView. If no errors, I have code to persist object and redirect to another view that shows the user object that was just created. On this view, I need to display some messages which I am trying to pass as redirect attributes to the redirect receiving controller method. Please read the commented lines that explain why I need to pass the messages. I wrote my Controller method as follows:
@GetMapping("/user/home")
public ModelAndView getUser(
@RequestParam(name="userId", required = true) String userId,
@RequestParam(name="message", required = false) String message,
HttpSession session){
ModelAndView mv = new ModelAndView();
User user = (User)session.getAttribute("user");
mv.addObject("message", message);
mv.setViewName("user/home/view");
return mv;
}
I have not been able to retrieve the "message" attribute here. I have tried using RedirectAttributes too, but either way I am not able to retrieve the values stored in "message". Of course I can send "message" as another request parameter, but my messages tend to be long and I don't want to see super long URLs.
Can somebody please advice how do I tackle this problem? Thanks.
RedirectAttribute
will be restored as part of the model. So no you won't be able to access it using@RequestParam
. It is already part of the implicit model. I suggest to stop usingModelAndView
and just inject what you need. If you hadd aModel
orModelMap
as method argument instead, it will already contain themessage
attribute. – M. DeinumModelMap
isMap
and has all the methods that a regularMap
has. – M. Deinum