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) { ... }
Related
I would like to stay at the same page with the filled form with "wrong" data, if binding result has errors. I have this code, but i got npe and null object "employeeTripOrder". What i do wrong? I can't use the RedirectAttributes cause i have old spring version.
#RequestMapping("/editEmployeeTripOrder")
public String editEmployeeTripOrder(HttpServletRequest request,
#RequestParam("trip_cards") String tripCards,
#RequestParam("dependenceTypes") String dependenceType,
#RequestParam("dependenceOrderIds") String dependenceOrderId,
#Valid #ModelAttribute("trip_order") EmployeeTripOrder employeeTripOrder,
BindingResult bindingResult,
ModelMap modelMap) throws Exception {
if (bindingResult.hasErrors()){
modelMap.addAttribute("trip_cards", tripCards);
modelMap.addAttribute("dependenceTypes", dependenceType);
modelMap.addAttribute("dependenceOrderIds", dependenceOrderId);
modelMap.addAttribute("trip_order",employeeTripOrder);
return "redirect:/editEmployeeTripOrder";}
//*** }
I am learning spring MVC and come across these methos in spring contrller MVC 3.1
ControllerClass(){
#RequestMapping(....)
public String show( Model uiModel) {
return ".....";
}
#RequestMapping(value = "/{id}", params = "form", method = RequestMethod.POST)
public String update(#Valid Contact contact, BindingResult bindingResult, Model uiModel,
HttpServletRequest httpServletRequest, RedirectAttributes redirectAttributes, Locale locale,
#RequestParam(value="file", required=false) Part file) {
if (bindingResult.hasErrors()) {
...........
return ".....";
}
parameters like BindingResult , Model ,
HttpServletRequest , RedirectAttributes , Locale ,
#RequestParam(value="file", required=false) Part are optional but I wonder where I can find these optional parameter and under which situation it can appear in method.
Parameter:
BindingResult - imagine you have an registration-form and you would pre validate the user input, then you can use the BindingResult.
Model - After the user is registered, he wants to edit his own profile he goes to a edit site, in this site you would show the data from the user. Here you can search for the user and add the user-object to the model and in the template you can read the values from the model-attribute.
HttpServletRequest provides request information.
#RequestParam(value="file", required=false) from Spring:
annotated parameters for access to specific Servlet request parameters. Parameter values are converted to the declared method argument type
Imagine you have a table of users and you would edit one of these, you select an entry and there you can send the userId as a requestparam.
There is a similar attribute, it's called #PathVariable the main difference, the #PathVariable is mandatory. The #RequestParam is optional respectively for this exist a "fallback/default value".
The #PathVariable is a part from the url:
#RequestMapping(value = "/{login}/edit", method = RequestMethod.GET)
public ModelAndView editUserByLogin(#PathVariable("login") final String login, final Principal principal) {}
The other two I have not used yet.
#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.
In one of my controllers I have:
#RequestMapping(value = "search", method = RequestMethod.GET)
public ModelAndView searchUsers(HttpSession session, HttpServletRequest request) {
UiUserSearchCriteria userSearchCriteria = (UiUserSearchCriteria) session
.getAttribute("UsersController_userSearchCriteria");
if (null == userSearchCriteria) {
userSearchCriteria= defaultUserSearchCriteria;
}
// Here be dragons
return searchUsers(userSearchCriteria, new BeanPropertyBindingResult(userSearchCriteria,
"userSearchCriteria"), session, request);
}
#RequestMapping(value = "search", method = RequestMethod.POST)
public ModelAndView searchUsers(
#ModelAttribute("userSearchCriteria") UiUserSearchCriteria userSearchCriteria,
BindingResult bindingResult, HttpSession session, HttpServletRequest request) {
userSearchCriteriaValidator.validate(userSearchCriteria, bindingResult);
if (bindingResult.hasErrors()) {
// Here be dragons
return new ModelAndView("searchUsers");
}
ModelAndView result = new ModelAndView("redirect:listUsers");
PagedListHolder<UiUser> userList = new PagedListHolder<UiUser>(
usersService.searchUsers(userSearchCriteria));
userList.setPageSize(10);
userList.setSort(defaultSort);
userList.resort();
session.setAttribute("UsersController_userList", userList);
session.setAttribute("UsersController_userSearchCriteria", userSearchCriteria);
return result;
}
The logic is simple: when the user navigates to search page I actually perform a search with default criteria and return him a list (this is the result of requirements changing, huh).
I found a problem in this code, accidentally. When default search criteria is not valid the behavior is: navigate to search -> populate search criteria with invalid criteria -> call another method (the second one, with POST) -> perform validation -> errors are not empty, so return searchUsers view. But the BindingResult bindingResult is actually syntethic, from previous method (new BeanPropertyBindingResult(userSearchCriteria, "userSearchCriteria")). So I got an error No binding result is bound to session (I agree with this).
I cannot have #ModelAttribute and BindingResult parameters (that, which are bound by Spring) pair in GET method to call POST with them.
So what is the best solutions for this?
I think you can simply associate your new BeanPropertyBindingResult(userSearchCriteria,
"userSearchCriteria") with an appropriate Spring model attribute name, this way:
BindingResult bindingResult = new BeanPropertyBindingResult(userSearchCriteria, "userSearchCriteria")
model.addAttribute(BindingResult.MODEL_KEY_PREFIX + "userSearchCriteria", bindingResult);
This is the default Spring MVC behavior of binding the validation results of a specific model attribute and should help you avoid the No binding result.. error
I am using Spring validation(JSR 303) in one of the web apps.I have no issues when a user submits data and spring validation works pretty neat.But I have a scenario where I have to fetch data from a service and validate it and then bind them to my view.(something non-form validation).How can I use #Valid in this case or does it have to be done differently?
Here is a sample code,i started with
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ModelAndView getView(
#PathVariable("id") final String id, #User user,
HttpSession session) {
User user= getUser();
BindingResult result = new BeanPropertyBindingResult(user, "user");
validator.validate(user, result);
if(result.hasErrors()){
logger.log(Level.ERROR, "Errors");
}
ModelAndView view = new ModelAndView ("home");
view.addObject("user",user );
view.addAllObject(result.getModel());
return view;
As far as I understand you need to inject default org.springframework.validation.Validator into your controller (if #Valid works you should be able to do it)
#Autowired
Validator validator;
run validation manually as follows
User user = ...;
BindingResult result = BeanPropertyBindingResult(user, "user");
validator.validate(user, result);
and merge results into ModelMap (declare it as argument of your method) as follows
model.addAllAttributes(result.getModel());