Spring 3.0M4 and passing objects as parameters to POST - java

I'm quite sure this has to be in the docs somewhere, but I've looked for days and haven't spotted it. I'm probably staring myself blind when it's right in front of me, so sorry for asking an abvious question, but....
#RequestMapping(method = RequestMethod.POST)
public ModelAndView post(#ModelAttribute("user") User user) {
ModelAndView mav = new ModelAndView(jsonView);
//....
return mav;
}
This is my POST function as part of my controller, and I'd like to try it out. So I fire up Poster, the Firefox REST tester that I use for trying out my functions, and fire a POST to http://localhost:8000/userController with parameters { firstname = "foo", lastname = "bar }. That gives me:
org.springframework.web.HttpSessionRequiredException: Session attribute 'user' required - not found in session
So I try with { user.firstname = "foo", user.lastname = "bar" }, same error. What parameters do I need to send in a POST or PUT request in order to use this mechanism that automatically maps my parameters to an object?
Cheers
Nik

That effect apparnetly occurs if you have #SessionAttributes annotation at your class. This causes Spring to expect the model attribute to be stored in the session from a prior GET web request, that put the object into the model.
This behaviour allows partial binding of request parameters to model objects. The workflow is as follows:
you receive a GET request to populate the model
Spring binds all model objects you configured either by name or type in #SessionAttributes to the session
you receive a POST request with updated data
Spring takes the objects from the session and binds the request data to them
Othwerise Spring would populate an empty new object which is mostly not the desired behaviour.

That annotation will search in the session an attribute named 'user', while the parameters you send in the POST are stored as parameters of the request:
//Get a session attribute:
request.getSession().getAttribute("user");
//Get a request parameter:
request.getParameter("firstname");
More here

No annotation should be necessary on the User method parameter, Spring will recognise it as a command object and bind to it without the annotation.
#ModelAttribute is slightly confusing, I find, its meaning seems to vary from situation to situation.

Related

SessionAttributes when open new browser tabs

I have an Spring-mvc application and in each controller I add a form to SessionAttributes to preserve properties when save, delete or do another get request. Main problem becomes when I try to open some link in another browser tab and try to submit the first one. I tried this solution but when I do a redirect (in controller I only have 1 return for view and the other methods do a redirect) it creates a new conversation and can't find previous one.
I have another question about this triying to use spring-session, question It's here but I don't know if this will work too.
Did you look into Spring's RedirectAttributes? I haven't used it myself but it sounds like it should do what you would like. RedirectAttributes is typically used for GET/redirect/POST patterns and at least one user seems to think passing session attributes this way is bad practice, however they go on to mention there doesn't seem to be a better solution. Anyway, the example shown in the documentation:
#RequestMapping(value = "/accounts", method = RequestMethod.POST)
public String handle(Account account, BindingResult result, RedirectAttributes redirectAttrs) {
if (result.hasErrors()) {
return "accounts/new";
}
// Save account ...
redirectAttrs.addAttribute("id", account.getId()).addFlashAttribute("message", "Account created!");
return "redirect:/accounts/{id}";
}
would add the "message" attribute to a RedirectModel, and if your controller redirects, then whatever method handles the redirect can access that data like so:
#RequestMapping(value = "/accounts", method = RequestMethod.POST)
public String handleRedirect(Model model) {
String message = (String) model.asMap().get("message");
return new ModelAndView();
}
So adding session attributes should be possible in the same way. Another reference here.
EDIT
I was looking through the Spring documentation and they also mention this annotation #SessionAttributes. From the documentation:
The type-level #SessionAttributes annotation declares session attributes used by a specific handler. This will typically list the names of model attributes or types of model attributes which should be transparently stored in the session or some conversational storage, serving as form-backing beans between subsequent requests.
Could this be what you need?
And also a link to documentation on flash attributes.
This is the solution we have come up with, nothing to do with Spring:
On each html form of your application you will have to include a hidden field. Let's name this field CSRF_TOKEN. This field should have a randomly generated value. This value is placed both in the session and the hidden field. The name of the session attribute is SESSION_CSRF_TOKEN
When the form is submitted to the server, you check whether the value in the session (SESSION_CSRF_TOKEN) equals the value sent in the HTTP request parameter CSRF_TOKEN. If not, you show some kind of error message and you stop processing. If they are equal, proceed.
If the user opens a new tab or duplicates a tab, the server will re-render the page and a new CSRF_TOKEN will be generated. So the user will only be able to submit the form from the newly opened tab , and not from the original.
This solution offers an additional bonus: It protects from CSRF attacks.

