How to handle/display errors without a ModelAttribute in Spring MVC? - java

In my insert/edit form I have a submit button to save changes to my model attribute, while I handle delete command by a simple link.
Now I'd like to show delete errors the same way I show global errors for form submission, but it seems I cannot use BindingResult without a ModelAttribute in my controller method.
For clarity, my code is like this:
#RequestMapping(value = "/delete")
public String deleteJob(Integer jobId, BindingResult result) {
// DELETE BY ID
return "myView";
}
But as expected I get this exception:
java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be immediately after the model attribute argument in the controller method signature
Is there any way to do something similar?

you dont need the BindingResult result, what you can do is to create your errors and add them in the Errors object. and return it to your view

What you could do is add an attribute to your domain object - like "delete", bind it to a hidden field on the form and set that to true when the user clicks on the remove button and then submit it to the server to be processed as a model attribute. All validation checks and binding result will behave as expected.

Related

Spring MVC - send model to view and back to controller

I have a problem with data flow in my app..
In the controller I am taking some model from DB, then I pass it to view - here some fields are shown (not all of them), and the user is able to modify them..
Then when he submits form, the controller should update the model in db.
The problem is flow, because not all of the fields are in tags, so they won't pass after submiting the form..
The only solution I found, is to create additional tags with all of the fields, which are not used in to pass them forward..
But in case I have many fields, for example - 30, I would have to create a lot of hidden fields...
What solution do you think would be the best?
Greetings,
M.
You have 2 options
Create a #ModelAttribute annotated method to get the model object from the database for each request
Put it in the session using #SessionAttributes.
#ModelAttribute annotated method
Instead of having a GET method filling the model you can also use a #ModelAttribute annotated method. This method will be invoked before each request handling method in the controller. One thing to take care of is that the id is passed in each request.
#ModelAttribute
public YourObject modelObject(#RequestParam long id) {
return yourObjectDao.findOne(id);
}
Now you can simply remove the filling of the model from the GET method and add a #ModelAttribute annotated method argument to your POST method. Which will then use the freshly obtain object.
Drawback of this approach is that when using optimistic locking it doesn't work so well anymore because each time you get the most recent version.
Using #SessionAttributes
Annotate your controller with #SessionAttributes this instructs the web handling to store the matching model objects in the session and retrieve them from there before binding.
#SessionAttributes("yourObject")
#Controller
public class YourController { ... }
Now in your POST method add an argument of the type SessionStatus and when everything is well call the isComplete method on that object. This will cleanup any session attributes put in the session by this controller.
public String handlePost(#ModelAttribute YourObject model, BindingResult result, SessionStatus status) {
if (result.hasErrors) {
return "yourView";
} else {
status.isComplete();
yourObjectDao.save(model);
return "redirect:your-new-view";
}
}

Spring model attribute gets null within the request

I have a page with pagination links at the top.
When I click the pages it takes me from record 1-50, 51-100 and so on.
I am having issue when i click the second action like when I click page # 2 #ModelAttribute values gets null.
this is tha page url: http://localhost:8080/tax/taxedYear.html?p=2
It takes me to spring controller class with /taxedYear.html and the method is as below:
#RequestMapping(value = "/taxedYear.html", method = RequestMethod.GET)
public ModelAndView showTaxResults(#ModelAttribute("criteria")
Criteria criteria, Model model, HttpSession session, HttpServletRequest request) {
String src = criteria.getSource();
System.out.println("src === "+src);
//....
//
}
When it is called anything from criteria is null. The same method is called from the previou page and it works fine.
This happens only when I click the page urls which also calls the same method in the controller and sends page # in addition.
From Spring reference:
An #ModelAttribute on a method argument indicates the argument should be retrieved from the model. If not present in the model, the argument should be instantiated first and then added to the model.
Model is populated by controller. You assume that the model remains the same when second call is made, but apparently your assumption is wrong. Because Spring initializes the model, I believe you thought it's persistent. And it is the reasonable way, model shouldn't be persistent among HTTP calls.

Do we need similar #RequestMapping value for both http get and post when we are going to use Spring #ModelAttribute

