Spring 4 MVC: passing multiple #modelattributes trough controllers - spring

I'm looking for a solution to pass 2 #ModelAttributes from my GET controller to my POST controller without using Session. I'm using Spring Boot and Thymeleaf.
My view is bound only to one of those but the second controller need to use them both. The problem is that the second controller reinitialize the #ModelAttribute not used in view.
The controller:
//in this controller I've initialized the first #modelAttribute
#RequestMapping(value="/simulations", method=RequestMethod.POST)
public String checkSimulationsManagerForm(#Valid #ModelAttribute("sim_manager") Simulations_manager sim_manager, BindingResult bindingResult, final RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
return "set_simulations-manager_form";
}
redirectAttributes.addFlashAttribute("sim_manager", sim_manager);
return "redirect:/simulations2";
}
//GET
#RequestMapping(value="/simulations2", method=RequestMethod.GET)
public String showSimulationsClassForm(#ModelAttribute("sim_class") Simulations_class sim_class, #ModelAttribute("sim_manager") Simulations_manager sim_manager){
//Do some stuff
return "set_simulations-class_form";
}
//POST that reinitilize the firse #ModelAttribute
#RequestMapping(value="/simulations2", method=RequestMethod.POST)
public String checkSimulationsClassForm( #Valid #ModelAttribute("sim_class") Simulations_class sim_class, BindingResult bindingResult,#ModelAttribute("sim_manager") Simulations_manager manager,final RedirectAttributes redirectAttributes) {
//ERROR IS HERE, manager attributes are all null, even if they were not.
}
The view:
<form action="simulations2" th:action="#{/simulations2}" th:object="${sim_class}" method="post">
…
</form>

Related

Neither BindingResult nor plain target object for bean name AFTER redirect

I have a form like this (in a page called add.jsp):
<form:form action="${pageContext.request.contextPath}/add" method="post" modelAttribute="addForm">
</form:form>
On GET request, i populate modelAttribute:
#RequestMapping(value ="add", method = RequestMethod.GET)
public ModelAndView add(Map<String, Object> model) {
model.put("addForm", new AddUserForm());
return new ModelAndView("add");
}
When i perform the form submitting (a POST request), i have the follow method:
#RequestMapping(value ="add", method = RequestMethod.POST)
public ModelAndView add(Map<String, Object> model, #Valid AddUserForm form, Errors errors) {
if (errors.hasErrors()) {
//model.put("addForm", new AddUserForm());
return new ModelAndView("add");
}
....
}
But i get this error: Neither BindingResult nor plain target object for bean name 'addForm' available as request attribute
My workaround is to add model.put("addForm", new AddUserForm());, the command that i have commented on POST request.... but... where is my error ?
In both case, you are returning the same view (i.e. "add") and this view contains a form with a modelAttribute="addForm" therefore the model MUST contains an object named "addForm".
If you don't wan't to populate your model with a new AddUserForm after a POST with errors, you probably should :
return another view (without the "addForm" model attribute)
or
reuse the same "addForm": model.put("addForm", form);

Spring MVC command object and redirect attributes

I have a simple scenario:
User submits form, if there are binding errors I redisplay it, otherwise I set a flash attribute and redirect to the home page. I can't get the command object and RedirectAttributes to play together though, I can either validate the command object or use redirect attributes but not both. This gives me a 400 Bad Request
#RequestMapping(value = "/set", method = RequestMethod.POST)
public String setPassword(#AuthenticationPrincipal User currentUser,
#Validated #ModelAttribute("command") SetPasswordCommand command,
RedirectAttributes redirectAttributes,
BindingResult bindingResult) {
if (bindingResult.hasErrors())
return SET_PASSWORD_VIEW_PATH;
...
redirectAttributes.addFlashAttribute("flashMessage", "Password changed");
return "redirect:/";
}
This works but without the flash attrbute:
#RequestMapping(value = "/set", method = RequestMethod.POST)
public String setPasswordPost(#AuthenticationPrincipal User currentUser,
#Validated #ModelAttribute("command") SetPasswordCommand command,
BindingResult bindingResult) {
if (bindingResult.hasErrors())
return SET_PASSWORD_VIEW_PATH;
...
return "redirect:/";
}
What is the recommended pattern for handling this sort of thing?
Your method signature is wrong, as explained here the BindingResult must directly follow the model attribute.
org.springframework.validation.Errors / org.springframework.validation.BindingResult validation results for a preceding command or form object (the immediately preceding method argument).
So moving the RedirectAttributes after the BindingResult will make it work.
#RequestMapping(value = "/set", method = RequestMethod.POST)
public String setPassword(#AuthenticationPrincipal User currentUser,
#Validated #ModelAttribute("command") SetPasswordCommand command,
BindingResult bindingResult,
RedirectAttributes redirectAttributes) { ... }

spring 4 not validate

