Spring MVC 3.1 - Model Attribute lost - spring-mvc

I have a quick question on scope of ModelAttributes.
Dev. Env: Spring MVC 3.1/Java 6/JSP w/JSTL for Views
In my controller, I add an attribute to the model via
model.addAttribute(“appForResubmission”, appForResubmission);
In the JSP(served out in response to a GET request) I read it’s contents as:
${appForResubmission.appId}
— works fine and the data is shown on JSP as expected.
Upon submission of the JSP, in the same controller in a different method(in response to a PUT request), I try to read the attributes from the Model for any changes and I am doing this as
#ModelAttribute(“appForResubmission”) Application app
in the method signature.
However, all I get is a new Application object when I try to interrogate the object for data. Spring’s documentation says this kind of instantiation of a new object happens when the requested attribute does not exist in the Model.
What would cause the attribute to be lost? Any ideas? I am suspecting it is a scope issue someplace but I am not sure where the problem could be.
Any pointers you could provide is greatly appreciated?
Thank you,
M. Reddy

The scope of a modelattribute is the request, internally it is just equivalent to HttpSerletRequest.setAttribute("model", model).
If you want the model to be available in a different controller you probably have two options, one is to reconstruct it, based on what you submit to the controller or using your persistent source. The second option is for specific model attributes to be added to the session using #SessionAttribute({'modelname'}), but just be careful that you have to call SessionStatus.complete to remove the model added to the session later.

Related

Spring MVC Session delete attribute over multiple requests

i saw here a lot of issues about deletion of session-attributes, which works fine, but it is not what i want. Maybe i misunderstand this.
Problem:
I send two ajax-requests over one session.
When i send first ajax-request "RequestA", my attribute "AtributeA" will be deleted. I see, that within hattpSession it is not listed anymore.
When i send second ajax-request "RequestB" to some other handler, i still see my attribute "AtributeA". Even hash-value from this object is the same like in "RequestA". Maybe i make something wrong or it is normal behavior?
My Code by first ajax-request with Requestmapping: "routeA":
#Controller
#SessionAttributes({"ObjectAA"}){
#RequestMapping("/routeA")
public handlerAA(HttpSession session){
session.removeAttribute("ObjektAA"); //Attribute will be deleted as expected
}
#RequestMapping("/routeB")
public handlerBB(HttpSession session){
session.getAttribute("ObjektAA");
}
}
My Code by second ajax-request with Requestmapping: "routeB":
#Controller
#SessionAttributes({"ObjectAA"}){
#RequestMapping("/routeA")
public handlerAA(HttpSession session){
session.removeAttribute("ObjectAA");
}
#RequestMapping("/routeB")
public handlerBB(HttpSession session){
session.getAttribute("ObjectAA"); //ObjectAA is still in the session? how could it be?
}
}
Check this spring document, it will clear your problem.
org.springframework.web.bind.annotation.SessionAttributes
Annotation that indicates the session attributes that a specific handler uses.
This will typically list the names of model attributes which should be transparently stored in the
session or some conversational storage, serving as form-backing beans. Declared at the type level,
applying to the model attributes that the annotated handler class operates on.
NOTE: Session attributes as indicated using this annotation correspond to a specific handler's model
attributes, getting transparently stored in a conversational session. Those attributes will be
removed once the handler indicates completion of its conversational session. Therefore, use this
facility for such conversational attributes which are supposed to be stored in the session temporarily
during the course of a specific handler's conversation.
For permanent session attributes, e.g. a user authentication object, use the traditional
session.setAttribute method instead. Alternatively, consider using the attribute management
capabilities of the generic org.springframework.web.context.request.WebRequest interface.
NOTE: When using controller interfaces (e.g. for AOP proxying), make sure to consistently put all
your mapping annotations — such as #RequestMapping and #SessionAttributes — on
the controller interface rather than on the implementation class.
Since:
2.5
Author:
Juergen Hoeller
Sam Brannen
If you found it helpful mark it as helpful. #happycoding

ASP.Net MVC - ModelState.AddModelError when GET/POST have different models