This is the question which is pressing my head since long time a go.
Suppose I have an index page and there's login form in there.
What I noticed is that for handling #ModelAttribute I should have instantiate the object of my model first in coming Http-GET request:
#RequestMapping(value="/index", method=RequestMethod.GET)
public String renderHomePage(#ModelAttribute("userCredential") UserCredential userCredential, ....){
return "index-page";
}
and then I can fetch my Object when I post the form using HTTP-POST:
#RequestMapping(value="/index", method=RequestMethod.POST)
public String checkCredential(#ModelAttribute("userCredential") UserCredential userCredential, ....){
//do some user credential checking
return "faileOrSuccessPage";
}
and both method must have the same #RequestMapping value for the submission form to work.
now I have several question:
suppose my index page(value="/index", method=RequestMethod.GET) has 10000 hit a day, Does it mean that for each coming get request, An object of UserCredential will be created? (I want to know about object life cycle)
Is there any methodology for us to bind a #ModelAttribute object with the second method (checkCredential) only (just when we want to submit a form)?
If in my case I just have to use #RequestParam to fetch my input values, how I can validate the #RequestParam without using BindingResult and return them back to the view for show?
Regarding your questions:
.1. suppose my index page(value="/index", method=RequestMethod.GET) has 10000 hit a day, Does it mean that for each coming get request, An object of UserCredential will be created? (I want to know about object life cycle)
Yes, but it is tied to the http request scope and the object will be eligible for garbage collection as soon as your page is rendered. 10000 is a fairly small number for the JVM to handle.
.2. Is there any methodology for us to bind a #ModelAttribute object with the second method (checkCredential) only (just when we want to submit a form)?
Depends on your flow - I am assuming you are using a spring form tag to show validation errors back to the user if the user or password don't conform to certain standards you have, if that is the case you will need to set the #ModelAttribute to populate your domain object at the point of redirection back to your index page.
If on the other hand you don't intend to show feedback to your user with the original values that have been set by the user then you don't to set the ModelAttribute, you can totally ignore it and use normal form html elements instead of spring tag.
.3. If in my case I just have to use #RequestParam to fetch my input values, how I can validate the #RequestParam without using BindingResult and return them back to the view for show?
I wouldn't recommend this, a wrapper type is way better and will be validated with the registered validator and the BindingResult will cleanly have the validation errors that you can directly carry over to the UI. If you absolutely want to validate the #RequestParam on your own, you can call the validator yourself. There are ways to set more model attributes to carry back the validation exceptions and present on the UI.

Keep object in the view after refreshing when using RedirectAttributes.addFlashAttribute

Thank for Spring 3.1, I can make Post/Redirect/Get happen using RedirectAttributes.addFlashAttribute, But it seem like has small issue
here is the method that persists form object, then redirect to the view to show that form object:
#RequestMapping(value = "/{formType}/onTheEarch", method = RequestMethod.POST)
public String submitAndRedirect(SomeWebForm someWebForm,
#PathVariable("formType") String formType,
final RedirectAttributes redirectAttributes) {
// do something according to formType
// .......
redirectAttributes.addFlashAttribute("webObject", webObject);
String view = "redirect:/formType/toTheMoon";
}
here is the method to direct user to the view that shows form object
#RequestMapping(value = "/{formType}/toTheMoon", method = RequestMethod.GET)
public String submitAndRedirect(#PathVariable("formType") String formType) {
// do something according to formType
// .......
String view = "toTheMoon";
}
So far so good, but one deficiency. When I refresh the view toTheMoon, everything is gone. So the question here is
(1)How does `RedirectAttributes.addFlashAttribute` works?
(2)How can I keep the object from "FlashAttribute" even after refreshing the page?
I know for the second question, we can avoid RedirectAttributes.addFlashAttribute and just pass in any parameters in the URL to implement the RGP pattern, however, I try to avoid this as the parameter value is sensitive and should not expose to user on the browser. So what to do?
As mentioned on spring documentation chapter 17.6
Flash attributes are saved temporarily before the redirect (typically
in the session) to be made available to the request after the redirect
and removed immediately.
If you want the result to persist for few more requests, you can store them in session with some identifier, and pass only the identifier as a request parameter to the result page
Other approach I commonly do is to check whether result model exist on the result page, if not just redirect into an error page (ie: user not meant to press refresh / access the result page directly, if they do just present error). Then do a client-side refresh prevention using javascript

What causes Getting a neither bindingresult nor plain target object error in Spring MVC

I have a <form:options> in my jsp for which I have defined the path attribute. It looks like this
<form:select id="drpDwn" path="usrNm" onchange="getUserNames()">
My Controller method signature looks like this, I am just calling my service method to populate the user names
#RequestMapping(value="/usrForm", method = RequestMethod.GET, headers="Accept=application/json")
public #ResponseBody JSONArray getUserNames(#RequestParam("userId") Integer userId, OutputStream opStream){
return usrService.getUserNames(userId, opStream);
}
When I am submitting the page I am getting the error
Neither BindingResult nor plain target object for bean name 'usrNm' available as request attribute
I looked up the forum and found that I have to define the Model Attribute , but I have not understood the root cause of this issue.
Can anybody please list it down , and explain that what is it exactly that Spring is looking for
the form expects a bean called usrNm. Whichever controller directs to the page with the form should set that bean.
The controller you show is for processing the form (I assume), however it is the code that returns the view with the form on that is causing the error.

Categories

Resources