I noticed that when a Form Submit happens, my handler method that captures a #Model object as a parameter does have a valid Model available to me, e.g.
public ModelAndView save(final HttpServletRequest request,
#ModelAttribute(MODEL_NAME) MyModel model,
BindingResult bindingResult)
But when I have a handler method corresponding to a URL redirect from a simple <a href=".."> button/link, e.g.
<a href="myController.do&function=add">
leading to
#RequestMapping(params = "function=add")
public ModelAndView add(final HttpServletRequest request,
#ModelAttribute(MODEL_NAME) MyModel model) throws Exception
in that case, the model object is NULL. The model wasn't carried through the request and made available to me in the handler method.
Is there a way to reexpose the model? I do have the same param in both methods, but in the 2nd one the "model" object is NULL.
If you want to use GET request with you will need to add the model to the URL. Or you can use POST with a form instead.
See: how to pass a java object from jsp to spring controller on clicking a link
Related
In Springboot 2.7 I have a simple controller that dinamically sets up a page using a static resource:
#RequestMapping(value = "/controller-first", method = RequestMethod.GET)
public ModelAndView controller-first( Locale locale,
HttpServletRequest request,
HttpServletResponse response,
Model model)
{
dinamically manipulate model here...
return new ModelAndView("static_resource_here");
}
With this controller I have a form and submit that calls the second controller. The second controller should keep the ModelAndView from the first controller, modify the ModelAndView and send it to the user. Which is the best solution to implement such controller?
I got it. In the second controller I added a RedirectAttributes, then in the body I write:
//for each attribute changed
attributes.addFlashAttribute("attribute_name", model.getAttribute("name"));
//now redirect to the first controller
return new ModelAndView("redirect:/controller-first");
I have a form, but when I submit it, my initbinder doesn't intercept my post request.
This is my initbinder:
#InitBinder(value="confermaDto")
protected void initBinderDto(final WebDataBinder binder, final Locale locale) {
binder.registerCustomEditor(MyClass.class, myClassEditor);
}
And this is my method to intercept the post:
#RequestMapping(value="confermaDati", method = RequestMethod.POST)
public String confermaDati(#Valid final ConfermaDatiAttrezzaturaDto confermaDto,
final BindingResult bindingResult, final Model uiModel, final HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
uiModel.addAttribute("message", "Errore Salvataggio");
uiModel.addAttribute("dto", confermaDto);
}
uiModel.asMap().clear();
return "redirect:/";
}
I think, that it should work because the value in initbinder, and the name of my model attribure are equal.
So why don't it work??
Thank you
The names of command/form attributes and/or request parameters that this init-binder method is supposed to apply to.
Default is to apply to all command/form attributes and all request parameters processed by the annotated handler class. Specifying model attribute names or request parameter names here restricts the init-binder method to those specific attributes/parameters, with different init-binder methods typically applying to different groups of attributes or parameters.
Above is from the javadoc of #InitBinder.
In your code you specify the name of a model attribute to use, namely confermaDto. However in your request handling method there is no notion of a model attribute (i.e. nothing is annotated with #ModelAttribute).
public String confermaDati(#Valid final ConfermaDatiAttrezzaturaDto confermaDto, final BindingResult bindingResult, final Model uiModel, final HttpServletRequest httpServletRequest) { ... }
You have a argument annotated with #Valid which will only trigger validation, Spring will also instantiate this object and put values from the request onto it however it is NOT designated as a model attribute. Next to your #Valid annotation add the #ModelAttribute annotation. (Or remove the name from the #InitBinder annotation so that it will always be applied).
I think, that it should work because the value in initbinder, and the name of my model attribute are equal. So why don't it work??
In short to answer this question, the method argument name is equal but there is no model attribute. Hence no triggering of the #InitBinder method.
If you do not specify a ModelAttribute value into RequestMapping annotated method You have to specify in value attribute of #Initbinder anotation the class required name with first letter NOT capitalized.
I have a controller which has multiple actions and corresponding #modelattribute methods. One of the methods output is a input to the next method. However the value was never getting set. When I debugged, I found that the order in which the methods are called are not what I expected. Is it anyway related to the command name #ModelAttribute("nominationCommand") or the method name. What drives this?
#ModelAttribute("awardCommand")
public AwardCommand getAwardList(HttpServletRequest request, HttpSession session, Model model) {
#ModelAttribute("associateDetails")
public List<AssociateDetailsCommand> getAssociateList (HttpServletRequest request, HttpSession session, Model model) {
#ModelAttribute("achievementCommand")
public AchievementDetailsCommand getAchievementDetails(HttpServletRequest request, Model model) {
#ModelAttribute("departmentCommand")
public List<DepartmentCommand> getDepartmentList(HttpServletRequest request,HttpSession session, Model model) {
I need the methods to be called in the same order as listed above. But the third method is called, before the second one.
Need your help.
Spring is using Java Reflection for getting list of methods. In most cases it's quite unpredictable in terms of JDK.
The most common workaround is to replace #ModelAttribute with corresponding model in controller's handler.
#RequestParam("/example/view")
public ModelAndView view(HttpServletRequest request, Model model /*probably some more parameters*/){
model.put("awardCommand", getAwardCommand());
model.put("achievementCommand", getAchievementCommand());
///... TODO put other
}
I'm trying to use an Object as the command object of a <%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>element.
In the controller's GET method, I add the Object like this:
#RequestMapping(method = RequestMethod.GET)
public String renderForm(ModelMap model, HttpServletRequest request) {
[...]
model.addAttribute("voting", voting);
[...]
}
The rendered form does show the command object correctly when defined like this:
<form:form action="vote" method="PUT" commandName="voting" name="oform">
Now when trying to access the form's command object back in the controller, on the POST method, I have two approaches. First, I declare the #ModelAttribute in the signature:
#RequestMapping(method = RequestMethod.PUT)
public String newVoting(#ModelAttribute("voting") Voting voting, HttpServletRequest request) { [...]}
Or I access the ModelMap and get the value from the underlying map:
#RequestMapping(method = RequestMethod.PUT)
public String newVoting(ModelMap model, HttpServletRequest request) {
Voting voting = (Voting) model.get("voting");
[...]
}
When doing the first, I get the object as it was submitted by the form. Doing the latter, I get the object as it was BEFORE being handled by the form.
Why does the form's submit not change the object in the ModelMap and why does the #ModelAttribute differ from whats in the actual model? I feel like the name 'ModelAttribute' should result in the same object like getting the object directly from the model.
Maybe #ModelAttribute is kind of misleading?
EDIT
Forgot to mention that the object is a #SessionAttributes
#SessionAttributes({"voting", "state"})
Your first approach, using the #ModelAttribute annotation does two things:
Creating the Voting object using the submitted form data;
Exposing the Voting object to the view by adding it to the model (request, or, in your case, session because of the #SessionAttributes({"voting"})).
Your second approach uses just the ModelMap, so it's getting only model attributes (from the request or, in your case, the session, depending on the #SessionAttributes annotation). This approach does not use the data from the submitted form.
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