JSON response giving Http 500 internal server error

I am getting Internal Error when trying to make an ajax POST Call which returns JSON.
The ajax call is made from JS page:
$.post(
'FilterAsJson',
$(formWithReportData).serialize(),
function(data){funtion_body}
);
This is my Spring MVC calling method:
#RequestMapping(value = "/Reporting/FilterAsJson", method = RequestMethod.POST)
public #ResponseBody PagedQueryResult<GetEntitlementOverviewReportResult> filterAsJson(#ModelAttribute GetEntitleReportQuery query, HttpSession session)
{
getEntitlementOverviewFromSession(session).updateFromQuery(query, session);
return queryDispatcher.dispatch(query);
}
The issue comes where I am setting only few fields in this class GetEntitlementOverviewReportResult(17 out of 30). This is a bean class with simple setter getters. If I set all the 30 fields it works fine.
Can you suggest how the JSON response is set so I can rectify this issue.
A 500 error means that your server encountered an error while processing the request. Since you are using AJAX, you do not see the full message from the server.
2 Options:
A - Check the server logs
B - See below:
Best way I know of to check this with an asynchronous call is to press F12 to bring up your developer tools in your web browser.
Then, you click the "Network" tab on the browser tool and you can see all of the requests that your application makes.
Make your request that is giving you a 500 error, then find it in the list of network requests. You should see the 500 error and be able to see the actual output (server response) that will give you an actual message.
#RequestMapping(value = "/Reporting/FilterAsJson", headers = "Accept=application/json", method = RequestMethod.POST)
public #ResponseBody PagedQueryResult<GetEntitlementOverviewReportResult> filterAsJson(#ModelAttribute GetEntitleReportQuery query, HttpSession session) {
getEntitlementOverviewFromSession(session).updateFromQuery(query, session);
return queryDispatcher.dispatch(query);
}
UPDATED
Oh, i see. I didn't understand question properly.
Show us please class GetEntitleReportQuery which propagate #ModelAttribute.
Also check what does method serialize when you filled not all fields. Does it exist?
UPDATED
An idea.
When u filled up not all fields of class, he try to find class with such fields and can't find. So, try to named your class in Controller and add binding result param: filterAsJson(#ModelAttribute("query") GetEntitleReportQuery query, HttpSession session, BindingResult result) also send from JSP with name "query".

Spring-MVC :: How to pass request parameters (or) query string values to another subsequent request?