I have a use case where I used different models for the GET and POST actions in my controller. This works great for my view, because most of the data goes into labels. The model for the GET method contains 10 properties, but the model for the POST method only needs 3.
This GET view renders a form, which only needs 3 of these properties, not all 10. Thus, the model for the POST method accepts a model class which contains only these 3 properties. Therefore, the ASP.Net MVC model binder populates the model class parameter on my POST method with only these 3 necessary properties, and all is well.
Here's the question: When I encounter some business rule violation in the POST method, and want to use ModelState.AddModelError, and re-display the original view, I no longer have the 7 properties that were not POSTed, as they were not part of the form, and are not part of the model class which this method takes as its parameter.
Currently, I'm calling into a builder to return an instance of the model class for the POST method, and have the GET method itself delegating to the same builder. So, in these cases, when there is some business rule violation in the POST method, I return a View("OriginalGetView", originalGetModel). How can I use ModelState.AddModelError in this case, in the POST method, if I want to send custom messages back to the view, using a completely different model class?
It seemed way too lazy to use the same model class for both the GET and POST methods, given that their needs were so different. What is the best practice here? I see a lot of people recommending to use the same model for both methods, and to POST all of the fields back from hidden form fields, but that just seems like a waste of bandwidth in the majority of cases, and it feels ugly to be sending things like "VendorName" back to the server, when I already have "VendorId".
I may be misunderstanding what you are trying to do, but make sure you aren't being penny-wise and pound foolish. I see you may only want to post the identifiers and not necessarily the descriptors. But it sounds like you have to re-display the view after posting...if so you can just access the model properties if you post the same model that is in the get. If you only post the identifiers, you have to spend time re-accessing the database to get the description values(i.e. vendorname as you describe) using the vendor id no? Wouldn't that also be extra processing? Like I said, I could be misunderstanding your post, but for consistency using the same view model for your view to get and post makes the most sense to me.
Hidden Inputs maybe the best solution here still I think, even on 2g you shouldn't create any lag unless unless the values of your Model properties are long strings or something encrypted or xml.
So your .cshtml would have this in it for the 4 properties not currently included in the form:
<form>
#Html.HiddenFor(m => m.Property1)
#Html.HiddenFor(m => m.Property2)
#Html.HiddenFor(m => m.Property3)
#Html.HiddenFor(m => m.Property4)
But you could also get the model state errors from the original posted model and recreate the ModelError state in your response model to get around using hidden inputs.
I just found this guide (not the answer with Green Checkmark but the highest upped Answer: ASP.NET MVC - How to Preserve ModelState Errors Across RedirectToAction?
Note: if you need to copy model properties from Model to another Model (of the same type or different type), in a cleaner way, check out AutoMapper.
Perhaps this could help with what you were trying to achieve - 'Model' level errors - which wouldn't need to attach to a specific field/property - but can be displayed in a Global area.
https://stackoverflow.com/a/53716648/10257093

DefaultAnnotationHandlerMapping for portlets vs. servlets

I have been developing with Spring MVC in a Servlet environment for quite some time, mostly on Spring 3.1.x and 3.2.x, but recently moved jobs to a company that uses a mixture of Portlets and Servlets using Spring 3.0.6.
Fist, there seems to be two versions of DefaultAnnotationHandlerMapping, one for Portlets and one for Servlets. My limited knowledge of Portlets makes me believe they are just an extention of Servlets, so I can vaguely understand the need to have two separate HandlerMappings, one to handle generic Servlets, the other to handle specifics to Portlest. What is throwing me is how they each seems to behave differently with regaurds to how they handle the #RequestMapping annotations, and how my new employer has chosen to set things up.
In my past, I have had one DispatchHandler for the entire application. I know you can have multiple DispatchHandlers, but I never saw the benefit past segregation of sub-context XMLs. Anyhow, in the past I would have a DispatchHandler mapped to "/", and then each Controller set a mapping on top using #RequestMapping("/someUrl") and then another #RequestMapping on each handler method further extending the URL mapping. So, from a browser I would get something like:
http://somehost.com/myWar/myController/myMethod
where the first "/myWar" is mapped to the WAR deployment, the next "/" is mapped to the DispatchServlet, "/myController" is the Controller's mapping, and anything after is matched to some method using a combination of URL signature, request method, parameters, etc.
Now lets evaluate what I am seeing at my new firm. First, each Controller gets its own DispatchServlet, so there is like 20-30 DispatchServlets defined, all with different base URIs mapped, some with the same base Application Context XML, some with different ones, all using the same Application Context from the ContextLoaderListener. Each of the subsequent DispatchServlet's path is the same as the #RequestMapping on their "mapped" Controller, so in the above example DispatchServlet would have the path "/myController" and the Controller would have #RequestMapping("/myController"). On top of that, at the Controller's method level, the value specified on #RequestMapping seems to totally ignore any additional pathing applied to it.
So, for instance, if I have a Controller with #RequestMapping("/myController"), followed by a method with #RequestMapping("/edit"), hitting the URL http://somehost.com/myWar/myContoller/edit gives me a 404. However, if I change the method-level #RequestMapping to #RequestMapping(parameter="actionMethod=edit"), and the URL to http://somehost.com/myWar/myController?actionMethod=edit, it maps just fine and I get my page. Further, if I change my method-level #RequestMapping to #RequestMapping(value="/edit",params="actionMethod=view") neither http://somehost.com/myWar/myController?actionMethod=edit nor http://somehost.com/myWar/myController/edit?actionMethod=edit work at all. The problem is that now to get to anything besides the default mapping at the method level requires me to take on "?actionMethod=edit", instead of simply extending the URI with the added paths. Also, it prevents me from using a RESTful approach, since now I can't define something like #RequestMapping("/somePath/{id}").
I have so much confussion in my brain, like why is the DispatchServlet mapping in the web.xml overlapping the Controllers #RequestMapping, and why is the #RequestMapping at the Controller's method level not working when I set the value property to a valid URI mapping, but works fine when I set some parameter mapping?
Oh, and sorry for the long posting. I just want to get a better understanding of what is happening here so I can either deal with it with an intellegent approach, or go back to my new group and say "this should be changed, and this is why". I can extend this lengthy question with some simplified code examples if that helps.

Does Velocity template has implicit request object?

I'm rephrasing my existing question to a more generic one. I want to know if Velocity has got implicit object references like JSP does.
I'm particularly interested in knowing about the request object.
In JSP we can get the attribute in the request scope like <%= request.getAttribute("req1") %>
I know that JSP is a servlet and <%= request.getAttribute("req1") %> ends up as a part of _jspService() method which has the request object available to it before the scope of the request ends.
I'm not sure how Velocity works behind the scenes (it may be leaving the request object behind by the time it plays it role)
To test that I did the following thing which was a the part of my previous question.
I have a Spring MVC TestController in which I'm setting a request attribute. I'm using Velocity templates for rendering the views.
#RequestMapping(value="/test", method=RequestMethod.GET)
public ModelAndView display(HttpServletRequest req, HttpServletResponse resp){
...
req.setAttribute("req1", "This should be present for first request");
...
}
In the Velocity template I'm doing something like
Request: $request.getAttribute('req1')
but I'm not getting the value of req1. I know I should have put req1 in model map instead of request but I want to know about implicit request object ref.
I tried $req1 as well but its not working.
When I'm doing the same thing with the model and returning it back, everything is working correctly.
Where am I going wrong?
Update: The same thing is happening with req.getSession().setAttribute("req1", testObject) also.
Salaam,
req.getSession().getAttribute("req1", testObject) == $req1
AFAIK, you cannot access the request object at VelocityViewServlet's templates, unless you explicity set the request object in context or use a v-tool .
Take a look at this question: Velocity + Spring. The Spring folks haven't kept the integration with Velocity very up to date.
Once you've created that extension and set it up to be used properly in your servlet configuration, you'd be able to simply put the object on the ModelAndView and from there do whatever you need with it.

Does a 'model' have to be declared as a 'var' in order to bind to it in Spring Webflow 2?

I'm currently using Spring Webflow 2, and I've been writing a unit test for a flow before I actually write all the JSPs for the flow. For some reason, my requestParameters aren't being bound to my model object. I'm creating the model object right before I enter the view state that binds to it (rather than declaring it as a 'var' within the flow). I've double checked all the parameter names / model object properties and everything's right, but for some reason it's just not binding. Does anybody have any idea why ?
Are you referring to a unit test like in Chapter 14 of the Reference? If so, the model doesn't get bound within those tests for reasons that I've not yet understood. The Spring Web Flow mocking doesn't emulate the binding portions.
See also this similar question.
Until they fix this issue, you just need to do the binding yourself in the test, setting the fields of your object to the parameters that you're setting in the flow. But it's not a very satisfying test then, I know.

Resources