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

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..

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

Avoid Spring MVC form resubmission when refreshing the page

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.

Intercepting the #responsebody in spring mvc

I have a Spring MVC web application with conroller like below :
#Controller
public class ActionRestController {
#RequestMapping(value = "/list", method = GET)
#ResponseBody
public List<Action> list(Action action, SearhCriteria searchCriteria) {
List<Action> ret = new ArrayList<Action>();
// Call a service method to get the records
// Copy the records into the list
// return the list of objects
return ret;
}
The Controller is invoked when the user does a search. There are several such controllers in the app, one for each searchable entity.
For reasons that I cannot explain very well, here, I cannot modify these controllers in anyway.
But now, I have requirement in the UI to display the search criteria and the no. of records and paging details, as well. This information is not returned by the controller. The JSON returned by the Controller contains just the list of records.
I have put up a different controller which will handle the request, gets and puts the extra info in the model and forwards the request to the existing controller like below :
#Controller
public class ActionExtendedController {
#RequestMapping(value = "/searchlist", method = GET)
#ResponseBody
public List<Action> list(Action action, SearhCriteria searchCriteria, Model model) {
model.addAttribute("searchParameters", searchCriteria);
return "forward:/list";
}
Upto this point, all is well.
What I want to do is intercept the request at a point where the List is returned from the controller, before it is converted to JSON, and return a map containing the list and the search parameters.
Now since the 'immutable' controller users ResponseBody the control goes to the JacksonMessageConverter amd the response goes out from there. I have already tried the following paths and they do not work.
Interceptor - By the time I get here, the response is already written out, so there is no way to change it.
Custom ObjectMapper for the JasksonMessageConverter - Will not work, since I do not have access to the model object inside the mapper, I only have access to the list returned by the controller.
Aspect #After pointcut for the controller - I think this technique will work, but I cannot get it to work. The advise does not fire and I am sure I am missing something in the configuration.
Is there a way to get Spring AOP to fire on a annotated controller, handler method or
can anyone suggest another method of intercepting the handler return value (along with the model) ?
How about a simple delegation to the base controller in your extended controller:
#Controller
public class ActionExtendedController {
#Autowired ActionRestController baseRestController;
#Autowired MappingJacksonJsonView mappingJacksonJsonView;
#RequestMapping(value = "/searchlist", method = GET)
public View list(Action action, SearhCriteria searchCriteria, Model model) {
List<Action> actions = baseRestController.list(action, searchCriteria, model);
model.addAttribute("actions", actions);
model.addAttribute("searchParameters", searchCriteria);
return mappingJacksonJsonView;
}
this way you are delegating to the original controller, but using this new controller for the view. Just register a mappingJacksonJsonView as a bean also which will serialize all model objects (searchcriteria and actions) into the json view. You need not even return a view but can also use #ResponseBody, with a type that can hold the responses and search criteria.
Why don't you change the return type to a Map? Like:
#Controller
public class ActionRestController {
#RequestMapping(value = "/list", method = GET)
#ResponseBody
public Map<String, Object> list(Action action, SearhCriteria searchCriteria) {
Map<String, Object> map = new HashMap<String, Object>();
List<Action> ret = new ArrayList<Action>();
// Call a service method to get the records
// Copy the records into the list
// return the list of objects
map.put("searchResult",ret);
map.put("searchCriteria", searchCriteria);
return map;
}

SPRING MVC: How can I render ModelAndView into a string

Inside Controller I need to get a rendered string and do some actions with it. This string has to be rendered out of a view. Is there a simple way of doing it?
Clarification:
I have controller
#RequestMapping(value = "/")
#ResponseBody
public String renderString() {
//I NEED TO RENDER SOME CONTENT I SAVED IN A VIEW
//I DONT WANT TO RETURN THIS CONTENT BACK TO THE BROWSER
//INSTEAD I WANT TO LETS SAY SEND CONTENT VIA EMAIL
ModelAndView view = new ModelAndView("email_template", Model);
**//QUESTION IS HERE, HOW DO I GET RENDERED STRING OUT OF VIEW/MODEL?
String emailText = view.render(); ??????????**
...sendEmail(emailText);
return "Email send";
}
Hope is more clear now
As Japs told you, I'm not sure to really understand your question, but I'll go for what I think "out of a view" means.
With Spring you can add the annotation #ResponseBody to your Controller. The String returned by the method will then be the only content of the response.
Example:
#RequestMapping(value = "/")
#ResponseBody
public String renderString() {
return "Rendered String";
}
You will get "Rendered String" at screen.

Session Handling in Spring MVC 3.0

I am using session.setAttribute to store user object after login. In next controller, I have #SessionAttribute for the same user and #ModelAttribute for same object to be used in the method mapped to a RequestMapping. After login if I click any link in the user home page it give
HttpSessionRequiredException: Session attribute '' required - not found in session
I am not sure what I am doing wrong. I went through many article and question in this site as well but could find any solution. The user object which I am storing in session stores user's account details which are required in all the controller to get different information from DB. I using SessionAttribute is wrong should I use HttpSession instead in all the controller and get the object from session manually or there is a proper way to handle in spring 3.0. Please note that this user object is not backing any form just login, but contains many other details.
As help would be good.
Have a look at my (non-perfect) use of session data:
#Controller
#SessionAttributes("sharedData")
public class RegistrationFormController {
#Autowired
private SharedData sharedData; // bean with scope="session"
#RequestMapping(value = {"/registrationForm"}, method = RequestMethod.GET)
public ModelAndView newForm() {
final ModelAndView modelAndView = new ModelAndView("registrationForm");
modelAndView.addObject("registrationForm", new RegistrationForm());
// I want to render some data from this object in JSP:
modelAndView.addObject("sharedData", sharedData);
return modelAndView;
}
#RequestMapping(value = {"/registrationForm"}, method = RequestMethod.POST)
public String onRegistrationFormSubmitted(HttpServletRequest request,
#ModelAttribute("registrationForm") RegistrationForm registrationForm, BindingResult result) {
if (result.hasErrors()) {
return "registrationForm";
}
// Perform business logic, e.g. persist registration data
return "formSubmitted";
}
}

Resources