|
From: <wi...@ly...> - 2004-02-14 01:39:45
|
I recently started using the web framework portion of Spring. One
concept in particular has bitten me a couple of times and I have been
unable to determine a best practice. The concept is how
SimpleFormHandler has a different workflow based on whether it is a get
request versus a post request. This concept seemed very intuitive and
works fine if the post goes off to a result page. However, below is a
scenario that I believe is quite common and SimpleFormHandler doesn't
seem to deal with it very elegantly. The problem arises when a page
displays both a form and the results of a form post on the same page.
Scenario:
There is item search page with a item search form on the top and a
tabular view of the item search results below the search page.
Example Controller:
public class ItemSearchController extends SimpleFormController {
private ItemManager manager;
public void setSearchManager(ItemManager manager) {
this.manager = manager;
}
protected Map referenceData(HttpServletRequest request) throws
Exception {
Map map = new HashMap();
map.put( "itemTypes", manager.getItemTypes() );
return map;
}
protected ModelAndView onSubmit(Object object) throws Exception {
Item command = (Item)object;
return new ModelAndView( getSuccessView(), "items",
manager.findItemsByExample( command ));
}
}
So, I request the page via /searchItem.htm which maps
ItemSearchController. The "get" workflow works as usual --
referenceData gets called and the page displays fine. The user submits
a search criteria which then goes through "post" workflow and onSubmit
gets called which returns a list of items via ModelAndView. The
successView now needs to return to the same page and this time the
results will be displayed below the form.
However,
1. If I forward back to /searchItem.htm, then I end up in an
infinite loop because the controller keeps processing it as a post.
2. If I forward on to the jsp that displayed the form originally, I
will not go through the same workflow as when the page was first loaded
and referenceData won't get called. Not too mention that I'll get an
binding errors missing exception -- I saw that RC1 tried to address
this, but only if you don't override onsubmit.
So, I decided to solve the problem with option 1 and cause the form to
realize that the post had already been handled and it must be a "get"
request being caused by a forward. The main reason for this is that the
get workflow gets used when entering the page each. To fix it, I
overrode isFormSubmission and set an attribute when a formSubmission was
recognized. If this attribute already exists, it assumes that it is a
get request instead.
Example:
protected boolean isFormSubmission(HttpServletRequest httpServletRequest) {
Object alreadySubmitted = httpServletRequest.getAttribute(
"formSubmission");
if (alreadySubmitted != null) {
return false;
}
boolean formSubmission = super.isFormSubmission(httpServletRequest);
if( formSubmission ) {
httpServletRequest.setAttribute( "formSubmission",
Boolean.TRUE );
}
return formSubmission;
}
I am a surprised that SimpleFormController doesn't deal with this
scenario since it is so common or maybe I am missing something and it
does. With the above code you can switch out the success view to go to
a seperate result page later by just changing the IOC configuration.
Basically, your controller doesn't really need to know that the results
page is the same view as the form view.
I am very curious on how others are dealing with this scenario and if
Spring deals with it and I have just overlooked it.
Keep up the good work,
Bill Lyvers
|