Avoid Spring MVC form resubmission when refreshing the page - spring

I am using spring MVC to save the data into database. Problem is it's resubmitting the JSP page when I am refreshing the page.
Below is my code snippet
<c:url var="addNumbers" value="/addNumbers" ></c:url>
<form:form action="${addNumbers}" commandName="AddNumber" id="form1">
</<form:form>
#RequestMapping(value = "/addNumbers", method = RequestMethod.POST)
public String addCategory(#ModelAttribute("addnum") AddNumber num){
this.numSrevice.AddNumbers(num);
return "number";
}

You have to implement Post/Redirect/Get.
Once the POST method is completed instead of returning a view name send a redirect request using "redirect:<pageurl>".
#RequestMapping(value = "/addNumbers", method = RequestMethod.POST)
public String addCategory(#ModelAttribute("addnum") AddNumber num){
this.numSrevice.AddNumbers(num);
return "redirect:/number";
}
And and have a method with method = RequestMethod.GET there return the view name.
#RequestMapping(value = "/number", method = RequestMethod.GET)
public String category(){
return "number";
}
So the post method will give a redirect response to the browser then the browser will fetch the redirect url using get method since resubmission is avoided
Note: I'm assuming that you don't have any #RequestMapping at controller level. If so append that mapping before /numbers in redirect:/numbers

You can return a RedirectView from the handler method, initialized with the URL:
#RequestMapping(value = "/addNumbers", method = RequestMethod.POST)
public View addCategory(#ModelAttribute("addnum") AddNumber num,
HttpServletRequest request){
this.numSrevice.AddNumbers(num);
String contextPath = request.getContextPath();
return new RedirectView(contextPath + "/number");
}

My answer shows how to do this, including validation error messages.
Another option is to use Spring Web Flow, which can do this automatically for you.

Related

How to handle two jsp forms pages in Spring MVC controller class

I have two different jsp pages one is login.jsp and form.jsp.i want to build application like ones login success then form page will open. here i am handle two jsp pages but it will show ambiguity problem.
#RequestMapping(value = "/", method = RequestMethod.GET)
public String loginModel(Model model){
model.addAttribute("loginBean",new LoginBean());
return "login";
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public String model(Model model){
//FrontBean fBean=new FrontBean();
model.addAttribute("frontBean",new FrontBean());
return "form";
}
Here is your login page, it is your welcome page also
#RequestMapping(value = "/", method = RequestMethod.GET)
public String loginModel(Model model) {
model.addAttribute("loginBean", new LoginBean());
return "login";
}
then you should not add the same path to another method. change your other method to like this (change the mapping value to the second method)
#RequestMapping(value = "/welcome", method = RequestMethod.GET)
public String model(Model model){
//FrontBean fBean=new FrontBean();
model.addAttribute("frontBean",new FrontBean());
return "form";
}
You also need business logic to check the username and password. thereafter redirect to your welcome page like this. (your login.jsp should send the username and password to /check-user in post method)
#PostMapping("/check-user")
String checkUser(#RequestParam("userName") String userName , #RequestParam("passWord") String passWord){
if(userName.equals("Your username") && passWord.equals("Your password")){
return "redirect:welcome";
}
return "error";
}
Remember this is not a secure way to implement. it is just an example of an easy understanding. you can implement your own things. best of luck

Spring data binding with and without #modelAttribute in method parameter

I've read that adding #modelAttribute in method param binds the incoming data to the object and add it to the model object as attribute.
#RequestMapping(value = "/list", method = RequestMethod.GET)
public String list(#ModelAttribute User user) {
return "list";
}
if this is accessed via /list?name=unnamed, in list.jsp "unnamed" can be seen using {user.name} because it was added as model attribute for list.jsp. This is very clear to me.
But if i do
#RequestMapping(value = "/list", method = RequestMethod.GET)
public String list(User user) {
return "list";
}
"unnamed" can still be seen using {user.name} when accessed via /list?name=unnamed. I thought the user object will not be added into model because it does not have #ModelAttribute annotation.
Are you sure of this part of code: return "list"; ???
Seems you are returnig the String, not the object. Try it and post and both cases, I have no permissions to comment yet =\

Spring binding multiple attributes to same #ModelAttribute

I have a preview page which takes add or edit models and displays the preview.
#RequestMapping(value = "/preview", method = RequestMethod.POST)
public ModelAndView preview(#ModelAttribute("editForm") FormModel editFormModel) {
//action
}
#RequestMapping(value = "/preview", method = RequestMethod.POST)
public ModelAndView preview(#ModelAttribute("addForm") FormModel addFormModel) {
//action
}
I need to call preview from add form page and edit form page. The models I'm going to pass are same but come from different forms.
(1) Is there a way ModelAttribute supports this kind of multi-attribute name mapping?
(2) How can I think about redesigning this? Thinking about (a) Renaming the form name/attribute before form submit to use the same attribute name. (b) Remove ModelAttribute altogether - That's not an option for me as I'm using spring mvc form binding.
Note: I'm using editForm/addForm as session attributes.
Not actually solutions but work arounds.
Approach 1:
#RequestMapping(value = "/preview", method = RequestMethod.PUT)
public ModelAndView preview(#ModelAttribute("editForm") FormModel editFormModel) {
//action
}
#RequestMapping(value = "/preview", method = RequestMethod.POST)
public ModelAndView preview(#ModelAttribute("addForm") FormModel addFormModel) {
//action
}
Approach 2:
#RequestMapping(value = "/editpreview", method = RequestMethod.PUT)
public ModelAndView preview(#ModelAttribute("editForm") FormModel editFormModel) {
//action
}
#RequestMapping(value = "/addpreview", method = RequestMethod.POST)
public ModelAndView preview(#ModelAttribute("addForm") FormModel addFormModel) {
//action
}

Spring MVC: #valid validation failed: going back to same page

so,
I have Spring MVC, #Valid annotation.
On my home page I have search box, and some other stuf printed on the page which is read from database when we visit that page,
Now, when someone hits search button without putting anything the text box, .hasErrors() is true and return "index" which is same page.
the issue is that when I get back to the same page only the search box and search button and error message is there but everything else (the stuff read from database) is no more visible.
its probably because its not being served by same controller method, but what do I do to keep the page same?
Method populating the initial view:
#RequestMapping(value = "/" , method = RequestMethod.GET)
public String indexPage(Model model, HttpServletRequest request){
List<Ad> ads = adDao.getAll();
model.addAttribute(ads);
// this below is added for data binding.
model.addAttribute("adSearchForm",new AdSearchForm());
return "index";
}
Method when someone tries to search
#RequestMapping(value = "/search", method = RequestMethod.POST)
public String searchAds(Model model,#Valid #ModelAttribute("adSearchForm") AdSearchForm adSearchForm,
BindingResult result,
HttpServletRequest request
){
if(result.hasErrors()){
return "index";
}
List<Ad> ads = adDao.searchAds(adSearchForm.getSearchTerm());
model.addAttribute("searchresults",ads);
return "searchResults";
}
so when /search request is served, the data read by first method above is not visible on index page.
It just works this way. When i have more than 2/3 elements which i need to add to model and there is some form with binding result i usually create private method like this:
private void initModel(Model model)
{
model.addAttribute("attr1", //getAttrFromDb
model.addAttribute("attr2", //getAttrFromDb
//more attributes...
}
And use it in GET and POST methods..

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 } )

Resources