I have a scenario to pass values from one request to another subsequent rquest. (i.e) I will call 'Controller1' on the first request and take the request parameters or query string and should send them to 'Controller2' as 'new request'.
Strictly I should not use any of the following approaches.
should not use sessions.
should not use cookies.
should not use requestdispatcher.forward(--).
without FlashAttributes (which internally uses session, which won't work in 'Clustered environmnets').
should not expose the ModelAttribues in request parameters in case of redirection (i.e) I should not even expose them as request parameters using spring RedirectView.
please let me know, if we have any alternative approch.
Thanks in advance.
You could call the underlying method directly
So if you have as controller2 :
#RequestMapping(value = "/MyURL", method = RequestMethod.POST)
public String myMethod(final BaseDTO baseDTO, Model model) {}
Inject controller2 into controller1 and call "normally":
controller2.myMethod(baseDTO, model);

Redirect or Forward maintaining the BindingResults

I am looking for a way to do a redirect or forward from one Controller request mapping to another.
The situation is that I have a Controller that has three stages: User inputs data -> Preview page -> Submit. In the Preview request mapping I have the Model Attribute and its BindingResult. If I have errors in the binding, I want to push the user back to the New form using a redirect, but when I do that Spring re-evaluates the ModelAttribute, and thusly re-creates the BindingResult.
Some code:
#RequestMapping(value = "\new", method = RequestMethod.GET)
#ApplicationUserCreated
public String formNew(
#ModelAttribute("formBean") FormBean formBean,
BindingResult bindingResults,
Model uiModel) {
// Do some stuff
// Send the "new form" view
return "new.jsp";
}
#RequestMapping("/preview", method = RequestMethod.POST)
#ApplicationUserCreated
public String formPreview(
#ModelAttribute("formBean") FormBean formBean,
BindingResult bindingResults,
Model uiModel) {
// TODO: Validate the form
if(bindingResults.hasErrors()) {
// Redirect them back to the "New" form
return "redirect:" + "/new";
} else {
return "preview.jsp";
}
}
Please excuse any typos, as I had to try to simplify the code some. I tried removing the BindingResults from the formNew() method, but when Preview redirects to New, it still seems to overwrite the BindingResults. I also tried doing a "forward" instead, but same results.
I ended up just calling formNew() from formPreview() when I needed to send the user back to the new.jsp. I don't get the redirect, so the URL in the browser shows as "/preview", but at least it's working and I feel like I am not wasting time duplicating code.
You can store the BindingResult in Session or you can try to send that data with Spring Flash Attributes, if you have at least spring 3.1 .
** if ManagementMovesFormBean extends or implements you're FormBean, you should send that bean in flash attributes.
** by the way, to validate you're form, you should have added #Valid in front of #ModelAttribute(".....
Don't forget that a BindingResult is assign to a single class, in you're example you have 2 methods with different expected objects, so those two BindingObjects are different
I am not sure what the purpose of the preview page is but I would recommend performing validation on the same page and only when input is valid to proceed to preview using a redirect.

Spring MVC(Spring 2.5) Question about Post-Redirect-Get

I have a Spring Annonted Controller that is used to capture the information from a form and get a list of search results from the database.
Here is the definition of the method
#RequestMapping(method = RequestMethod.POST, params = {SUBMIT_BTN })
public ModelAndView processForm(#ModelAttribute(COMMAND_NAME){
// 1. Load search results using search parameters from form (Contained in a collection of some sort)
// 2. Create the ModelAndView
// 3. Redirect with RequestView or redirect: to generate a GET.
}
I think I need to redirect with redirect: since i have a list of items in a collection store in the session. Cannot add that as a url request param.
Basically I'm trying to prevent problems whith the back button where it says that the page is expired. I want to implement the PRG pattern in strings.
I'm having a hard time wrapping my head around converting the POST into a GET. Can I just redirect or do I need two methods? Thanks for any help you can provide.
The standard pattern is to have a controller method to handle the GET,and which shows the form (or whatever) to the user, and one to handle the POST, which is the form submission. The POST method sends a redirect after it has finished processing the submission, which comes back in to the GET method.
#RequestMapping(value="/myapp", method=GET)
public String showForm(#ModelAttribute(COMMAND_NAME){
return "form.jsp";
}
#RequestMapping(value="/myapp", method=POST)
public String processForm(#ModelAttribute(COMMAND_NAME){
// do stuff to process for submission
return "redirect:/myapp";
}
Returning a view name with the "redirect:" prefix forces Spring to send an HTTP direct rather than an internal request forward.
This is the same pattern that Spring 2.0 implemented with SimpleFormController, but the new way is far more transparent.

Categories