play框架使用起来(14)-高级指南
2016-11-04 15:27
399 查看
高级指南
[b]1、HTTP数据验证
[/b]
数据验证是应用程序健壮性的体现,在实际项目中也是必不可少的环节。Play内置了验证器(Validation)的支持,并提供了非常灵活的使用方法。在Play项目中可以很简单地对数据,模型对象(可能需要持久化)以及HTTP表单进行验证。
出于数据验证的考虑,框架为每个请求绑定了验证器。应用代码中可以通过以下三种方式对数据进行验证:
1.在控制器的Action方法中,直接使用验证器对数据进行相应的验证:
2.在控制器的Action方法的参数中,使用注解进行数据验证:
3.定义域模型时直接为属性添加验证注解,Action中就可以通过@Valid注解对该POJO参数进行验证了:
注意:
框架为每个请求绑定了一个验证器,同个验证器可以校验多个数据。
当验证不通过时,验证器会将错误以play.data.validation.Error的形式保存,因此每个验证器以集合的形式维护了一系列的error对象。每个error对象有key和message两个属性:
key:该属性帮助我们标识引起错误的元素。key的值可以任意设定,默认与验证的数据同名。
message:验证消息,用于描述验证不通过的错误信息。message可以是纯文本或指向消息包(message bundle)的key(通常为了支持国际化)。
文字的描述可能有些空洞,接下来让我们看看如何使用验证器校验简单的HTTP参数:
以上这段程序代码检查了name参数是否被赋值。如果没有,相应的错误就会被添加到当前的error集合中。如果有多个数据需要验证,可以重复该操作:
在验证结束后我们可以检查是否有error产生,并将验证消息打印出来:
假定name和age都没有赋值,控制台将会打印以下信息:
这是因为在$PLAY_HOME/resources/messages文件中定义了默认的消息:
Play提供了三种方式自定义验证消息:
在项目的conf/messages文件中自定义消息,覆盖默认的message消息。
直接将自定义的验证消息作为参数传递给验证器,覆盖默认的message消息。
定义带参数的验证消息,参数通常为error对象的key值。
本地化的验证消息
我们可以配置应用程序的conf/messages文件,采用统一的验证消息匹配error对象的message消息,这是最简单的覆盖消息的写法:
经过以上配置后,任何不通过validation.required验证的消息都是Please enter a value。
带参数的验证消息
%s占位符将被替换成error对象的key:
结合以上例子,输出结果为:
框架默认将被验证的参数的名字作为error对象的key值进行传递,但也有其他方法修改error对象的key值。比如,针对上例中hello方法(Action)的name参数进行本地化处理:
结果就会变成:
也可以使用error.message(String key)方法直接覆盖error对象的key值:
Play内置了很多验证方法,也提供了不同的消息参数。比如match验证,在消息表达式中定义了字符串类型的参数,与前面介绍的%s的占位符不同,其规定的参数索引为2:
类似的,range验证定义了两个整数型参数,以2和3作为索引:
读者可以在$PLAY_HOME/resources/messages文件中查看其他的验证以及所含的参数。
补充:
读者可能会有疑问,为什么这些参数的索引都是从2开始的。因为match,range,minSize等验证都是需要比较的,框架规定将索引为1的参数设置为比较源。
自定义本地化验证消息
Play内置验证器的message消息,是在$PLAY_HOME/resources/messages文件中定义的。我们也可以在项目中定义自己的验证消息:
在Action方法中,就可以采用自己定义的验证消息机制,手动进行验证:
我们也可以把自己定义的验证消息机制作为注解中message的参数使用:
同理,JavaBean的属性中也可以使用这种验证技术(注解在JavaBean的属性前):
更灵活的自定义方式
Play还提供了一种非常灵活的方式实现验证消息的自定义,直接在代码中为验证器标注message消息:
在注解中的使用方法:
在JavaBean中的使用方法:
如果需要将验证的错误信息在视图模板中显示,Play提供的#{ifErrors}标签和error对象可以轻松完成这些工作。在hello Action中进行数据验证,并使用默认的hello.html模板显示:
编辑view/Application/hello.html模板内容,使用#{ifErrors}标签显示验证结果信息:
显然,以上的代码并不能满足真实应用的需求。因为在实际项目中,如果验证失败了就应该显示原来的表单,并提示用户请再次输入。针对这个需求,我们需要定义两个Action:一个用于显示表单,另一个用于处理POST,数据的验证将发生在后一个操作。当验证有错误发生时,保存错误信息并重定向到第一个Action。Play提供的validation.keep()方法可以在下一个请求中保持错误信息的集合。以下是真实项目示例:
修改view/Application/index.html模板:
为了提供更好的用户体验,我们可以将错误信息显示在未通过验证的字段旁:
注解封装于play.data.validation包中,它采用与每个验证对象一一对应的方式,实现有选择性的,更加直观的数据约束。在使用数据验证的时候,只需要对控制器中的方法参数添加注解即可:
相比之下,使用注解的代码就显得整洁的多了。
在Play中通常采用注解的形式为模型对象添加数据验证。重写前面所介绍的例子,为User实体的name属性添加@Required验证注解,age属性添加@Required和@Min(0)验证注解:
接着修改hello Action方法,使用@Valid注解对模型对象进行数据验证:
最后修改index.html表单,如果验证有错,在页面上显示提示信息:
在框架的play.data.validation包中,系统已经定义了若干内置的验证机制,这些常用的验证如表1所示:
(表1 内置验证)
其中,required、min以及range验证器在前几节介绍的示例中已经有所涉及。本小节将着重介绍其中的email、match与phone验证器。除此之外的几类验证器都非常简单实用,就不再做过多的叙述了。
email
使用email验证器可以对给定的E-mail地址是否正确进行验证,其message key为validation.email。下面通过示例演示如何使用email验证器对给定的E-mail地址进行检测。
对变量address进行email验证,如果address不是有效的E-mail地址,验证器会将错误以play.data.validation.Error的形式保存。email验证同样也支持注解用法,读者在定义model时可以为模型的属性添加@Email注解:
match
match验证器是相对比较特别的验证器,该验证器可以使用正则表达式(用于描述或者匹配一系列符合某个句法规则的字符串的单个字符串)作为校验规则。在使用match验证器时,需要制定充当验证规则的正则表达式字符串作为参数,注意空字符串将会被认为是合法的,其message key为validation.match。下面通过示例演示如何使用match验证器对给定的字符串进行检测。
对变量abbreviation进行match验证,如果abbreviation不能匹配正则表达式,验证器会将错误以play.data.validation.Error的形式保存。match验证同样也支持注解用法,读者在定义model时可以为模型的属性添加@match注解:
phone
phone验证器可以对电话号码进行校验,验证是否合法。在使用phone验证器时需要注意,空字符串也将被认为是合法的,其message key为 validation.phone。下面通过示例演示如何使用phone验证器对给定的电话号码进行检测。
对变量value进行phone验证,如果value不是合法的电话号码,验证器会将错误以play.data.validation.Error的形式保存。phone验证同样也支持注解用法,读者在定义model时可以为模型的属性添加@phone注解:
读者在使用时需要注意,phone验证器的底层实现是基于电话号码模式匹配的,其准确性并不是特别高。如果希望实现准确的电话号码验证器,推荐使用@match验证器制定不同国家的电话号码验证方式。电话号码的自定义格式可以是+CCC (SSSSSS)9999999999xEEEE,其中:
+是可选的,代表国家码。
CCC是可选的,代表前3位国家代码,需要注意的是其后必须要有一个分隔符。
(SSSSSS)是可选的,代表6位地区码。
9999999999是必须,表示电话号码,最高为20位(已覆盖了所知的情况和未来可能的号码)。
x是可选的,表示扩展,也可以写成“ext”或“extension”。
EEEE是可选的,代表扩展码,最多4位。
分隔符可以使用空格、‘-’、‘.’或是‘/’其中的一个,并且可以在号码的任意地方使用。
下面是不同国家电话号码的样例,提供给读者们参考:
中国:+86 (10)69445464
美国:(305) 613 09 58 ext 101
法国:+33 1 47 37 62 24 x3
德国:+49-4312 / 777 777
英国:(020) 1234 1234
自定义的验证器可以通过@CheckWith注解进行绑定:
注意:
自定义验证器时不要忘记加载play.data.validation包。
[b]1、HTTP数据验证
[/b]
数据验证是应用程序健壮性的体现,在实际项目中也是必不可少的环节。Play内置了验证器(Validation)的支持,并提供了非常灵活的使用方法。在Play项目中可以很简单地对数据,模型对象(可能需要持久化)以及HTTP表单进行验证。
1.1 使用Play验证器#
出于数据验证的考虑,框架为每个请求绑定了验证器。应用代码中可以通过以下三种方式对数据进行验证:1.在控制器的Action方法中,直接使用验证器对数据进行相应的验证:
public static void hello(String name) { validation.required(name); //验证name参数是否被赋值 ... }
2.在控制器的Action方法的参数中,使用注解进行数据验证:
public static void hello(@Required String name){ ... }
3.定义域模型时直接为属性添加验证注解,Action中就可以通过@Valid注解对该POJO参数进行验证了:
public class User extends Model { @Required public String name; //为User的name属性添加@Required验证 ... }
//直接使用@Valid注解对POJO参数进行验证 public static void save(@Valid User user) { ... }
注意:
框架为每个请求绑定了一个验证器,同个验证器可以校验多个数据。
当验证不通过时,验证器会将错误以play.data.validation.Error的形式保存,因此每个验证器以集合的形式维护了一系列的error对象。每个error对象有key和message两个属性:
key:该属性帮助我们标识引起错误的元素。key的值可以任意设定,默认与验证的数据同名。
message:验证消息,用于描述验证不通过的错误信息。message可以是纯文本或指向消息包(message bundle)的key(通常为了支持国际化)。
文字的描述可能有些空洞,接下来让我们看看如何使用验证器校验简单的HTTP参数:
public static void hello(String name) { validation.required(name); ... }
以上这段程序代码检查了name参数是否被赋值。如果没有,相应的错误就会被添加到当前的error集合中。如果有多个数据需要验证,可以重复该操作:
public static void hello(String name, Integer age) { validation.required(name); //验证name是否被赋值 validation.required(age); //验证age是否被赋值 validation.min(age, 0); //验证age不小于0 ... }
1.2 验证消息(error对象中的message属性)#
在验证结束后我们可以检查是否有error产生,并将验证消息打印出来: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()); } } }
假定name和age都没有赋值,控制台将会打印以下信息:
Required Required
这是因为在$PLAY_HOME/resources/messages文件中定义了默认的消息:
validation.required=Required
Play提供了三种方式自定义验证消息:
在项目的conf/messages文件中自定义消息,覆盖默认的message消息。
直接将自定义的验证消息作为参数传递给验证器,覆盖默认的message消息。
定义带参数的验证消息,参数通常为error对象的key值。
本地化的验证消息
我们可以配置应用程序的conf/messages文件,采用统一的验证消息匹配error对象的message消息,这是最简单的覆盖消息的写法:
validation.required = Please enter a value
经过以上配置后,任何不通过validation.required验证的消息都是Please enter a value。
带参数的验证消息
%s占位符将被替换成error对象的key:
validation.required=%s is required
结合以上例子,输出结果为:
name is required age is required
框架默认将被验证的参数的名字作为error对象的key值进行传递,但也有其他方法修改error对象的key值。比如,针对上例中hello方法(Action)的name参数进行本地化处理:
name = Customer name
结果就会变成:
Customer name is required age is required
也可以使用error.message(String key)方法直接覆盖error对象的key值:
Error error = validation.required(name).error; if(error != null) { System.out.println(error.message("Customer name")); }
Play内置了很多验证方法,也提供了不同的消息参数。比如match验证,在消息表达式中定义了字符串类型的参数,与前面介绍的%s的占位符不同,其规定的参数索引为2:
validation.match=Must match %2$s
类似的,range验证定义了两个整数型参数,以2和3作为索引:
validation.range=Not in the range %2$d through %3$d
读者可以在$PLAY_HOME/resources/messages文件中查看其他的验证以及所含的参数。
补充:
读者可能会有疑问,为什么这些参数的索引都是从2开始的。因为match,range,minSize等验证都是需要比较的,框架规定将索引为1的参数设置为比较源。
自定义本地化验证消息
Play内置验证器的message消息,是在$PLAY_HOME/resources/messages文件中定义的。我们也可以在项目中定义自己的验证消息:
validation.required.em = You must enter the %s!
在Action方法中,就可以采用自己定义的验证消息机制,手动进行验证:
validation.required(manualKey).message("validation.required.em");
我们也可以把自己定义的验证消息机制作为注解中message的参数使用:
public static void hello(@Required(message="validation.required.em") String name) { ... }
同理,JavaBean的属性中也可以使用这种验证技术(注解在JavaBean的属性前):
public class Person extends Model { @Required(message = "validation.required.em") public String name; ... }
public static void hello(@Valid Person person) { ... }
更灵活的自定义方式
Play还提供了一种非常灵活的方式实现验证消息的自定义,直接在代码中为验证器标注message消息:
validation.required(manualKey).message("Give us a name!");
在注解中的使用方法:
public static void save(@Required(message = "Give us a name!") String name) { ... }
在JavaBean中的使用方法:
public class Person extends Model { @Required(message = "Give us a name!") public String name; ... }
public static void save(@Valid Person person) { ... }
1.3 模板中显示错误信息#
如果需要将验证的错误信息在视图模板中显示,Play提供的#{ifErrors}标签和error对象可以轻松完成这些工作。在hello Action中进行数据验证,并使用默认的hello.html模板显示:public static void hello(String name, Integer age) { validation.required(name); validation.required(age); validation.min(age, 0); render(name, age); }
编辑view/Application/hello.html模板内容,使用#{ifErrors}标签显示验证结果信息:
#{ifErrors} <h1>Oops...</h1> #{errors} <li>${error}</li> #{/errors} #{/ifErrors} #{else} Hello ${name}, you are ${age}. #{/else}
显然,以上的代码并不能满足真实应用的需求。因为在实际项目中,如果验证失败了就应该显示原来的表单,并提示用户请再次输入。针对这个需求,我们需要定义两个Action:一个用于显示表单,另一个用于处理POST,数据的验证将发生在后一个操作。当验证有错误发生时,保存错误信息并重定向到第一个Action。Play提供的validation.keep()方法可以在下一个请求中保持错误信息的集合。以下是真实项目示例:
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(); // 将HTTP参数保存在Flash作用域中 validation.keep(); // 在下一个请求中保持错误信息的集合 index(); } render(name, age); } }
修改view/Application/index.html模板:
#{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}
为了提供更好的用户体验,我们可以将错误信息显示在未通过验证的字段旁:
#{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}
1.4 注解方式#
注解封装于play.data.validation包中,它采用与每个验证对象一一对应的方式,实现有选择性的,更加直观的数据约束。在使用数据验证的时候,只需要对控制器中的方法参数添加注解即可:public static void hello(@Required String name, @Required @Min(0) Integer age) { if(validation.hasErrors()) { params.flash(); // 将HTTP参数保存在Flash作用域中 validation.keep(); // 在下一个请求中保持错误信息的集合 index(); } render(name, age); }
相比之下,使用注解的代码就显得整洁的多了。
1.5 模型对象的验证#
在Play中通常采用注解的形式为模型对象添加数据验证。重写前面所介绍的例子,为User实体的name属性添加@Required验证注解,age属性添加@Required和@Min(0)验证注解:package models; public class User { @Required public String name; @Required @Min(0) public Integer age; }
接着修改hello Action方法,使用@Valid注解对模型对象进行数据验证:
public static void hello(@Valid User user) { if(validation.hasErrors()) { params.flash(); // 将HTTP参数保存在flash作用域中 validation.keep(); // 在下一个request中保持错误信息的集合 index(); } render(user); }
最后修改index.html表单,如果验证有错,在页面上显示提示信息:
#{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}
1.6 内置验证#
在框架的play.data.validation包中,系统已经定义了若干内置的验证机制,这些常用的验证如表1所示:(表1 内置验证)
名称 | 验证内容 | 名称 | 验证内容 |
---|---|---|---|
验证E-mail地址是否合法 | equals | 验证两个值是否相等 | |
future | 验证是否为相对未来的时间 | isTrue | 验证String或者Boolean类型变量是否为true |
max | 验证数值大小是否大于给定的值 | maxSize | 验证字符串长度是否大于给定的值 |
min | 验证数值大小是否小于给定的值 | minSize | 验证字符串长度是否小于给定的值 |
match | 验证是否匹配给定的正则表达式 | past | 与future相对,验证是否为相对过去的时间 |
range | 验证是否在给定的两个数值范围内 | required | 验证是否为空 |
url | 验证是否为合法的URL | phone | 验证是否为合法的电话号码 |
ipv4Address | 验证是否为符合ipv4规则的IP地址 | ipv6Address | 验证是否为符合ipv6规则的IP地址 |
使用email验证器可以对给定的E-mail地址是否正确进行验证,其message key为validation.email。下面通过示例演示如何使用email验证器对给定的E-mail地址进行检测。
validation.email(address);
对变量address进行email验证,如果address不是有效的E-mail地址,验证器会将错误以play.data.validation.Error的形式保存。email验证同样也支持注解用法,读者在定义model时可以为模型的属性添加@Email注解:
@Email String address
match
match验证器是相对比较特别的验证器,该验证器可以使用正则表达式(用于描述或者匹配一系列符合某个句法规则的字符串的单个字符串)作为校验规则。在使用match验证器时,需要制定充当验证规则的正则表达式字符串作为参数,注意空字符串将会被认为是合法的,其message key为validation.match。下面通过示例演示如何使用match验证器对给定的字符串进行检测。
validation.match(abbreviation, "[A-Z]{3}"); // TLA
对变量abbreviation进行match验证,如果abbreviation不能匹配正则表达式,验证器会将错误以play.data.validation.Error的形式保存。match验证同样也支持注解用法,读者在定义model时可以为模型的属性添加@match注解:
@Match("[A-Z]{3}") String abbreviation
phone
phone验证器可以对电话号码进行校验,验证是否合法。在使用phone验证器时需要注意,空字符串也将被认为是合法的,其message key为 validation.phone。下面通过示例演示如何使用phone验证器对给定的电话号码进行检测。
validation.phone(value);
对变量value进行phone验证,如果value不是合法的电话号码,验证器会将错误以play.data.validation.Error的形式保存。phone验证同样也支持注解用法,读者在定义model时可以为模型的属性添加@phone注解:
@Phone String phone
读者在使用时需要注意,phone验证器的底层实现是基于电话号码模式匹配的,其准确性并不是特别高。如果希望实现准确的电话号码验证器,推荐使用@match验证器制定不同国家的电话号码验证方式。电话号码的自定义格式可以是+CCC (SSSSSS)9999999999xEEEE,其中:
+是可选的,代表国家码。
CCC是可选的,代表前3位国家代码,需要注意的是其后必须要有一个分隔符。
(SSSSSS)是可选的,代表6位地区码。
9999999999是必须,表示电话号码,最高为20位(已覆盖了所知的情况和未来可能的号码)。
x是可选的,表示扩展,也可以写成“ext”或“extension”。
EEEE是可选的,代表扩展码,最多4位。
分隔符可以使用空格、‘-’、‘.’或是‘/’其中的一个,并且可以在号码的任意地方使用。
下面是不同国家电话号码的样例,提供给读者们参考:
中国:+86 (10)69445464
美国:(305) 613 09 58 ext 101
法国:+33 1 47 37 62 24 x3
德国:+49-4312 / 777 777
英国:(020) 1234 1234
1.7 自定义验证#
自定义的验证器可以通过@CheckWith注解进行绑定: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); } } }
注意:
自定义验证器时不要忘记加载play.data.validation包。
相关文章推荐
- play框架使用起来(15)
- play框架使用起来(12)
- play框架使用起来(10)
- play框架使用起来(13)
- play框架使用起来(17)
- play框架使用起来(6)
- play框架使用起来(18)
- play框架使用起来(7)
- play框架使用起来(8)
- Wine完全使用指南——从基本到高级(ubuntu14 .04)
- play框架使用起来(16)
- play框架使用起来(11)
- play框架使用起来(5)
- Fedora14 i386下 使用Intel编译器 安装WRF指南
- Android RoboGuice 使用指南(14):Inject View
- Play 框架学习 (一) 什么是框架 为什么使用框架
- web.py 0.3 新手指南 - 使用db.query进行高级数据库查询
- [zz]Wine完全使用指南——从基本到高级
- Delphi for iOS开发指南(14):在iOS应用程序中使用InterBase ToGo
- Play 2.0 用户指南 - 使用缓存 -- 针对Scala开发者