I agree, a server side forward definitely is not a "view", but I think Spring has already gone down that path with the RedirectView.
I agree, a server side forward definitely is not a "view", but I think Spring has already gone down that path with the RedirectView.
Why so fatalistical? :wink: I've never had a problem that I couldn't find a solution for with Spring MVC.Originally Posted by kevinha
Seriosly, let's consider the basic question at the root of this thread: why do we need to forward from one controller to another?
Some possible reasons:
1. Redirect: you want a new URL to show in the user's browser.
For example, a user clicked on a "Save" button, which submitted form data to be saved. When this request is handled without a redirect, the URL that the form was submitted to is displayed in the users browser. Even worse than the cosmetics are the implications of a page "reload"; the form would be re-submitted in most browsers. One workaround for this it to use session forms and the handleInvalidSubmit method. Another solution is to redirect to a different URL to prevent resubmission. IMHO this is about the only case in which a redirect is needed in the context of forwarding from one controller to another (the others that I know of are more obscure). Note that you can pass parameters through a redirect by supplying a model in addition to a RedirectView when constructing the ModelAndView. For example:
2. You have multiple controllers to handle a single request.Code:return new ModelAndView(new RedirectView(getSuccessView()), modelMap)
This case should be VERY rare. With the use of interceptors and/or filters, correct usage of referenceData() in form controllers, etc. multiple controllers per request can almost always be avoided. In the rare case that it must be done, I simply wire my Controller objects together in the Spring context. For example:
Then in the controller I simply delegate:Code:<bean id="controller1" ... > ... </bean> <bean id="controller2" ... > <property name="controller1"><ref local="controller1"/></property> ... </bean>
A controller can transparently delegate to another controller and the second controller does not need to know anything about how it was invoked--it just receives a request and a response. The delegating controller can even inspect the ModelAndView object returned by handleRequest() and add additional model objects and/or change the view.Code:public class Controller2 extends SimpleFormController { private Controller controller1; ... ModelAndView onSubmit(...) { return controller1.handleRequest(...); } }
In a recent project, I used both of these techniques together to allow many forms to be submitted to the same URL while preventing form refreshes. I made a RedirectingController that saved request parameters, redirected to itself, then delegated to the correct form controller after the redirect. The trick was to make the original request parameters available to the delegate controller after the redirect, which was done by creating a wrapper for HttpServletRequest.
~ Daniel Miller
To drag one up from November :o
Dealing with point 2. I was just wondering whether the Spring coders had intended this kind of delegation between controllers, and if not, whether there was any risk that it may "upset" the underlying framework in any way. If controllers are multi-threaded singletons, then probably not. Just a thought.
One other question...
Please consider the following "not so rare" scenario.2. You have multiple controllers to handle a single request.
This case should be VERY rare.
Page X. Requires a Controller X to get some data (from the business tier) so that a drop down list can be presented to the user in a JSP
Page Y. Requires a Controller Y to handle a form submission.
So, in my scenario, after the successful submission of the form in Page Y, the user should be presented with Page X. As far as I can see, this would be a common usage of a forward from one controller to another. I.E where a page requires a controller to set up data required in the page. I would not want to distribute the same set up code in multiple controllers.
Your solution will definately solve this, but I would be interested to know if I am missing a Spring related structural solution.
Any comments appreciated.
Adam
If you have a need to chain together multiple controller actions, combined with non-trivial page flow requirements (demanding wizards, master-detail forms, chunks of page flow that need to be reused in different contexts, dynamic page flows, flows whose execution need to be audited/observed), you seriously should look at Spring web flow, which we are integrating now for Spring 1.2. It exists for exactly this purpose.
A little background: Spring web flow was originally implemented by Ervin Vervaet (http://www.ervacon.com/products/springwebflow) - we liked his base page flow model so much, we ran with it and between Erwin, myself, Colin, and Rod have put together a even better, more powerful implementation we're very excited about.
For now, the code, with complete javadocs and test cases, is in the sandbox now in org.springframework.web.flow. We will promote it to the main src tree after 1.1.5 clears (I'd do it now if I could ;-)) I still need to make an official announcement, but between now and 1.2, we'd like as many people to evaluate it as possible.
Erwin and I are in the process of moving over his samples and tutorials into our documentation area, and bringing them in-line with the current implementation. His original xml-based flow definition format has changed very little (near backwards compatible between impls!), and there is a well-defined "builder strategy" for flows configured in other formats (like straight up java code or your favorite scripting language).
Keith Donald
Core Spring Development Team
I was looking at the UrlBasedViewResolver and I noticed that with the release of 1.1.3, Spring now allows server side forwards by specificying the prefix forward: in the view name. As stated in the javadocs:
"Furthermore, forward URLs can be specified via the "forward:" prefix. E.g.: "forward:myAction.do" will trigger a forward to the given URL, rather than resolution as standard view name. This is typically used for controller URLs; it is not supposed to be used for JSP URLs - use logical view names there. "
Karl Baum
weblog: www.jroller.com/page/kbaum
sorry not work with ResourceBundleViewResolverOriginally Posted by kbaum
What's the alternative solution when using a ResourceBundleViewResolver thenI mean, in a bean file, where you can't use new RedirectView(...)
Last edited by Chaps; Jul 17th, 2006 at 11:32 AM.
I know some cases where a controller chain is a very nice feature. For example:
An edit view. The data is stored in session. You have a new button which clears the data and shows the edit form.
In this case chaining controller would be a great benefit.
NewController (clearing the data) -> EditController (preparing Form) -> EditView
Without repeating code or configuration the possibilities are rare. One solution would be to subclass the editcontroller but in this case I still have twice as much configuration.
My solution:
public abstract class AbstractDelegateController extends AbstractController {
private String delegateController;
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
doWork(request, response);
if (delegateController == null)
return new ModelAndView();
else
return new ModelAndView("forward:" + delegateController);
}
protected abstract void doWork(HttpServletRequest request, HttpServletResponse response);
public void setDelegateController(String delegateController) {
this.delegateController = delegateController;
}
}
configuration:
<bean name="/new.do" class="web.controller.NewController">
<property name="delegateController" value="/edit.do"/>
</bean>