|
From: <jue...@we...> - 2003-05-22 10:50:25
|
Ken,
You're right about the back-and-resubmit-valid-form case. I've changed =
the default implementation of handleInvalidSubmit to fetch a new backing =
object and resubmit, instead of showing a new form. So you don't need to =
override handleInvalidSubmit in your case to get the desired behavior.
Note that duplicate submissions are now possible with the default =
behavior. If you want to forbid them, you need to explicitly override =
handleInvalidSubmit and either show a "invalid submit" message or =
redirect to a new form. Only then will the form object in the session =
serve as transaction token.
I hope this is now as intuitive as possible (it's also documented in =
JavaDoc). What do you think?
BTW, I'm gonna check the change in this afternoon, together with some =
polishing, and full tests for ControllerServlet and co.
Regards,
Juergen
-----Original Message-----
From: Ken Krebs [mailto:kk...@kk...]
Sent: Thursday, May 22, 2003 12:00 AM
To: j=FCrgen h=F6ller [werk3AT]
Cc: spring-dev-list
Subject: [Springframework-developer] MVC Forms
Hi Juergen,
Thanks for your changes, but there is something I still have a question=20
about.
NOTE: In the following, I have removed my IsFormSubmission override and=20
set bindOnNewForm=3Dtrue.
Consider the scenario in petclinic where a user submits some changes to=20
an owner's info. The owner page is then displayed with the changes and=20
the user notices that a change was forgotten. The user then uses the=20
Back button to go back to the "change owner info" page, makes another=20
change, and sumits the form. I expected that the change will be=20
validated and submitted and the owner page with the new info would then=20
be displayed. What happens is that=20
AbstractFormController.handleRequestInternal calls handleInvalidSubmit=20
as expected when it can't find the formObject but it then returns=20
without processing the validate/submit logic. The user must then submit=20
the new change a second time to actually get it submitted.
To make it work the way I intended, I must override handleInvalidSubmit=20
and in it call showNewForm to rebind the data to the formObject, ignore=20
it's returned ModelandView, and then process a duplicate of=20
AbstractFormController's validate/submit logic. The complete code is=20
shown below.
Is this the way you intended it to work and if so, why ?
Best Regards,
Ken
/*
* OwnerInfoForm.java
*
* Created on May 9, 2003, 9:53 AM
*/
package petclinic.web;
import petclinic.Clinic;
import petclinic.Owner;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
import com.interface21.validation.BindException;
import com.interface21.web.servlet.ModelAndView;
import com.interface21.web.servlet.mvc.SimpleFormController;
import com.interface21.web.bind.ServletRequestDataBinder;
import com.interface21.context.ApplicationContextException;
/**
*
* @author Ken Krebs
*/
public class OwnerInfoForm extends SimpleFormController {
=20
/** Holds value of property clinic. */
private Clinic clinic;
=20
/** Creates a new instance of OwnerInfoForm */
public OwnerInfoForm() {
}
=20
/** Setter for property clinic.
* @param clinic New value of property plinic.
*/
public void setClinic(Clinic clinic) {
this.clinic =3D clinic;
}
=20
protected void init() throws ApplicationContextException {
if(clinic =3D=3D null)
throw new ApplicationContextException("Must set clinic bean=20
property on " + getClass());
}
=20
protected ModelAndView onSubmit(Object command) throws=20
ServletException {
Owner owner =3D (Owner) command;
// add stuff to test if adding new or updating existing owner
clinic.update(owner);
return new ModelAndView(getSuccessView(), "owner", owner);
}
=20
protected Object formBackingObject(HttpServletRequest request)=20
throws ServletException {
int ownerId =3D 0;
try {
ownerId =3D =
Integer.parseInt(request.getParameter("ownerId"));
} catch(NumberFormatException e) {/*OK to trap & ignore*/}
Owner owner =3D clinic.getOwner(ownerId);
return (owner !=3D null) ? owner : new Owner();
}
protected ModelAndView handleInvalidSubmit(HttpServletRequest=20
request, HttpServletResponse response)
throws ServletException, IOException {
showNewForm(request, response);
// process submit
Object command =3D userObject(request);
ServletRequestDataBinder errors =3D bindAndValidate(request, =
command);
return processSubmit(request, response, command, errors);
}
=20
}
j=FCrgen h=F6ller [werk3AT] wrote:
>Ken,
>
>I've further refined invalid submission handling. An invalid submit =
request in session form mode (i.e. when no form object is in the =
session) triggers AbstractFormController's handleInvalidSubmit method. =
The latter's default implementation simply shows a new form, binding the =
submitted values to the new form in case of "bindOnNewForm=3Dtrue". But =
handleInvalidSubmit can be overridden now, to show an "invalid resubmit" =
error message or redirect to some other view.
>
>Regarding transaction tokens: In session mode, form objects can serve =
as transaction tokens. If a user presses the browser's reload button, he =
either sees a new form or some custom error message (as determined by =
the handleInvalidSubmit implementation). Thus, if you need to forbid =
duplicate submissions for a certain form, switch its controller into =
session form mode in any case (even if you wouldn't need to keep the =
form object in the session otherwise).
>
>Thus, we don't really need dedicated transaction token support - just =
leverage AbstractFormController's invalid submission handling in session =
form mode. A dedicated token attribute in the session would only be =
necessary if there isn't any form object involved. Do you see a use case =
for forbidding duplicate submissions without a form?
>
>Struts has programmatic token support: You can manually add it to a =
session/request in an Action implementation when showing the form, and =
manually check its validity on submit. The html:form tag automatically =
adds a respective hidden field. I don't see actual value in this, =
though, beyond what proper session form handling already provides. BTW, =
transaction tokens aren't even mentioned in the Struts User Guide.
>
>Regards,
>Juergen
>
>
>-----Original Message-----
>From: Ken Krebs [mailto:kk...@kk...]
>Sent: Tuesday, May 20, 2003 7:21 PM
>To: j=FCrgen h=F6ller [werk3AT]
>Cc: 'spring-dev-list'
>Subject: Re: [Springframework-developer] MVC Forms
>
>
>Juergen,
>
>I haven't had a chance to look at them but your changes for the Back=20
>button problems, including some way of forbidding duplicate submission=20
>(hopefully possible through configuration of the form bean), sound like =
>they will help provide what's needed and are a real plus for =
developers.=20
>I will try to point this out in the accompanying tutorial text.
>
>As for AbstractFormController and SimpleFormController seeming=20
>restrictive, this was probably just a perception I got as I tried to=20
>solve the Back button issue. My own AbstractSearchFormController=20
>subclass of SimpleFormController shows that it is not restrictive on=20
>submission. I was concerned about how to handle things going wrong =
prior=20
>to submission (see next paragraph).
>
>There is another class of MVC problem not necessarily just with forms,=20
>and that is when the user directly enters a mapped url to a Controller, =
>and the Controller expects to see parameters that aren't there. An=20
>example of my own handling of this in petclinic is in the method=20
>ClinicController.ownerHandler. In this case, it's makes sense to just=20
>redirect the user to the FindOwnerForm as I've done. I was planning on=20
>handling this situation for the OwnerInfoForm by making the form=20
>dynamically show a "Update Owner Info" button if the preconfigured=20
>object can be provided or a "Add Owner" button if there is no=20
>preconfigured object, but redirection may be desirable in some=20
>situations. What do you think ?
>
> From the viewpoint of an organization considering adopting Spring, the =
>fact that Spring addresses these problems directly without individual=20
>developers having to craft their own adhoc solutions should be seen as =
a=20
>plus.
>
>Ken
>
>
> =20
>
|