#RequestMapping(value="/app/home/refernece",method=RequestMethod.POST)
public String processReference(HttpServletRequest request, #ModelAttribute("refernceForm") #Validated #Valid ReferenceForm referenceForm, BindingResult bindingResult, Model model){
if(!bindingResult.hasErrors()){
boolean emailExists = customerservice.customerWithEmailExists(referenceForm.getRefernceMail());
if (!emailExists) {
bindingResult.rejectValue("refernceMail", "registrationform.valid.email.exists");
}
}
System.out.print(referenceForm.getRefernceName());
if (bindingResult.hasErrors()) {
//logger.log(Level.DEBUG, "Form Errors.");
//model.addAttribute("BindingResult",bindingResult);
//model.addAttribute("refernceForm", new ReferenceForm());
return "view/app/refernce";
}
return "redirect:/home/systemschein";
}
This my handler method.
I add 2 validator to this controller but its not validating?
Your ModelAttribute name may have a typo - it says 'refernceForm' when maybe it should say 'referenceForm'. If you post the code for the ReferenceForm class we can also check what it should be validating.

Spring 3 : Binding same controller method to multiple form action

I have a controller method with RequestMapping.PUT and having a URI
#RequestMapping(value = "/add/email", method = RequestMethod.POST)
public String addNewAccountEmail(#Valid #ModelAttribute EmailClass emailObject, BindingResult bindingResult, Model model) {
return displayForm(model);
}
I have a form like :
<form:form id="add-user-email" action="/add/email" name="manageUserAddEmail" method="post" modelAttribute="accountEmail">
I want to have more form pointing to same action , but need to do different operations inside addNewAccountEmail method. So how can I achieve this in Spring ? Basically any parameter which can make me differentiate functionalities or somehow I can have multiple methods having same RequestMapping URL and Method ?
I can only use RequestMethod.POST as I have similar requirements for other methods as well.
Basically I do not want the URL to change in Browser when invoking actions, that is why I want all form actions to point to same action URL.
You could point all of your forms at the same controller method and then differentiate the form-specific functionality within that method by looking for form-specific request parameters.
Each form would need to add its own request parameter to identify it - such as:
<input type="hidden" name="form1_param" value="1"/>
And then you can vary the behaviour inside the method by inspecting the HttpServletRequest:
#RequestMapping(value = "/add/email", method = RequestMethod.POST, )
public String addNewAccountEmail(#Valid #ModelAttribute EmailClass emailObject, BindingResult bindingResult, Model model, HttpServletRequest request) {
if (request.getParameter("form1_param") != null) { // identifies 1st form
// Do something
} else if (request.getParameter("form2_param") != null) { // indentifies 2nd form
// Do something else
}
...
}
It would be cleaner however to have multiple controller methods mapped to the same path, but specify different params in the RequestMapping - to differentiate the different forms.
#RequestMapping(value = "/add/email", params="form1_param", method = RequestMethod.POST)
public String addNewAccountEmail1(#Valid #ModelAttribute EmailClass emailObject, BindingResult bindingResult, Model model) {
// Do something specific for form1
return displayForm(model);
}
And also:
#RequestMapping(value = "/add/email", params="form2_param", method = RequestMethod.POST)
public String addNewAccountEmail2(#Valid #ModelAttribute EmailClass emailObject, BindingResult bindingResult, Model model) {
// Do something specific for form2
return displayForm(model);
}
Etc.
#RequestMapping accepts arrays as parameters (with an or semantic).
#RequestMapping(
value = "/add/email",
method = { RequestMethod.POST, RequestMethod.PUT } )

Can't access Model attributes during validation

I'm using Spring 3.1 and have web pages using validation. The field-level validation, and the display of errors, works OK. My problem is with Model attributes not being available during the validation form display.
Let's say I've code:
#RequestMapping(value="/edit", method=RequestMethod.GET)
public String getEdit(#RequestParam("id") Long id, Model model) {
model.addAttribute("mytitle", "Hello There");
return "editObject"
}
#RequestMapping(value="/edit", method=RequestMethod.POST)
public String postEdit(#RequestParam("id") Long id, #Valid #ModelAttribute("object") MyData object, BindingResult result) {
if(result.hasErrors()) {
return "editObject";
}
[snip]
}
If I have an error the hasErrors() is detected and short-circuits to the map "editObject". However, the model attributes aren't available.
What do I use here? I tried adding a Model reference to the postEdit parameter list and adding in again things like the "mytitle" attribute.
Thanks,
Jerome.
When postEdit controller render the editObject view, you are in a new request, so you are loosing the model (previously set for getEdit action).
What you need to do it re-set any values needed in a new model:
#RequestMapping(value="/edit", method=RequestMethod.POST)
public String postEdit(#RequestParam("id") Long id, #Valid #ModelAttribute("object") MyData object, BindingResult result, Model model) {
if(result.hasErrors()) {
model.addAttribute("mytitle", "Hello There");
model.addAttribute("object", object);
return "editObject";
}
If you need to keep those attributes for different views you can store them in a session for example (so that you won't have to re-set them for each new request).

Resources