How we assingn value to spring form fields from reference data method on loading - spring

I have one spring form name UpdateStock.jsp
<form:form........>
<form:input path="compAmount"/>
............
</form:form>
My intent is initialize the above spring form text box by some default values from database. So I have form text tag to
<form:input path="compAmount" value=${compamount}/>
Here ${compamount} is one of the value returned from referenceData() method.
But the problem is value=${compamount} is invalid.
So I leave it and do the next thing as below:
that is initialize Object command object in reference_Data() method as below. But it is not working.
protected Map reference_Data(HttpServletRequest request, Object command,Errors errors, int page) throws Exception {
UpdateStockBean bean=new UpdateStockBean();//which is correspond to UpdateStock.jsp page
bean.setCompAmount(300);//this do not change the value of corresponding field
command=new Object();
command=(Object)bean;
}
Can you suggest solution!

It sounds like you want to some default values for some text fields of your form. If you are using SimpleFormController you can simply override the method protected Object formBackingObject(HttpServletRequest request) to populate your form with some default data in the fields of your form.
You should not use protected Map referenceData(HttpServletRequest request) method for this purpose. Because referenceData is used for providing list data for checkboxes or radio buttons. This is nicely explained in this nice article of mkyoung.
If you are using AbstractWizardFormController, still you have the methods protected Object formBackingObject(HttpServletRequest request) and protected Map referenceData(HttpServletRequest request). Because AbstractWizardFormController is a subclass of AbstractFormController, which eventually holds the above mentioned methods. Here is a sample demonstration of using AbstractWizardFormController with form baking object.
Cheers!

you can try somethig like this, you are using Map Collection:
Map yourname = new HashMap();
yourname.put("compamount", bean.getCompAmount());
So a here ${compamount} is one of the value returned from reference_Data() method.
I hope help you :)

Related

How does Spring bind form values into class variables?

