Here is an update to this same question for Spring/Spring Boot in 2023 (at least what is working for me with thymeleaf). Updating Utku Özdemir's answer:
@Valid
will automatically perform validation before entering controller and call a MethodArgumentNotValidException
upon failure, so you have to get rid of @Valid
in method definition and manually use org.springframework.validation.Validator
(that is, if you don't want to centrally handle the form errors by overwriting exceptions).
Also,BindingResult
now has a static key (MODEL_KEY_PREFIX
) you can call to get it's proper key name.
Also, use org.springframework.web.servlet.view.RedirectView
instead of a string to redirect with flashAttributes.
@Autowired
Validator validator;
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public final RedirectView submit(@ModelAttribute("register") final Register register, final BindingResult binding, RedirectAttributes attr, HttpSession session) {
//Validate manually (remember to remove @Valid in method declare)
validator.validate(register, binding);
if (binding.hasErrors()) {
attr.addFlashAttribute(BindingResult.MODEL_KEY_PREFIX+"register", binding);
attr.addFlashAttribute("register", register);
//remember to change return type of method from string to RedirectView
return new RedirectView("/register/create", true);
}
//remember to change return type of method from string to RedirectView
return new RedirectView("/register/success", true);
}
FlashAttributes are automatically added to the model in the redirected method.
That goes for both the entity (Request) and the BindingErrors for the fields. However, if (for some weird reason) you need to get them from the FlashAttributes directly (instead of just the Model), you can access them using org.springframework.web.servlet.support.RequestContextUtils
using the request. This utility is actually used for accessing custom flash attributes that you may have added in the POST because those (unlike the BindingErrors), you'll have to add manually to the model.
@RequestMapping(value = "/register/create", method = RequestMethod.GET)
public String registerCreatePage(HttpServletRequest request, Model model) {
// get the BindingResults errors from flash attributes if you want (but kind of pointless)
Map<String, ?> flashMap = RequestContextUtils.getInputFlashMap(request);
if (flashMap != null && flashMap.containsKey(BindingResult.MODEL_KEY_PREFIX + "register")) {
BindingResult fieldErrors1 = (BindingResult) flashMap.get(BindingResult.MODEL_KEY_PREFIX + "register");
}
if (flashMap != null && flashMap.containsKey("register")) {
Register register = (Register) flashMap.get("register");
}
// or just get it from the Model cause it was already added by the system
BindingResult fieldErrors2 = (BindingResult)model.asMap().get(BindingResult.MODEL_KEY_PREFIX+"register");
Register register2 = (Register)model.asMap().get("register");
//Or just return form cause thymeleaf or other view should find errors and model as is.
}