In the play framework documentation, th开发者_运维技巧ere are two different ways to handle an action with validation errors :
- Redirect to the index (validation section of the documentation) :
if (validation.hasErrors()) {
params.flash(); // add http parameters to the flash scope
validation.keep(); // keep the errors for the next request
index();
}
- Render to the form template (in the tutorial) :
if (validation.hasErrors()) {
render("@form", post);
}
What is the best way to do this ? Render or redirect ?
There are pros and cons for both approaches.
My personal preference is to use the redirect approach, and the reason is that the browser URL correctly states where you are in the application. For example, if your index page calls the login action, if you don't use redirects, then the browser URL will show login, when you are actually on the index page with errors.
But, there is a problem with this approach. To achieve the redirect, and keep the validation error messages, you need to use validation.keep()
and params.flash()
(see this post here for details), so that the validation errors are kept for the next request. This is achieved behind the scenes by storing the validation errors and the user entered parameters in a Cookie (to ensure that Play remains stateless). As you are probably aware, the HTTP spec limits Cookies to 4Kb, so there is a risk that if you are entering data greater than 4Kb (which is possible for forms where you are entering big pieces of text), then your Cookie will overflow, and you will lose data.
The original method that Play used was the redirect approach, but the second approach was specifically added to the documentation as a workaround because of the Cookie limit.
A third, and a potentially cleaner option is to perform validation from the client side using javascript that envokes some serverside logic using AJAX. A sample of this can be seen in the 10th example of the samples-and-test/validation
sample application.
I would prefer to render the form-template again, because I think a redirect wasn't useful in such a situation. If the user press F5 it's still OK that he send the same data again. The only problem the user has, is to get an cancel operation.
To avoid the url-problem COdemwnci mentioned you can use the following trick in the routes.conf
GET /customer/edit CustomerController.load()
POST /customer/edit CustomerController.save()
Then you always have a clean URL.
I go for redirects as well, in order to have clean URLs. However, switching from one variant to the other often requires more than keeping the validation results and the http parameters, namely taking care of all other render arguments.
Recent example of mine is form validation and address correction :
before
public static void step2(@Valid Address address)
{
AddressResult result = ....; // perform address check
if (result.isCorrected())
{
validation.addError("address.streetAndHouseNumber", "Street has been corrected.");
address.streetAndHouseNumber = result.getStreet();
render("step1.html", address);
}
... // continue
}
after
public static void step2(@Valid Address address)
{
AddressResult result = ....; // perform address check
if (result.isCorrected())
{
validation.addError("address.streetAndHouseNumber", "Street has been corrected.");
// ----- note this line --------
params.put("address.streetAndHouseNumber", result.getStreet());
// -----------------------------
params.flash();
validation.keep();
step1();
}
... // continue
}
While local scoped variables can be easily populated in variant 2, we need to update the http parameters resp. write directly in the flash scope.
Anyone having a proper abstract level to easily switch between the two variants?
精彩评论