Why does #GetMapping method return request param while sending response? - spring

I get request params as POJO and do nothing in method but in jsp shows parameter which I get from request.Why does method return my object?
Additionally, when I use primitive type or String, It doesn't return object and works perfectly
Controller
#GetMapping("/ULD_details")
public String ULD_detailGet(ActionError ID){
return "ULD_detail";
JSP
<tr>
<td >ULD id</td>
<td>${actionError.ID}</td>
</tr>
Link
http://localhost:8080/UCM-controller/ULD_details?ID=1145

It doesn't return your object. It returns the String "ULD_detail", which is the name of the view to execute.
This view is executed, and finds an actionError bean in the request attributes (i.e. in the model), because the Spring documentation about handler methods arguments says:
Any other argument
If a method argument is not matched to any of the above, by default it is resolved as an #RequestParam if it is a simple type, as determined by BeanUtils#isSimpleProperty, or as an #ModelAttribute otherwise.
And the documentation of ModelAttribute says:
The default model attribute name is inferred from the declared attribute type (i.e. the method parameter type or method return type), based on the non-qualified class name: e.g. "orderAddress" for class "mypackage.OrderAddress"

Related

#ModelAttribute for form parameter in Spring post handler: is already an attribute?

There's this Spring behaviour that I can't explain from the documentation.
I have a form, which sends a name parameter. Name is a simple bean with a value property.
The handler looks something like this:
#PostMapping("/hello")
public String onSubmit(Name name, Model model) { // 1
// public String onSubmit(#ModelAttribute Name name, Model model) { // 2
// .. stuff
return "helloView";
}
Whether I add the #ModelAttribute annotation (commented line 2) or not (line 1) doesn't make a difference: both a unit test and a JSP page indicate the name attribute is there.
Is there some default behaviour which automatically forwards incoming attributes (from the form) to the model?
For what it's worth: I can use the annotation to change the attribute name. For example: #ModelAttribute("theName") Name name would no longer provide the attribute under the name key, but instead under the theName key (as you would pretty much expect).

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.

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.

Can #RequestParam be used on non GET requests?

Spring documentation says:
Use the #RequestParam annotation to bind request parameters to a
method parameter in your controller.
AFAIK, request parameters are variables retrieved from query strings if the request method is GET. They are also the variables retrieved from the form values when the request method is POST. I've verified this using a simple JSP that displays request parameters through method request.getParameter("key").
But it seems to me that #RequestParam only works on GET method requests. It can only get values from query strings.
Is this a bug in the documentation? Can someone please cite me some documentation that describes exactly what #RequestParam is used for, what it cannot be used for, and how it gets populated?
Can I use #RequestParam for POST methods to get the form values? If I can't use #RequestParam, what else can I use? I'm trying to avoid calling request.getParameter("key").
It works with posts too. Can you post your method body and you html?
Yes it works perfectly with post method too. you can mention the method attribute of #RequestParam as RequestMethod=POST. Here is the code snippet
#RequestMapping(value="/register",method = RequestMethod.POST)
public void doRegister
(
#RequestParam("fname") String firstName,
#RequestParam("lname")String lastName,
#RequestParam("email")String email,
#RequestParam("password")String password
)
Instead of #RequestParam which binds to a single form value, you can use #ModelAttribute annotation and bind to the whole object. But it should be used in conjunction with form or bind Spring's JSTL.
Example:
- controller that calls JSP-page, it should add objects to a Model:
#RequestMapping(value="/uploadForm", method=RequestMethod.GET)
public String showUploadForm(Model model) {
Artist artist = new Artist();
Track track = new Track();
model.addAttribute("artist", artist);
model.addAttribute("track", track);
return "uploadForm";
}
JSP might look something like that:
Track Title *:
Controller that processes form submission;
#RequestMapping(value="/uploadToServer", method=RequestMethod.POST)
public String uploadToServer(#ModelAttribute("artist") Artist artist, #ModelAttribute("track") Track track) { .... }
Here I found a good explanation of using #ModelAttribute annotation - krams915.blogspot.ca

MVC Ajax Int32 error

Hi when I try to do an Ajax post to my controller I keep getting this message:
The parameters dictionary contains a
null entry for parameter 'id' of
non-nullable type 'System.Int32' for
method 'System.Web.Mvc.JsonResult
GetContactsByDepartment(Int32)' in
'Intranet.Controllers.MyController'.
An optional parameter must be a
reference type, a nullable type, or be
declared as an optional parameter.
The method head looks like this: public JsonResult GetContactsByDepartment(int id)
What am I missing? I have ensured that the id is being passed through my Jquery ajax call.
Try to rename id to for example DepartmentID.
Probably an issue with your registered routes.

Resources