I have defined #ModelAttribute in my controller, which needs to be excuted based on the requested methods output. So when I trying to accessing the my ModelAttribute from JSP, but it is producing the previous result. For example below:
class MyController{
#modelAttribute("Address")
protected getAddress(HttpRequest req){
HttpSession sess = req.getSession();
return sess.getAttribute("Address");// For example now Address is "Test Address"
}
#RequestMapping("sample.do", method=RequestMethod.GET)
public Model requestMethod(......)
{
// after execution of this method
sess.setAttribute("Address","Changed Address");
return model;// request directed to my JSP.
}
}
When I use ${Address} in my JSP, it is displaying "Test Address", I need "Changed Address" in my JSP. But my ModelAttribute is executed after the jsp is loaded. Is it possible to make this possible using #ModelAttribute, if so then how.? . Is there anyother way to acheive this apart from #ModelAttribute.?
#ModelAttribute, on a method, is used to populate the model before the request mappingmethod is called. So if multiple views need to display the address, you can add the same #ModelAttribute-annotated method in all their controllers, and the views will thus find the address in the model and will thus be able to display it.
The problem here is that your request mapping method, called after the #ModelAttribute-annotated method, changes the valud of the address, but doesn't set the new value of the address in the model. So the view still displays the old address, added to the model by the #ModelAttribute-annotated. You shouldn't have many methods changing the address, so resetting the address in the model should be done there, but not everywhere else.
That said, the address comes from the session, so it's already available for all the views anyway, without needing any #ModelAttribute-annotated method (which just stores the same address in the request as well). Just removing the #ModelAttribute-annotated method would still let you access the right address in the views, since views have access to everything stored in the session. #ModelAttribute is useful when your model must contain data that comes from, typically, the database: the method gets the data from the database, and this data is stored in the model (the request) by Spring.
Your flow and use of ModelAttribute maybe incorrect/redundant.
From the official Spring documentation
#ModelAttribute is also used at the method level to provide reference
data for the model (see the populatePetTypes() method below). ..
Note: #ModelAttribute annotated methods will be executed before the
chosen #RequestMapping annotated handler method. ...
getAddress is getting called twice:
once before requestMethod is executed (since it's annotated with RequestMapping)
and again in your jsp.
Each time it's being called it's returning an Address with "Test Address". You should remove the call in your JSP (by removing the modelAttribute on the form). In your case it's redundant since you're already putting an updated version of Address in requestMethod.
Related
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";
}
}
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.
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.
I would like to pass one ModelMap object from one controller to another one, but the problem is
1. one controller (say /upload) has been assigned to POST method i.e. #RequestMapping(value="/upload", method = RequestMethod.POST).
2. another controller (say /display) has been assigned to GET method i.e.
#RequestMapping(value="/display", method = RequestMethod.GET).
Flow of calling the contoller is from /upload to /display/. I mean after uploading the files I am redirecting it to /display controller. But as expected it give 405 error i.e. Method Not Supported Error. If both would have assigned to any one method i.e. either RequestMethod.POST or RequestMethod.GET so it would have been easier for me to pass the ModelMap object, by using forward in return statement.
So is there any approach so that I can fulfill my purpose. Passing object or value from Post to GET or vice versa. Any help would be appriciated. Thanks
First approach
Since the second method supports get request, why not use querystring like
/display?queryparam1=Hello&queryparam2=world
and you can get these values, using request object or QueryParam or PathParam
Second approach would be to put the objects in session under some pre-defined keys. And when the control falls on the second controller, the values from session can be fetched.
I've been having a problem regarding using AJAX with Spring MVC. I have a form which has a lot of fields, and each field retrieves data depending on the associated button that was clicked.
So, each one of my buttons needs to call an AJAX request. Each response will be displayed on the associated field.
I wonder if it is possible to call a different method in my Spring controller once I clicked on a different button?
In other words, I want to make multiple ajax requests to the same controller where each request will call a different method in that same controller.
See this example :
// when get account detail is clicked it will call this method
#RequestMapping(method=RequestMethod.POST)
public #ResponseBody String getAccountDetails(#RequestParam(value="accountid") String accountid){
return somefunct.getAccountDetails(accountid);
}
// when get account summary is clicked it will call this method
#RequestMapping(method=RequestMethod.POST)
public #ResponseBody String getAccountSummary(#RequestParam(value="accountid") String accountid){
return somefunct.getAccountSummary(accountid);
}
/* when submit button is clicked... Form is submitted for saving*/
#RequestMapping(method=RequestMethod.POST)
public String submitForm(){
// save here
return "myform";
};*/
Currently, I can have only one AJAX request. How can I modify this code so that I can have different functionality for different AJAX requests?
First, consider that when you retrieve data from a server without modifying the state of that server, the commonly accepted standard is to use the HTTP GET method, not POST. Thus, for your first two methods, you are misusing the HTTP Methods.
Second, you can map individual URL patterns to a specific method using the value property of the RequestMapping annotation.
Third, the most RESTful way to represent your account details resource is to use the PathVariable annotation and include your identifying accountid in the actual path:
#RequestMapping(value="/account/{accountid}/details", method = RequestMethod.GET)
public #ResponseBody String getAccountDetails(#PathVariable(value="accountid") String accountid){
return somefunct.getAccountDetails(accountid);
}
Next, you can represent your account summary using a different URL pattern where the URL is built like a tree, where the first two parts of the path are once again "Account" and the accountid:
// when get account summary is clicked it will call this method
#RequestMapping(value="/account/{accountid}/summary", method=RequestMethod.GET)
public #ResponseBody String getAccountSummary(#PathVariable(value="accountid") String accountid){
return somefunct.getAccountSummary(accountid);
}
Now, your submit method, on the other hand, has side effects. This is just a fancy way of saying that the state of your server will be different at the end of this request, and any GET requests made to that resource will be different than they were prior to the change. The appropriate HTTP method to use when modifying a resource or adding a resource to a collection is the HTTP POST Method. When replacing a collection, the HTTP Method PUT is the generally accepted method of choice.
Another differentiating factor between PUT and POST is that PUT is idempotent, meaning that the same request repeated over and over again doesn't change the state on the server. If hitting the same request multiple times creates more records, then use POST.
Lastly, this request can be mapped to a URL as well. In the example below, I've assumed you are creating a new Account record and inserting a new record in the collection of accounts in the database. Thus, I've used POST. I also modified your parameter list to use PathVariable to take the accountid from the URL path, and I added a RequestBody annotation so that you can send an object in the body of the request, which could be deserialized into a Java object:
/* when submit button is clicked... Form is submitted for saving*/
#RequestMapping(value="/account/{accountid}", method=RequestMethod.POST)
public String submitForm(#PathVariable String accountid, #RequestBody Account account){
// save here
return "myform";
}
For more information on Spring MVC, please check out the Spring documentation on Spring MVC.