laenzlinger
Mar 20th, 2006, 09:55 AM
First of all I would like to thank all the people who helped to develop such a great framework as Spring is! We were using Spring with great success in several projects!
So far we have used the Struts in the web layer but we are investigating using Spring MVC (and Spring Web Flow) instead.
One requirement we face is the "Redirect after Post" pattern. The SimpleFormController does allow that pattern on submit (e.g. by using a redirect: view).
Is there also a proper way of redirecting back to the from on error (binding- or validation-error)?
I was thinking of a RedirectFormController (see below) that implements a similar workflow than the SimpleFormController (by extending the AbstractFormController). On error it persists the errors in the session and then redirects back to the form. Before the form is presentet, the stored errors are retrieved from the session again.
Is there a better solution for this or should one use Spring Web Flow for such pageflows?
Thanks for any suggestions
package example;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractFormCo ntroller;
public class RedirectingFormController extends AbstractFormController {
// -------------------------------------------------------------------------
// PUBLIC CONSTANTS
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// PROTECTED AND PRIVATE VARIABLES AND CONSTANTS
// -------------------------------------------------------------------------
protected static Log log = LogFactory
.getLog(RedirectingFormController.class);
private String formRedirect;
private String formView;
private String successView;
// -------------------------------------------------------------------------
// CONSTRUCTORS
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// PUBLIC METHODS
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// PROTECTED METHODS
// -------------------------------------------------------------------------
protected ModelAndView showForm(HttpServletRequest request,
HttpServletResponse response, BindException errors)
throws Exception {
return showForm(request, response, errors, null);
}
protected ModelAndView showForm(HttpServletRequest request,
HttpServletResponse response, BindException errors, Map controlModel)
throws Exception {
log.debug("showForm");
String errorsAttrName = getErrorsSessionAttributeName(request);
BindException sessionErrors = (BindException) request.getSession()
.getAttribute(errorsAttrName);
if (sessionErrors != null) {
if (log.isDebugEnabled()) {
log.debug("redirected error request");
}
errors.addAllErrors(sessionErrors);
request.getSession().removeAttribute(errorsAttrNam e);
}
return showForm(request, errors, getFormView(), controlModel);
}
protected ModelAndView processFormSubmission(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception {
if (errors.hasErrors()) {
if (log.isDebugEnabled()) {
log.debug("Data binding errors: " + errors.getErrorCount());
}
return redirectForm(request, response, command, errors);
} else {
log.debug("No errors -> processing submit");
return onSubmit(request, response, command, errors);
}
}
// redirect view -----------------------------------------------------------
protected ModelAndView redirectForm(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception {
ModelAndView mv = new ModelAndView(getFormRedirect());
// store the form into the session
if (isSessionForm()) {
String formAttrName = getFormSessionAttributeName(request);
if (log.isDebugEnabled()) {
log.debug("Setting form session attribute [" + formAttrName
+ "] to: " + errors.getTarget());
}
request.getSession().setAttribute(formAttrName, errors.getTarget());
}
// store the errors into the session
String errorsAttrName = getErrorsSessionAttributeName(request);
if (log.isDebugEnabled()) {
log.debug("Setting errors session attribute [" + errorsAttrName
+ "] to: " + errors);
}
request.getSession().setAttribute(errorsAttrName, errors);
if (log.isDebugEnabled()) {
log.debug("send redirect to [" + getFormRedirect() + "]");
}
return mv;
}
protected Object formBackingObject(HttpServletRequest request)
throws Exception {
// required when presenting the errors on redirect
Object sessionForm = request.getSession().getAttribute(
getFormSessionAttributeName(request));
if (sessionForm != null) {
return sessionForm;
}
return super.formBackingObject(request);
}
protected String getErrorsSessionAttributeName(HttpServletRequest request) {
return getErrorsSessionAttributeName();
}
protected String getErrorsSessionAttributeName() {
return getClass().getName() + ".ERRORS." + getCommandName();
}
// on submit chain ---------------------------------------------------------
protected ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception {
return onSubmit(command, errors);
}
protected ModelAndView onSubmit(Object command, BindException errors)
throws Exception {
ModelAndView mv = onSubmit(command);
if (mv != null) {
// simplest onSubmit version implemented in custom subclass
return mv;
} else {
// default behavior: render success view
if (getSuccessView() == null) {
throw new ServletException("successView isn't set");
}
return new ModelAndView(getSuccessView(), errors.getModel());
}
}
protected ModelAndView onSubmit(Object command) throws Exception {
doSubmitAction(command);
return null;
}
protected void doSubmitAction(Object command) throws Exception {
}
// -------------------------------------------------------------------------
// PRIVATE METHODS
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// PUBLIC ACCESSORS (GETTERS / SETTERS)
// -------------------------------------------------------------------------
/**
* @return Returns the formView.
*/
public String getFormView() {
return formView;
}
/**
* @param formView The formView to set.
*/
public void setFormView(String formView) {
this.formView = formView;
}
/**
* @return Returns the successView.
*/
public String getSuccessView() {
return successView;
}
/**
* @param successView The successView to set.
*/
public void setSuccessView(String successView) {
this.successView = successView;
}
/**
* @return Returns the formRedirect.
*/
public String getFormRedirect() {
return formRedirect;
}
/**
* @param formRedirect The formRedirect to set.
*/
public void setFormRedirect(String formRedirect) {
this.formRedirect = formRedirect;
}
}
Christof
So far we have used the Struts in the web layer but we are investigating using Spring MVC (and Spring Web Flow) instead.
One requirement we face is the "Redirect after Post" pattern. The SimpleFormController does allow that pattern on submit (e.g. by using a redirect: view).
Is there also a proper way of redirecting back to the from on error (binding- or validation-error)?
I was thinking of a RedirectFormController (see below) that implements a similar workflow than the SimpleFormController (by extending the AbstractFormController). On error it persists the errors in the session and then redirects back to the form. Before the form is presentet, the stored errors are retrieved from the session again.
Is there a better solution for this or should one use Spring Web Flow for such pageflows?
Thanks for any suggestions
package example;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractFormCo ntroller;
public class RedirectingFormController extends AbstractFormController {
// -------------------------------------------------------------------------
// PUBLIC CONSTANTS
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// PROTECTED AND PRIVATE VARIABLES AND CONSTANTS
// -------------------------------------------------------------------------
protected static Log log = LogFactory
.getLog(RedirectingFormController.class);
private String formRedirect;
private String formView;
private String successView;
// -------------------------------------------------------------------------
// CONSTRUCTORS
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// PUBLIC METHODS
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// PROTECTED METHODS
// -------------------------------------------------------------------------
protected ModelAndView showForm(HttpServletRequest request,
HttpServletResponse response, BindException errors)
throws Exception {
return showForm(request, response, errors, null);
}
protected ModelAndView showForm(HttpServletRequest request,
HttpServletResponse response, BindException errors, Map controlModel)
throws Exception {
log.debug("showForm");
String errorsAttrName = getErrorsSessionAttributeName(request);
BindException sessionErrors = (BindException) request.getSession()
.getAttribute(errorsAttrName);
if (sessionErrors != null) {
if (log.isDebugEnabled()) {
log.debug("redirected error request");
}
errors.addAllErrors(sessionErrors);
request.getSession().removeAttribute(errorsAttrNam e);
}
return showForm(request, errors, getFormView(), controlModel);
}
protected ModelAndView processFormSubmission(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception {
if (errors.hasErrors()) {
if (log.isDebugEnabled()) {
log.debug("Data binding errors: " + errors.getErrorCount());
}
return redirectForm(request, response, command, errors);
} else {
log.debug("No errors -> processing submit");
return onSubmit(request, response, command, errors);
}
}
// redirect view -----------------------------------------------------------
protected ModelAndView redirectForm(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception {
ModelAndView mv = new ModelAndView(getFormRedirect());
// store the form into the session
if (isSessionForm()) {
String formAttrName = getFormSessionAttributeName(request);
if (log.isDebugEnabled()) {
log.debug("Setting form session attribute [" + formAttrName
+ "] to: " + errors.getTarget());
}
request.getSession().setAttribute(formAttrName, errors.getTarget());
}
// store the errors into the session
String errorsAttrName = getErrorsSessionAttributeName(request);
if (log.isDebugEnabled()) {
log.debug("Setting errors session attribute [" + errorsAttrName
+ "] to: " + errors);
}
request.getSession().setAttribute(errorsAttrName, errors);
if (log.isDebugEnabled()) {
log.debug("send redirect to [" + getFormRedirect() + "]");
}
return mv;
}
protected Object formBackingObject(HttpServletRequest request)
throws Exception {
// required when presenting the errors on redirect
Object sessionForm = request.getSession().getAttribute(
getFormSessionAttributeName(request));
if (sessionForm != null) {
return sessionForm;
}
return super.formBackingObject(request);
}
protected String getErrorsSessionAttributeName(HttpServletRequest request) {
return getErrorsSessionAttributeName();
}
protected String getErrorsSessionAttributeName() {
return getClass().getName() + ".ERRORS." + getCommandName();
}
// on submit chain ---------------------------------------------------------
protected ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception {
return onSubmit(command, errors);
}
protected ModelAndView onSubmit(Object command, BindException errors)
throws Exception {
ModelAndView mv = onSubmit(command);
if (mv != null) {
// simplest onSubmit version implemented in custom subclass
return mv;
} else {
// default behavior: render success view
if (getSuccessView() == null) {
throw new ServletException("successView isn't set");
}
return new ModelAndView(getSuccessView(), errors.getModel());
}
}
protected ModelAndView onSubmit(Object command) throws Exception {
doSubmitAction(command);
return null;
}
protected void doSubmitAction(Object command) throws Exception {
}
// -------------------------------------------------------------------------
// PRIVATE METHODS
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// PUBLIC ACCESSORS (GETTERS / SETTERS)
// -------------------------------------------------------------------------
/**
* @return Returns the formView.
*/
public String getFormView() {
return formView;
}
/**
* @param formView The formView to set.
*/
public void setFormView(String formView) {
this.formView = formView;
}
/**
* @return Returns the successView.
*/
public String getSuccessView() {
return successView;
}
/**
* @param successView The successView to set.
*/
public void setSuccessView(String successView) {
this.successView = successView;
}
/**
* @return Returns the formRedirect.
*/
public String getFormRedirect() {
return formRedirect;
}
/**
* @param formRedirect The formRedirect to set.
*/
public void setFormRedirect(String formRedirect) {
this.formRedirect = formRedirect;
}
}
Christof