#RequestMapping(method = RequestMethod.GET, value = "/add")
public ModelAndView add() throws ConferenceNotFoundException {
LOGGER.debug("Getting adding page");
return new ModelAndView("conference/add", "form", new ConferenceForm());
}
#RequestMapping(method = RequestMethod.POST, value = "/add")
public String handleAddConferenceForm(#Valid #ModelAttribute("form") ConferenceForm form,
BindingResult bindingResult,
#ModelAttribute("currentUser") CurrentUser currentUser) {
LOGGER.debug("Processing add conference form={}, bindingResult={}", form, bindingResult);
form.setHost(currentUser.getUser());
if (bindingResult.hasErrors()) {
// failed validation
return "conference/add";
}
try {
conferenceService.create(form);
} catch (Exception e) {
e.printStackTrace();
}
// ok, redirect
return "redirect:/";
}
I make spring form like above the code. And it works well like above the picture.
#RequestMapping(method = RequestMethod.GET, value = "/{id}/admin/update")
public ModelAndView update(Model model,
#PathVariable("id") Long id) throws ConferenceNotFoundException {
LOGGER.debug("Getting update page");
Conference conference = conferenceService.findById(id);
model.addAttribute("conference", conference);
return new ModelAndView("conference/update", "form", new ConferenceForm(conference));
}
#RequestMapping(method = RequestMethod.POST, value = "/{id}/admin/update")
public String handleUpdateConferenceForm(#Valid #ModelAttribute("form") ConferenceForm form,
#PathVariable("id") Long id,
BindingResult bindingResult,
#ModelAttribute("currentUser") CurrentUser currentUser) {
LOGGER.debug("Processing update conference form={}, bindingResult={}", form, bindingResult);
form.setHost(currentUser.getUser());
if (bindingResult.hasErrors()) {
// failed validation
return "conference/update";
}
try {
conferenceService.update(form, id);
} catch (Exception e) {
e.printStackTrace();
}
// ok, redirect
return "redirect:/conferences/" + id + "/admin";
}
Otherwise, above the code does not work well. It's validator works well and it update the contents. But it generate Whitelabel Error Page when validator works.
I don't know why it generate Whitelabel Error Page.
I found what the problem is.
Change BindingResult bindingResult's location.
From:
public String handleUpdateConferenceForm(#Valid #ModelAttribute("form") ConferenceForm form,
#PathVariable("id") Long id,
BindingResult bindingResult,
#ModelAttribute("currentUser") CurrentUser currentUser)
To:
public String handleUpdateConferenceForm(#Valid #ModelAttribute("form") ConferenceForm form,
BindingResult bindingResult,
Model model,
#PathVariable("id") Long id,
#ModelAttribute("currentUser") CurrentUser currentUser)
Related
So i'm trying to create a from for adding products but when i go to the url the form doesn't show any input tag only the labels
I followed this documentation : https://www.baeldung.com/spring-mvc-form-tutorial
this is the GET method
#RequestMapping(value = "/product", method = RequestMethod.GET)
public ModelAndView showForm() {
return new ModelAndView("products/CreateProduct", "produit", new Produit());
}
and this is the POST method
#RequestMapping(value = "/create-product", method = RequestMethod.POST)
public String submitproduct(#Valid #ModelAttribute("produit")Produit produit,
BindingResult result, ModelMap model) {
if (result.hasErrors()) {
return "error";
}
model.addAttribute("productID", produit.getId_produit());
model.addAttribute("productName", produit.getNom_produit());
model.addAttribute("productPrice", produit.getPrix_produit());
model.addAttribute("productDescription", produit.getDescription_produit());
model.addAttribute("productBrand", produit.getMarque_produit());
model.addAttribute("productBarCode", produit.getCodeBarre_produit());
return "products/CreateProduct";
}
I have a user registration application in spring mvc.
When saving the user class, it normally validates the user and saves according to my UserValidator class, but when editing the same user, I can't validate in the same way.it goes to endless loop.
this is the case when saving
#RequestMapping(value = "/registration", method = RequestMethod.GET)
public String registration(Model model) {
model.addAttribute("userForm", new User());
return "registration";
}
#RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(#ModelAttribute("userForm") User userForm, BindingResult bindingResult, HttpServletRequest request) {
userValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "registration";
}
userService.saveUser(userForm);
securityService.autologin(userForm.getUsername(), userForm.getPasswordConfirm());
LOGGER.info("user with username %s successfully registered", userForm.getUsername());
return "redirect:/welcome";
}
this one is the case when editing
#RequestMapping(value = {"/edit-user-{id}"}, method = RequestMethod.GET)
public String editUser(#PathVariable Long id, ModelMap model) {
User user = userService.findById(id);
if (!user.getUsername().equals(context.getUserPrincipal().getName())) {
return "login";
}
model.addAttribute("userForm", user);
model.addAttribute("edit", true);
return "registration";
}
#RequestMapping(value = {"/edit-user-{id}"}, method = RequestMethod.POST)
public String updateUser(#Valid User userForm, BindingResult bindingResult, ModelMap model, #PathVariable Long id) {
model.addAttribute("edit", true);
model.addAttribute("success", "User " + userForm.getFirstName() + " " + userForm.getLastName() + " updated successfully");
userValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "registration";
}
userService.updateUser(userForm);
return "registrationsuccess";
}
anybody please help, what is wrong with this code, when I press the edit button, it does nothing, like it falls into endless loop.
The Problem solved by changing the code
if (bindingResult.hasErrors()) {
return "registration";
}
to
if (bindingResult.hasErrors()) {
return "forward:/registration";
}
I have next working code in my SpringMVC controller:
#RequestMapping(value = "/register", method = RequestMethod.GET)
public void registerForm(Model model) {
model.addAttribute("registerInfo", new UserRegistrationForm());
}
#RequestMapping(value = "/reg", method = RequestMethod.POST)
public String create(
#Valid #ModelAttribute("registerInfo") UserRegistrationForm userRegistrationForm,
BindingResult result) {
if (result.hasErrors()) {
return "register";
}
userService.addUser(userRegistrationForm);
return "redirect:/";
}
In short create method try to validate UserRegistrationForm. If form has errors, it leaves user on the same page with filled form fields where error message will be shown.
Now I need to apply the same behaviour to another page, but here I have a problem:
#RequestMapping(value = "/buy/{buyId}", method = RequestMethod.GET)
public String buyGet(HttpServletRequest request, Model model, #PathVariable long buyId) {
model.addAttribute("buyForm", new BuyForm());
return "/buy";
}
#RequestMapping(value = "/buy/{buyId}", method = RequestMethod.POST)
public String buyPost(#PathVariable long buyId,
#Valid #ModelAttribute("buyForm") BuyForm buyForm,
BindingResult result) {
if (result.hasErrors()) {
return "/buy/" + buyId;
}
buyForm.setId(buyId);
buyService.buy(buyForm);
return "redirect:/show/" + buyId;
}
I faced with issue of dynamic url. Now if form has errors I should specify the same page template to stay on current page, but also I should pass buyId as a path variable. Where are a conflict in this two requirements. If I leave this code as is, I get an error (I'm using Thymeleaf as a template processor):
Error resolving template "/buy/3", template might not exist or might not be accessible by any of the configured Template Resolvers
I can write something like return "redirect:/buy/" + buyId, but in this case I lose all data and errors of form object.
What should I do to implement in buyPost method the same behaviour as in create method?
I tried the solution metioned in this post at this weekend, but it doesn't work for BindingResult.
The code below works but not perfect.
#ModelAttribute("command")
public PlaceOrderCommand command() {
return new PlaceOrderCommand();
}
#RequestMapping(value = "/placeOrder", method = RequestMethod.GET)
public String placeOrder(
#ModelAttribute("command") PlaceOrderCommand command,
ModelMap modelMap) {
modelMap.put(BindingResult.MODEL_KEY_PREFIX + "command",
modelMap.get("errors"));
return "placeOrder";
}
#RequestMapping(value = "/placeOrder", method = RequestMethod.POST)
public String placeOrder(
#Valid #ModelAttribute("command") PlaceOrderCommand command,
final BindingResult bindingResult, Model model,
final RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
redirectAttributes.addFlashAttribute("errors", bindingResult);
//it doesn't work when passing this
//redirectAttributes.addFlashAttribute(BindingResult.MODEL_KEY_PREFIX + "command", bindingResult);
redirectAttributes.addFlashAttribute("command", command);
return "redirect:/booking/placeOrder";
}
......
}
*I'm using Hibernate Validator APIs to validate my beans. To preserve form data along with displaying error messages, you need to do these 3 things:
Annotate your bean (eg. #NotEmpty, #Pattern, #Length, #Email etc.)
Inside controller:
#Controller
public class RegistrationController {
#Autowired
private RegistrationService registrationService;
#RequestMapping(value="register.htm", method=RequestMethod.GET, params="new")
public String showRegistrationForm(Model model) {
if (!model.containsAttribute("employee")) {
model.addAttribute("employee", new Employee());
}
return "form/registration";
}
#RequestMapping(value="register.htm", method=RequestMethod.POST)
public String register(#Valid #ModelAttribute("employee") Employee employee, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.employee", bindingResult);
redirectAttributes.addFlashAttribute("employee", employee);
return "redirect:register.htm?new";
}
registrationService.save(employee);
return "workspace";
}
// ....
}
Update your view/jsp to hold error messages:
This article can surely be helpful.
You can change your POST implementation to this:
#RequestMapping(value = "/buy/{buyId}", method = RequestMethod.POST)
public String buyPost(#PathVariable long buyId,
#Valid #ModelAttribute("buyForm") BuyForm buyForm,
BindingResult result) {
buyForm.setId(buyId); // important to do this also in the error case, otherwise,
// if the validation fails multiple times it will not work.
if (result.hasErrors()) {
byForm.setId(buyId);
return "/buy/{buyId}";
}
buyService.buy(buyForm);
return "redirect:/show/{buyId}";
}
Optionally, you can also annotate the method with #PostMapping("/buy/{buyId}") if you use Spring 4.3 or higher.
I am reading a book about spring and in the chapter about spring mvc the author list the following controller code that is responsible for form submission.
My question (since the author is not referring to it is why and where we should use HttpServletRequest)
Here is the method :
#RequestMapping(value = "/{id}", params = "form", method = RequestMethod.POST)
public String update(#Valid Contact contact, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest, RedirectAttributes redirectAttributes, Locale locale)
{
logger.info("Updating contact");
if (bindingResult.hasErrors())
{
uiModel.addAttribute("message", new Message("error", messageSource.getMessage("contact_save_fail", new Object[]{}, locale)));
uiModel.addAttribute("contact", contact);
return "contacts/update";
}
uiModel.asMap().clear();
redirectAttributes.addFlashAttribute("message", new Message("success", messageSource.getMessage("contact_save_success", new Object[]{}, locale)));
contactService.save(contact);
return "redirect:/contacts/" + UrlUtil.encodeUrlPathSegment(contact.getId().toString(), httpServletRequest);
}
Use it whenever you need to use it...
In this example, the author is using it get the character encoding :
return "redirect:/contacts/" + UrlUtil.encodeUrlPathSegment(contact.getId().toString(), httpServletRequest);
Here is the code from the UrlUtil class :
public class UrlUtil {
public static String encodeUrlPathSegment(String pathSegment, HttpServletRequest
httpServletRequest) {
String enc = httpServletRequest.getCharacterEncoding();
if (enc == null) {
enc = WebUtils.DEFAULT_CHARACTER_ENCODING;
}
try {
pathSegment = UriUtils.encodePathSegment(pathSegment, enc);
} catch (UnsupportedEncodingException uee) {
}
return pathSegment;
}
}
More information about the HttpServletRequest class :
It extends the ServletRequest interface to provide request information for HTTP servlets. You might consider reading the javadoc if you want to learn more about the methods of the class.
I have my controller:
#RequestMapping(value = "/addtimesheet", method = RequestMethod.POST)
public String addTimeSheet(#ModelAttribute("timesheet")TimeSheet timeSheet,
BindingResult bindingResult,
ModelMap model) {
if (bindingResult.hasErrors()) {
if (bindingResult.hasFieldErrors("horaInicio")){
model.addAttribute("messageHoraInicioError",HORA_INICIO_INVALIDA);
}
if (bindingResult.hasFieldErrors("horaFim")){
model.addAttribute("messageHoraFimError",HORA_FIM_INVALIDA);
}
return TIMESHEETCRUD_NOVO;
}
return TIMESHEETCRUD_LIST;
}
when I try:
/timesheet/addtimesheet
with the field "horainicio = null", my bindingResult.hasError() is true.
Well, It's work :-)
My test:
#Test
#ExpectedDatabase("timeSheetControllerIt.xml")
public void novoTimeSheetSemHoraInicial() throws Exception {
TimeSheet novoTimeSheet = new TimeSheet();
mockMvc.perform(
post("/timesheet/addtimesheet")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(super.convertObjectToFormUrlEncodedBytes(novoTimeSheet))
.sessionAttr("timesheet", novoTimeSheet)
)
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name("timesheetcrud/novo"))
.andExpect(forwardedUrl("/WEB-INF/views/timesheetcrud/novo.jsp"))
.andExpect(model().attribute("messageHoraInicioError", is("timesheetcontroller.horainicio.invalida")));
}
I saw in my controller that object "timeSheet" is "horaInicio" null, but my bindingResult.hasErrors() is false.
Anybody have idea what's wrong ?
thanks