Validating HTTP data with Play
Validations ensure that the data has certain values or meets specific requirements. You can use validation to verify that your models are correct before saving them to the database, or use them directly on HTTP parameters to validate a simple form.
How validation works in Play
Each request has it own Validation object which collects errors. There are three ways to define validations.
- In a controller method, call methods on the controller’s validation field directly. You can also access a subset of the API using the play.data.validation.Validation class’ static methods.
- Add validation annotations to the controller method’s parameter declarations.
- Add the @Valid annotation to action methods’ POJO parameters, and add validation annotations to the POJO properties.
The validation object maintains a collection of play.data.validation.Error objects. Each error has two properties:
- The key. This helps you to determine which data element caused the error. The key value can be set arbitrarily but when Play generates errors, it uses default conventions that follow the Java variables’ names.
- The message. This contains the error’s textual description. The message can be a plain message or refer to a key from a message bundle (typically for internationalization support).
Using the first approach, let’s see how to validate a simple HTTP parameter:
public static void hello(String name) {
validation.required(name);
…
}
This code checks that the name variable is correctly set. If not, the corresponding error is added to the current errors collection.
You can repeat this operation for each validation you need:
public static void hello(String name, Integer age) {
validation.required(name);
validation.required(age);
validation.min(age, 0);
…
}
Validation error messages
At the end of the validation you can check if any errors have been created and display them:
public static void hello(String name, Integer age) {
validation.required(name);
validation.required(age);
validation.min(age, 0);
if(validation.hasErrors()) {
for(Error error : validation.errors()) {
System.out.println(error.message());
}
}
}
Assuming that name and age are null, this would display:
Required
Required
This is because the default message, defined in $PLAY_HOME/resources/messages, is:
validation.required=Required
There are three ways to customise the validation message.
- Override the default message, by redefining the message in your application’s messages file.
- Provide a custom message as an additional validation parameter.
- Provide a message key for a localised message as an additional validation parameter.
Localised validation messages
The simplest way to override these messages is to use the same message key for a message in your application’s conf/messages file. For example:
validation.required = Please enter a value
You can also provide localisations in other languages, as described in Internationalization.
Validation message parameters
You can use a placeholder in the message for the error key:
validation.required=%s is required
This changes the output to:
name is required
age is required
This error key defaults to the parameter name, and is itself used to look up a message. For example, the name parameter in the hello action method above could be localised with:
name = Customer name
This would result in the output:
Customer name is required
age is required
You can change also override the error key using the error.message(String key) method. For example:
Error error = validation.required(name).error;
if(error != null) {
System.out.println(error.message("Customer name"));
}
Several of the built-in validations define additional message parameters that correspond to the validation parameters. For example, the ‘match’ validation defines a second String parameter for the specified regular expression, which differs from the %s placeholder above in that it specifies the parameter index ‘2’:
validation.match=Must match %2$s
Similarly, the ‘range’ validation defines two additional numeric parameters, with indices 2 and 3:
validation.range=Not in the range %2$d through %3$d
Look in the file $PLAY_HOME/resources/messages to see which other validations have parameters.
Custom localised validation messages
The validation messages in $PLAY_HOME/resources/messages use the default message key for each of Play’s built-in validations. You can specify a different message key. For example:
validation.required.em = You must enter the %s!
Use this new message key for the message, for manual validation in the action method:
validation.required(manualKey).message("validation.required.em");
Alternatively, use the key in the annotation’s message parameter:
public static void hello(@Required(message="validation.required.em") String name) {
…
}
You can use the same technique with validation annotations on JavaBean properties:
public static void hello(@Valid Person person) {
…
}
public class Person extends Model {
@Required(message = "validation.required.emphasis")
public String name;
…
}
Custom literal (non-localised) validation messages
The Play message look-up just returns the message key if there is no message defined for the key, which means you can also just use a literal message instead of the message key if you prefer. Using the same examples as above, for manual validation:
validation.required(manualKey).message("Give us a name!");
For action method parameter annotations:
public static void save(@Required(message = "Give us a name!") String name) {
…
}
For JavaBean property annotations:
public static void save(@Valid Person person) {
…
}
public class Person extends Model {
@Required(message = "Give us a name!")
public String name;
…
}
Displaying validation errors in the template
In most cases you want to display the error messages in the view template. You can access them in the template using the errors object. Some tags help you to display the errors:
Let’s see a sample:
public static void hello(String name, Integer age) {
validation.required(name);
validation.required(age);
validation.min(age, 0);
render(name, age);
}
and now the template:
#{ifErrors}
<h1>Oops…</h1>
#{errors}
<li>${error}</li>
#{/errors}
#{/ifErrors}
#{else}
Hello ${name}, you are ${age}.
#{/else}
But in a real application you want to redisplay the original form. So you will have two actions: one to display the form and another one to handle the POST.
Of course the validation will occur in the second action and if some error occurs you will have to redirect to the first action. In this case you need a special trick to keep your errors during the redirect. Use the validation.keep() method. This will save the errors collection for the next action.
Let’s see a real sample:
public class Application extends Controller {
public static void index() {
render();
}
public static void hello(String name, Integer age) {
validation.required(name);
validation.required(age);
validation.min(age, 0);
if(validation.hasErrors()) {
params.flash(); // add http parameters to the flash scope
validation.keep(); // keep the errors for the next request
index();
}
render(name, age);
}
}
And the view/Application/index.html template:
#{ifErrors}
<h1>Oops…</h1>
#{errors}
<li>${error}</li>
#{/errors}
#{/ifErrors}
#{form @Application.hello()}
<div>
Name: <input type="text" name="name" value="${flash.name}" />
</div>
<div>
Age: <input type="text" name="age" value="${flash.age}" />
</div>
<div>
<input type="submit" value="Say hello" />
</div>
#{/form}
You can create a better user experience by displaying each error message next to the field that generated the error:
#{ifErrors}
<h1>Oops…</h1>
#{/ifErrors}
#{form @Application.hello()}
<div>
Name: <input type="text" name="name" value="${flash.name}" />
<span class="error">#{error 'name' /}</span>
</div>
<div>
Age: <input type="text" name="age" value="${flash.age}" />
<span class="error">#{error 'age' /}</span>
</div>
<div>
<input type="submit" value="Say hello" />
</div>
#{/form}
Validation annotations
The annotations in the play.data.validation package provide an alternative and more concise way to specify validation constraints, with an annotation that corresponds to each Validation object method. To use the validation annotations, just annotate the controller method parameters:
public static void hello(@Required String name, @Required @Min(0) Integer age) {
if(validation.hasErrors()) {
params.flash(); // add http parameters to the flash scope
validation.keep(); // keep the errors for the next request
index();
}
render(name, age);
}
Validating complex objects
You can also use the validation annotations to easily add constraints to your model object’s properties, and then in the controller specify that all properties must be valid. Let’s rewrite the previous example using a User class.
First the User class, with validation annotations on the properties:
package models;
public class User {
@Required
public String name;
@Required
@Min(0)
public Integer age;
}
Then the modified hello action, which uses the @Valid annotation to specify that all of the Userobject’s properties must be valid:
public static void hello(@Valid User user) {
if(validation.hasErrors()) {
params.flash(); // add http parameters to the flash scope
validation.keep(); // keep the errors for the next request
index();
}
render(name, age);
}
And finally the modified form:
#{ifErrors}
<h1>Oops…</h1>
#{/ifErrors}
#{form @Application.hello()}
<div>
Name: <input type="text" name="user.name" value="${flash['user.name']}" />
<span class="error">#{error 'user.name' /}</span>
</div>
<div>
Age: <input type="text" name="user.age" value="${flash['user.age']}" />
<span class="error">#{error 'user.age' /}</span>
</div>
<div>
<input type="submit" value="Say hello" />
</div>
#{/form}
Built-in validations
The play.data.validation package contains several built-in validations that you can use on theValidation object or with annotations.
Custom validation
Can’t find the validator you need in the play.data.validation package? Write your own. You can use the generic @CheckWith annotation to bind your own Check implementation.
For example:
public class User {
@Required
@CheckWith(MyPasswordCheck.class)
public String password;
static class MyPasswordCheck extends Check {
public boolean isSatisfied(Object user, Object password) {
return notMatchPreviousPasswords(password);
}
}
}
Continuing the discussion
The last layer of a Play application: Domain object model.
Validating HTTP data with Play的更多相关文章
- ExtJS4笔记 Data
The data package is what loads and saves all of the data in your application and consists of 41 clas ...
- (转) [it-ebooks]电子书列表
[it-ebooks]电子书列表 [2014]: Learning Objective-C by Developing iPhone Games || Leverage Xcode and Obj ...
- The template engine
Play has an efficient templating system which allows to dynamically generate HTML, XML, JSON or any ...
- Python框架、库以及软件资源汇总
转自:http://developer.51cto.com/art/201507/483510.htm 很多来自世界各地的程序员不求回报的写代码为别人造轮子.贡献代码.开发框架.开放源代码使得分散在世 ...
- 第五篇 Replication:事务复制-How it works
本篇文章是SQL Server Replication系列的第五篇,详细内容请参考原文. 这一系列包含SQL Server事务复制和合并复制的详细内容,从理解基本术语和设置复制的方法,到描述它是如何工 ...
- Awesome Python
Awesome Python A curated list of awesome Python frameworks, libraries, software and resources. Insp ...
- Machine and Deep Learning with Python
Machine and Deep Learning with Python Education Tutorials and courses Supervised learning superstiti ...
- ASP.NET MVC Framework
ASP.NET MVC Framework是微软在ASP.NET中所添加的一组类库,这组类库可以使用Model-View-Controller的设计模式来开发ASP.NET的应用程序.它与现有的ASP ...
- Backup and Recovery Strategies1
2.1.Data Recovery Strategy Determines Backup Strategy 在设计备份策略.如若数据恢复需求和数据恢复战略启动.每种类型的数据恢复需要你采取相应的备份类 ...
随机推荐
- Spring注意事项(各部分理解)
(1),每一个bean属性,就是一个普通的java类. 类有属性,有方法,如何交给容器管理.(注解的方式,xml方式配置) (2),通过Bean来实例化对象的方式 1.通过构造器(一般是无参的默认构造 ...
- 免费在线loading生成。
loading这个在项目中也是经常要使用,这里推荐一个网站http://www.ajaxload.info/可以在线生成loading. 进来页面是这样的. 勾选transparent将会生成透明的g ...
- 什么才是正确的javascript数组检测方式
前面的话 对于确定某个对象是不是数组,一直是数组的一个经典问题.本文专门将该问题择出来,介绍什么才是正确的javascript数组检测方式 typeof 首先,使用最常用的类型检测工具——typeof ...
- 小实例窥探dotnet垃圾回收
今天项目调试时发现VS中有下面这样的现象. 说明,file.ServerLocation是一个完整的物理路径.第三句代码是错误的,保留只是因为它使用了"s"字符串. 个人认为当 ...
- office2010里怎么设置页码为第几页共几页
在office2010里设置页眉,页脚,页码是很方便的,页眉页脚可以方便的添加信息,统一文本格式,页码的添加可以让读者清楚的知道阅读的进度,也可以方便下次阅读时从相应的页码开始阅读,就像软件中的进度条 ...
- Docker - 在CentOS 7中安装Docker
1-确认系统信息 # cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) # uname -a Linux CentOS-7 3. ...
- 【GIT】使用Git命令窗口将本地工程提交至远程GitHub
目标: 1.解决的问题是如何通过Git命令窗口将本地工程提交至GitHub. 2.方便园友的同时也方便自己以后解决此类问题. 步骤: 1.首先登陆GitHub网站https://github.com/ ...
- Math.ceil(a/b)结果出错--原因是a和b不是double
脑袋短路.连续测试几次发现Math.ceil(188/20)==9; 忍无可忍,突然发现是int问题,顺着表达式走一遍,188/20==9,然后再向上取整.脑袋僵化了.看来一直做简单的不动脑筋的工作, ...
- .net请求Webservice简单实现天气预报功能
很久没有接触Webservice的知识,今天稍微复习了一下关于webservice,简单做了一个天气预报的功能,虽然界面丑的厉害,但功能算是实现了,以下是效果展示. 这东西没什么难点,只是天气预报的功 ...
- HtmlAgilityPack 处理通配的contains
//选择不包含class属性的节点 var result = node.SelectNodes(".//span[not(@class)]"); //选择不包含class和id属性 ...