If I use a form:form object in Spring, I can use the commandName in order to let Spring inject the class variable values.
However, I wonder, how does the controller catch this value?
#RequestMapping(method = RequestMethod.POST, value = "/form")
public String postForm(#ModelAttribute("item") Item item, ModelMap model)
{
return "result";
}
In the above code, the Item is injected. However, even changing the name of this variable (or removing the modelattribute), doesn't affect that this variable is injected with the form values.
Will spring just inject the values in the first model class found, from the form? How does Spring know that it has to inject the form into the Item item parameter?
At first I thought the variable in the controller (POST) should have the name of commandName of the form, but it does work with other names as well, strangely enough.
There is a dedicated section in the Spring Documentation describing the usage of #ModelAttribute on method arguments.
This process is known as Data Binding on submit and is following some conventions:
If #ModelAttribute is explicitely declared with a name on an argument (your case). In this case the submitted data of the form are copied over automatically under this name. You can check yourself that it is already there in your ModelMap model by invoking/inspecting model.get("item").
If there is no #ModelAttribute argument annotation at all, then the attribute name is assumed from the type essentially in your case type Item converts to attribute name item (camelCase notation) that is created for you holding a new Item with the form data-bind'ed fields. That is also there in the ModelMap (same check as above: model.get("item"))
Key point to realise is in all these cases DataBinding occurs before hitting your Post form RequestMapping.

How to control two operations for same url in Spring mvc?

Consider the following problem.
The user has chosen to create a document by clicking on the Create document and then he writes data into the document. The url for creating the document is /document/save.
For the subsequent write up, the existing document must be saved instead of creating a new one.
Here is my code for that.
#Controller
public MyController implements Controller, TemplateTypeAware
{
#RequestMapping("/document/save")
public String saveOrCreateDocument(#ModelAttribute DocumentWrapper wrapper, ModelAndView m)
{
if(m.getModel().get("document_id")==null)
{
Document doc=createDocument(wrapper);
m.addObject("document_id",doc.getId());
}
else
{
saveDocument(m.getModel().get("document_id"), wrapper);
}
return documentView;
}
}
Template:
<form>
<input type="hidden" name="document_id" th:value="*{document_id}"/>
<!-- other fields -->
</form>
The problem here is, I am getting document_id always null. Is there any work around for this problem?
Thanks in advance. Hope you will reply as soon as possible.
Form fields will be automatically bound to your DocumentWrapper fields if they have matching names, that means DocumentWrapper needs a field named document_id, otherwise the document_id request parameter won't be bound to your object.
Model attributes will be exposed to the view, at this point the model will be empty, you can add attributes in your handler method and they will become in your view, but request parameters won't be in the model. That explains why you always get null.
If you just need the document_id parameter, use #RequestParam:
#RequestMapping("/document/save")
public String saveOrCreateDocument(#RequestParam("document_id") Long documentId, Model m) {
...
}
Please refer to the binding section of Spring MVC: http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestparam

Spring MVC: How to retrieve data apart from the Model submitted to a view

I have the following requirement. I submit a Model object to a view as follows...
#RequestMapping(value ="/addItem", method = RequestMethod.GET)
public ModelAndView showContacts() {
ModelAndView modelAndView = new ModelAndView("addItem", "command", new Item());
return modelAndView;
}
But on post, I need to retrieve a value apart from the "Item" object (model) that is returned to me. I can't have this variable be a part of the Item model object because it does not belong there. But I need it returned in order to act on that value. How can I get about doing this ?
I.e. In my JSP file, I have the following fields...
<form:input type="text" path="val1"/>
<form:input type="text" path="val2"/>
<form:input type="text" path="val3"/>
Out of the above, only fields val1 and val2 have mappings to the Item object, where as val3 does not. Nevertheless, I need the value of val3 passed back to my controller as well. The code I have right now to handle the POST is as follows, but I can't figure out how to get the value for val3. The code does not compile right now because it says that there is no field or appropriate getter method in the Item class for val3.
#RequestMapping(value = "/postItem", method = RequestMethod.POST)
public String postItem(#ModelAttribute("item") Item item , BindingResult result) {
logger.info("Post Item:");
return "home";
}
How can I modify the above code to suite my requirement ?
Some guidance on this matter will be highly appreciated.
You can pass a map as the model, and include all sorts of different things in there. You are not limited to a single domain object, that constructor is there as a convenience, it is not the only way to do it. There is a variation of the constructor:
public ModelAndView(Object view,
Map model)
Create a new ModelAndView given a View object and a model.
Parameters:
view - View object to render (usually a Servlet MVC View object)
model - Map of model names (Strings) to model objects (Objects).
Model entries may not be null, but the model Map may be null if
there is no model data.

Spring form backing object issue

I'm struggling with the way Spring handles form backing object during a POST. ScreenObject property that has a corresponding input tag in the html form survives the post, as expected. But if a property does not have an input tag, two scenarios occur:
If property is passed in as a request parameter, it survives the post.
If property is not passed in as a request parameter, it does not survive the post.
Here's my code.
screen object
private Integer hostSiteSectionId; // no input tag but survives if passed as a request param
private String name; // input tag so survives
private String orderFactor; // input tag so survives
private Integer hostSiteId; // no input tag but survives if passed as a request param
private String hostSiteName; // no input tag and not passed as request param so does not survive
GET
#RequestMapping(method=RequestMethod.GET)
public ModelAndView edit(#RequestParam(value="hostSiteId", required=false) Integer hostSiteId, #RequestParam(value="hostSiteSectionId", required=false) Integer hostSiteSectionId, Locale locale) {
HostSiteSectionHeaderEditScreenObject screenObject=new HostSiteSectionHeaderEditScreenObject();
initializeScreenObject(hostSiteId, hostSiteSectionId, screenObject, locale, true);
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject("screenObject", screenObject);
modelAndView.setViewName(WebView.HOST_SITE_SECTION_HEADER_EDIT_PAGE.getViewName());
return modelAndView;
}
POST with CANCEL
#RequestMapping(method=RequestMethod.POST, params="cancel")
public String cancel(#ModelAttribute("screenObject") HostSiteSectionHeaderEditScreenObject screenObject) {
// logic that returns redirect
}
My initializeScreenObject() method only sets properties of the screenObject. It doesn't operate on the model. I don't see how it would interfere, so I'm not posting it's basic code.
Within this post, and it works the same in other posts, screenObject has the following:
All input provided by user in the form via input tags is present. No issue.
hostSiteId (no input tag) is present in the screenObject only if getter url included it as parameter (edit?hostSiteId=2 for example)
hostSiteSectionId (no input tag) is present in the screenObject only if getter url included it as parameter (edit?hostSiteSectionId=2 for example)
All other properties that have no corresponding input tags and are not passed in as request params are null.
To illustrate further #4. I have a screenObject.hostSiteName property which is set in initializeScreenObject() method. The view is rendered properly with <td>${screenObject.getHostSiteName()}</td>. Now I click Cancel submit control. When controller takes over the submit, this property is null.
Please explain if this is expected or not. If expected, please explain how to go about it. I figured, I could add hidden form fields for those properties that need to survive the post but it's a bit of a hack. I hope there are better answers. And how does original request parameter come into focus within the post operation..?
It sounds like expected behavior. The HostSiteSectionHeaderEditScreenObject instance passed as an argument to the POST handler method is not the same instance as the one you put in the model in the GET handler method. By default it's a new instance that Spring creates. Spring will bind values to the object's fields based on what parameters are present in the request for the POST. So if a parameter isn't present in the POST (e.g. because you didn't put an input in the HTML form for it) that field will not be set by Spring, it will just be whatever the default initial value is for the field.
It sounds like maybe what you want is to have initializeScreenObject() applied to your screen object then have the request parameter values applied after that? There are a couple ways to go about that. One would be to have a controller method annotated with #ModelAttribute:
#ModelAttribute("screenObject")
public HostSiteSectionHeaderEditScreenObject initScreenObject(#RequestParam(value="hostSiteId", required=false) Integer hostSiteId, #RequestParam(value="hostSiteSectionId", required=false) Integer hostSiteSectionId, Locale locale) {
HostSiteSectionHeaderEditScreenObject screenObject=new HostSiteSectionHeaderEditScreenObject();
initializeScreenObject(hostSiteId, hostSiteSectionId, screenObject, locale, true);
}
http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-methods
If you do that, your GET handler method could be simplified to just return a view name.

What, exactly, does a modelbinder do? How to use it effectively?

I was researching something and came across this blog post at buildstarted.com about model binders. It actually works pretty darn well for my purposes but I am not sure exactly whats going on behind the scenes. What I did was create a custom ModelBinder called USerModelBinder:
public class UserModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult value = bindingContext.ValueProvider.GetValue("id");
MyEntities db = new MyEntities();
User user = db.Users.SingleOrDefault(u => u.UserName == value.AttemptedValue);
return user;
}
}
Then in my Global.asax.cs I have:
ModelBinders.Binders.Add(typeof(User), new UserModelBinder());
My understanding is that using the model binder allows me to NOT have to use the following lines in every controller action that involves a "User". So instead of passing in an "id" to the action, the modelbinder intercepts the id, fetches the correct "item"(User in my case) and forwards it to the action for processing.
MyEntities db = new MyEntities();
User user = db.Users.SingleOrDefault(u => u.UserName == value.AttemptedValue);
I also tried using an annotation on my User class instead of using the line in Global.asax.cs:
[ModelBinder(typeof(UserModelBinder))]
public partial class User
{
}
I'm not looking for a 30 page white paper but I have no idea how the model binder does what it does. I just want to understand what happens from when a request is made to the time it is served. All this stuff "just working" is not acceptable to me, lol. Also, is there any difference between using the annotation versus adding it in Global.asax.cs? They seem to work the same in my testing but are there any gotchas?
Usually the Model Binder (in MVC) looks at you Action method and sees what it requires (as in, the objects types). It then tries to find the values from the HTTP Request (values in the HTTP Form, QueryString, Json and maybe other places such as cookies etc. using ValueProviders). It then creates a new object with the parameters that it retrieves.
IMO What you've done is not really "model binding". In the sense that you've just read the id and fetched the object from the DB.
example of usual model binding:
// class
public class SomeClass
{
public int PropA {get;set;}
public string PropB {get;set;}
}
// action
public ActionResult AddSomeClass(SomeClass classToBind)
{
// implementation
}
// pseudo html
<form action="">
<input name="PropA" type="text" />
<input name="PropB" type="text" />
</form>
if you post a form that contains the correct values (lets say you post a form with PropA and PropB ) the model binder can identify that you've sent those values in the form and build a SomeClass object.
If you really want to create a real working example you should use a strongly typed View and use HtmlHelper's EditorFor (or EditorForModel) to create all the correct names that MVC needs.
--
for reference MVC's default binder is the DefaultModelBinder, and some (there are more, you can look around in the System.Web.Mvc namespace) ValueProviders that it uses by default are the FormValueProvider and the QueryStringValueProvider
So, as I already said, how this basically works is that the default model binder reads the model that the action is recieving (say SomeClass in the example) reads what are the values that it can read (say PropA and PropB) and asks the ValueProviders for the correct values for the properties.
Also, if I recall correctly, you can also see the value providers in runtime using the ValueProviderFactories static class.
A ModelBinder looks at the arguments of the selected Controller action's method signature, then converts the values from the ValueProviders into those arguments.
This happens when the ControllerActionInvoker invokes the action associated with the ControllerContext, because the Controller's Execute() method told it to.
For more about the ASP.NET MVC execution process, see Understanding the MVC Application Execution Process

Resources