I have many pages with the same form where I bind my object using commandName. I try to put the object to session with name "myObject" and use it for form (commandName = "myObject"). But system throws exception (Neither BindingResult nor plain target object for bean name "myObject").
How can I bind the object to session for any controllers and requests?
That error is typical when your use a form:form tag that targets a command object that is not available in the request.
A good approach is to combine #ModelAttribute annotated method with #SessionAttributes on a Controller that intially forwards to the view that contains the form, something like
#Controller
#SessionAttributes("myObject")
public class FormController {
#ModelAttribute("myObject")
public MyObject createMyObjectBean() {
return new MyObject();
}
...
}
The initally createMyObjectBean will be called with whatever is the first request to the controller methods, but it won't be called on subsequent request as the myObject value will come from session due to #SessionAttributes
just note that for this approach to work, you must have a controller that forwards to the view that contains your form
Related
#ModelAttribute
RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method =
RequestMethod.POST)
public String processSubmit(#ModelAttribute Pet pet) { }
http://.../?name=Something&age=100
public String doSomething(#ModelAttribute User user) { }
#RequestBody
#RequestMapping(value = "/user/savecontact", method = RequestMethod.POST
public String saveContact(#RequestBody Contact contact){ }
{ "name": "Something", "age": "100" } in request body
public String doSomething(#RequestBodyUser user) { }
#ModelAttribute will take a query string. so, all the data are being pass to the server through the url
#RequestBody, all the data will be pass to the server through a full JSON body
Now which one is the best approach ???
If both are for same purpose to bind to the bean..which one is the best practice or widely used as standard practice?
Both handles multi-part file and does it both have equivalent options with one another ?
https://javabeat.net/spring-multipart-file-upload/
How do i upload/stream large images using Spring 3.2 spring-mvc in a restful way
Does any one of them has lesser capabilities then the other one? Like length limitations, method limitations. Drawbacks
Which one is more secured in terms of security ?
As the javadoc suggests, it's the usage that sets them apart, i.e., use #ModelAttribute if you want to bind the object back to the web view, if this is not needed, use #RequestBody
#RequestBody
Usecases : Restful controllers (ex: produce and consume json/xml, processing direct document download requests, searching for stuff, ajax requests )
As the name suggests the if a method argument is annotated with #RequestBody annotation Spring converts the HTTP request body to the Java type of the method argument.
Is only allowed on method parameters (#Target(value={ PARAMETER}))
The body of the request is passed through an HttpMessageConverter to resolve the method argument depending on the content type of the request.
works for Post and not Get method.
#ModelAttribute
Usecases : web app controllers (ex: binding request query parameters, populating web views with options and defaults)
Uses data binders & ConversionService
Is allowed on methods and method params(#Target(value={METHOD, PARAMETER}))
Useful when dealing with model attributes for adding and retrieving model attributes to and from the Srping’s Model object
When used on METHODS, those methods are invoked before the controller methods annotated with #RequestMapping are invoked
binds a method PARAMETER or method return value to a named model attribute & the bound named model attributes are exposed to a web view
binds request query parameters to bean
For more information on Data Binding, and Type Conversion refer: https://docs.spring.io/spring/docs/5.1.x/spring-framework-reference/core.html#validation
I have kept a map in the page model. While invoking the page, am fetching few items from database and will keep that in the map so that i will use it in the JSP. Mainly these items are used for populating options in dropdown.
#RequestMapping(value = "/initSystemPage")
public String initSystemPage(#ModelAttribute("systemModel") SystemModel systemModel, ModelMap modelMap) {
Map<String, List<DropdownVO>> data = ** fetch items from database **;
systemModel.setData(data);
return "system";
}
Upon invoking the screen, i can get the items from the model and populate the values in the dropdown. So far fine. but the issue happens if i do any action like submitting the form. As am not keep an element in the JSP corresponding to the data attribute, upon submitting the form dropdown data is not mapped to model hence it is not available in the JSP after page refresh.
I dont want to populate the items in model in every action methods. if i keep the data in session attributes, is it possible to do the populate in a common method that need to be invoked in all actions? something like init-binder
If you want to keep your current design you can make use of #SessionAttributes annotation at class level to ensure that your systemModel attribute is stored in session and is accessible for subsequent requests. However make sure that you clear the attribute when you have completed form processing using SessionStatus. For example
#Controller
#SessionAttributes("systemModel")
public SystemPageController{
#RequestMapping(value = "/initSystemPage" , method = RequestMethod.GET)
public String initSystemPage(#ModelAttribute("systemModel") SystemModel systemModel, ModelMap modelMap) {
Map<String, List<DropdownVO>> data = ** fetch items from database **;
systemModel.setData(data);
return "system";
}
}
Alternatively you can use #ModelAttribute annotation to indicate methods which should be called for every request for the Controller to add model data.
#ModelAttribute("systemModel")
public SystemModel populateSystemModel(){
//code to populate and return
}
The signature is very flexible. You can include most parameters used with #RequestMapping methods such as HttpServletRequest #RequestParam , #PathVaribale etc
I am trying to build RESTful web service by using spring 4.0
I have a controller:
#Controller
#RequestMapping("test")
public class Controller{
#RequestMapping("fetch",method=RequestMethod.GET)
#ResponseStatus(value=HttpStatus.OK)
#ResponseBody
public ResultResponse fetchController(ResultRequest req){
if((req.getName).equals("John"))
return new ResultResponse(100);
else
return new ResultResponse(0);
}
}
and my ResultRequest.class
public class ResultRequest{
private String name;
//getter,setter
}
If I hit the url to //host//contextPath/test/fetch?name=John
the controller will return the object ResultResponse(100)
my question is, there no #RequestParam or other annotation in the request parameter,
how does the spring controller know to set the query parameter "name" as the property of wrapper class
ResultRequest ?
Thanks
Spring uses implementations of an interface called HandlerMethodArgumentResolver for resolving arguments to pass to handler methods, ie. methods annotated with #RequestMapping.
One of these is a ModelAttributeMethodProcessor. Its javadoc states
Resolves method arguments annotated with #ModelAttribute and handles
return values from methods annotated with #ModelAttribute.
Model attributes are obtained from the model or if not found possibly
created with a default constructor if it is available. Once created,
the attributed is populated with request data via data binding and
also validation may be applied if the argument is annotated with
#javax.validation.Valid.
When this handler is created with annotationNotRequired=true, any
non-simple type argument and return value is regarded as a model
attribute with or without the presence of an #ModelAttribute.
Spring registers two objects of this type. One to handle parameters annotated with #ModelAttribute and one to handle ones without.
Further reading:
Form submit in Spring MVC 3 - explanation
An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the #RequestBody or the #RequestPart arguments
I am loading a user object my calling a service and then store this user as a command object in the model on GET in the controller. This user object has many properties that are not mapped in the jsp page. After submitting the form, I am getting the command object i the controller on POST. But strangely, I only see the properties in the command object which are mapped to the jsp page. All the other properties those were there when I load the object are lost. I need all the properties in object to be able to successfully save it in hte database.
Can anybody help me figure this problem? Thanks!
Update
I am adding some code to better understand it. In POST handler, I was expecting the command object to have all the properties that was loaded in GET handler in addition to the properties that are bound with jsp. Instead I am losing all propeties except those are bound to the jsp. Am I doing something wrong here?
#RequestMapping(method = RequestMethod.GET)
public String showForm(ModelMap model, HttpSession session, HttpServletRequest request) throws Exception {
UserBean user = Util.getUser(session);
UserBean command = (UserBean)userProfileService.loadByUserName(user.getUserName());
model.addAttribute("command", command);
return formView;
}
#RequestMapping(method = RequestMethod.POST)
public String onSubmit(#ModelAttribute("command") UserBean command, BindingResult result, HttpSession session) throws Exception {
UserBean user = (UserBean) command;
userProfileService.saveUser(user);
return "successView";
}
Update
I am adding some code to better understand it. In POST handler, I was expecting the command object to have all the properties that was loaded in GET handler in addition to the properties that are bound with jsp. Instead I am losing all propeties except those are bound to the jsp. Am I doing something wrong here?
#RequestMapping(method = RequestMethod.GET) public String showForm(ModelMap model, HttpSession session, HttpServletRequest request) throws Exception { UserBean user = Util.getUser(session); UserBean command = (UserBean)userProfileService.loadByUserName(user.getUserName()); model.addAttribute("command", command); return formView; }
#RequestMapping(method = RequestMethod.POST) public String onSubmit(#ModelAttribute("command") UserBean command, BindingResult result, HttpSession session) throws Exception { UserBean user = (UserBean) command; userProfileService.saveUser(user); return "successView"; }
Update
If I store the command object in session how would the jsp bind the propeties. I thought I needed to store it in model for that?
Could you explain please.
Update
storing the command object in session solves the problem. I was able to store it by using
#SessionAttributes ("command")
Thanks a lot!
That's expected behaviour. Spring does not take your existing object (how would it get it?) - it creates a new one and fills it with data.
You can use the #ModelAttribute annotated-method to specify a method which will load the existing object from storage (db?) by its ID (submitted).
#ModelAttribute annotated methods are executed before the chosen #RequestMapping annotated handler method. They effectively pre-populate the implicit model with specific attributes, often loaded from a database. Such an attribute can then already be accessed through #ModelAttribute annotated handler method parameters in the chosen handler method, potentially with binding and validation applied to it.
See 15.3.2.8 of the MVC docs
The Spring-MVC Model values become Request scope attributes in your JSP. This is a one way translation, Spring-MVC does not restore the Model values when the user POSTs a form from your page.
When I need to store information between a GET and a POST (that is, set something on a GET and read it back on a POST), I set a Session attribute.
In your case, I believe that you will need to do one of the following:
Call Util.getUser(session); in the onSubmit method.
Store the command object in the session in the showForm and retrieve it in the onSubmit method>
#ModelAttribute is used to direclty set the values in the Student object from the jsp, other wise in the servlet you have to get the properties using request.getattribute() and than call student setter method.
so u can use both the keywords in jsp page.
<form action="grade" method="get" name="contact1" modelAttribute="contact1">
</form>
or
I'm working with Spring MVC and I'd like it to bind a a persistent object from the database, but I cannot figure out how I can set my code to make a call to the DB before binding. For example, I'm trying to update a "BenefitType" object to the database, however, I want it to get the object fromthe database, not create a new one so I do not have to update all the fields.
#RequestMapping("/save")
public String save(#ModelAttribute("item") BenefitType benefitType, BindingResult result)
{
...check for errors
...save, etc.
}
There are several options:
In the simpliest case when your object has only simple properties you can bind all its properties to the form fields (hidden if necessary), and get a fully bound object after submit. Complex properties also can be bound to the form fields using PropertyEditors.
You may also use session to store your object between GET and POST requests. Spring 3 faciliates this approach with #SessionAttributes annotation (from the Petclinic sample):
#Controller
#RequestMapping("/owners/*/pets/{petId}/edit")
#SessionAttributes("pet") // Specify attributes to be stored in the session
public class EditPetForm {
...
#InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
// Disallow binding of sensitive fields - user can't override
// values from the session
dataBinder.setDisallowedFields("id");
}
#RequestMapping(method = RequestMethod.GET)
public String setupForm(#PathVariable("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet); // Put attribute into session
return "pets/form";
}
#RequestMapping(method = { RequestMethod.PUT, RequestMethod.POST })
public String processSubmit(#ModelAttribute("pet") Pet pet,
BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "pets/form";
} else {
this.clinic.storePet(pet);
// Clean the session attribute after successful submit
status.setComplete();
return "redirect:/owners/" + pet.getOwner().getId();
}
}
}
However this approach may cause problems if several instances of the form are open simultaneously in the same session.
So, the most reliable approach for the complex cases is to create a separate object for storing form fields and merge changes from that object into persistent object manually.
So I ended up resolving this by annotating a method with a #ModelAttribute of the same name in the class. Spring builds the model first before executing the request mapping:
#ModelAttribute("item")
BenefitType getBenefitType(#RequestParam("id") String id) {
// return benefit type
}
While it is possible that your domain model is so simple that you can bind UI objects directly to data model objects, it is more likely that this is not so, in which case I would highly recommend you design a class specifically for form binding, then translate between it and domain objects in your controller.
I'm a little confused. I think you're actually talking about an update workflow?
You need two #RequestMappings, one for GET and one for POST:
#RequestMapping(value="/update/{id}", method=RequestMethod.GET)
public String getSave(ModelMap model, #PathVariable Long id)
{
model.putAttribute("item", benefitDao.findById(id));
return "view";
}
then on the POST actually update the field.
In you example above, your #ModelAttribute should already be populated with a method like the above method, and the properties be bound using something like JSTL or Spring tabglibs in conjunction with the form backing object.
You may also want to look at InitBinder depending on your use case.