Spring MVC - send model to view and back to controller - java

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";
}
}

Related

spring accept entity in controller

Typically the spring controller method has such view:
#RequestMapping("/url")
public String getUrl([params]){
// do some stuff..
}
As params spring can accept get/post/delete .. params from request or some standart params like model, locale etc.
My question is next: can spring accept my parametr when method is invoked. like:
#RequestMapping("/profile")
public String getUserProfile(UserEntity user, [params ..]){
// do some stuff..
}
Here UserEntity user is NOT a request body, but the entity from my DB.
Scenario is next: before executing method getUserProfile, spring execute some other method, that somehow get user from DB and pass it as method param.
Is there some way to repeat this scenario in real life?
This is possible if you use Spring Data. See the documentation: http://docs.spring.io/spring-data/commons/docs/current/reference/html/#core.web
Basically, what you have to do, is to add the id as parameter, and Spring Data will then use that ID to get the entity from the database and pass it to the method:
#RequestMapping("/{id}")
public String showUserForm(#PathVariable("id") User user) {}
To enable that feature, you have to put the annotation #EnableSpringDataWebSupport onto a #Configuration class
Check here.
We can use MVC interceptors. You need to modify the Interceptor implementation. Check the request URL pattern, if it matches then call a method that returns the UserProfile object. Hope this helps.

binding and working of spring form with the back end object in SpringMVC

I am new to SpringMvc. Could anyone please explain the binding and working of spring form with the back end object in SpringMVC.
some of the doubts are
Consider the scenario, there is a form which will take user details and it will be persisted to db
1) I have seen a controller which creates User's instances and adding the attribute to ModelMap. What is the use of that?
#Controller
#RequestMapping("/form.html")
public ModelAndView form(ModelMap map){
User user= new User();
map.addAttribute("user",user);
return new ModelAndView("form","command",map);
}
2) What is the use of command here? in the form page, this 'user' object will be available?
*form.jsp
<form:form.... action="formprocess.html" commandName="user"/>
(If I want to use 'user' should it have been already created as above?)
3) Why do we use #ModelAttribute? Why do we use Model instead of ModelMap?
#Controller
#RequestMapping("/formprocess.html")
public String form(#ModelAttribute("user"User user,Model model){
model.addAttribute("username",user.getUserName());
return "formprocess";
}
could anyone please explain or provide a link which has sufficient explanations
Regarding ModelMap, model map is used to pass certain data from you controller to the view which you delegate from that controller. You add attributes from controller and later on get attributes from view page.
Regarding commandName, commandName="user" this is something that the controller uses to map the form fields to a particular bean or POJO fields. So you do not have to manually get all the request parameters and set it yo pojos when a form is submitted and controller receives the event.
Regarding #ModelAttribute, since you use #ModelAttribute("user") as method parameter, spring container will look for a a command name user from request object and map it's properties to the pojos defined in #ModelAttribute viz in your case User class.
Regarding difference between Model and ModelMap :
ModelMap subclasses LinkedHashMap, and provides some additional conveniences to make it a bit easier to use by controllers
addAttribute can be called with just a value, and the map key is then inferred from the type.
The addAttribute methods all return the ModelMap, so you can chain method called together, e.g. modelMap.addAttribute('x', x).addAttribute('y',y)
The addAttribute methods checks that the values aren't null
The generic type of ModelMap is fixed at Map<String, Object>, which is the only one that makes sense for a view model.
So nothing earth-shattering, but enough to make it a bit nicer than a raw Map. Spring will let you use either one.
You can also use the Model interface, which provides nothing other than the addAttribute methods, and is implemented by the ExtendedModelMap class which itself adds further conveniences.

#ModelAttribute execution before displaying the JSP

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.

Does Spring MVC create a new object defined as a ModelAttribute on every call?

I am working on a wizard-like set of pages, where the user has to enter bits of data in several views for a final submission, allowing them to go back-and-forth prior to the final Submit is done. I was trying to use the same Bean, defined as a ModelAttribute, for all the views, basically just passing this one Bean around like a token in which each view adds its little bit of data.
The problem is that Spring MVC seems to create a new Bean on ever call. My admittedly fuzzy understanding about the Model was that it was basically like putting something into session, and that object would be around until the session was done. This does not seem to be the case.
So, I guess the first question is...where do Model Attributes "live", and for how long? Is there a better pattern out there for implementing a wizard-like interface using just Spring MVC (I am limited and can't use Web Flow...its not an approved tool where I work)?
It is NOT a good practise to use Model Attribute as a bean. It is good for manimulating form data before they are persisted into database.
#ModelAttribute("formAttribute") is created when you have specified it in your method as parameter:
public void getForm(#ModelAttribute("formAttribute") Form form) {
}
It is created before every method call by calling its contruct:
#ModelAttribute("formAttribute")
public Form getForm() {
return new Form();
}
When it is not specified in method parameter it doesn't exist.
There is possible to add your #ModelAttribute into session by defining #SessionAttributes on your controller:
#Controller
#SessionAttributes("formAttribute")
public HelloController
Then it is initialized once, when you firstly use it, and destroyed when you destroy it by calling:
public void finalStep(SessionStatus status) {
status.setComplete();
}
I think with combination of #SessionAttributes it is possible in relatively easy way create the wizard-like flow.
If Web-flow is not an option, you can try doing this:
Store your model attribute as a session attribute, this is accomplished by adding a #SessionAttribute annotation to your controller:
#Controller
#SessionAttribute("myconversationModel")
public class MyFlowController{
#RequestMapping
public String myMethod(#ModelAttribute("myconversationModel") ConversationModel myConversationModel){
....
}
}
Then where you think you are done with the flow, just accept an additional parameter SessionStatus and call sessionStatus.complete, this will wipe the attribute from session
#RequestMapping
public String myFinalMethod(#ModelAttribute("myconversationModel") ConversationModel myConversationModel, SessionStatus sessionStatus){
sessionStatus.complete();
....
}

Best way to execute repetitive Spring controller code?

I have a library method Common.addTheUsualStuffToTheModel(model) that needs to add various attributes to the model in every controller method in my app.
#RequestMapping(value = "/everypath", method = RequestMethod.GET)
public final String everyHandler(ModelMap model)
{
model = Common.addTheUsualStuffToTheModel(model);
return "everyPage";
}
So far I have been adding this same line to every handler method:
model = Common.addTheUsualStuffToTheModel(model);
But I'm afraid this is not consistent with the principle of "write once, use everywhere".
How do I avoid repeating this code in every handler?
You can use an interceptor and <mvc:interceptors> to do that
In your interceptor you can add anything as request attribute (which is in fact where the model attributes go). The interceptor code is executed before or after each method (that matches the interceptor mapping).
If you don't necessarily need the model to be populated before the controller method, in the postHandle method you get the ModelAndView object.
What about specifying #ModelAttribute annotated reference data provider methods. If you had a base class for all of your controllers, and that base class had #ModelAttribute annotated methods then I believe that data would be available in the model for all views handled by those controllers. Have a look at 15.3.2.8 in the Spring docs.

Categories

Resources