Grails的验证功能基于Spring's Validator API和数据绑定功能。不过,Grails利用这些特性,通过它的"constraints(约束)"机制, 提供了一个统一的定义验证约束方式。
Grails中的Constraints(约束)是用声明式指定效验规则的方式。常用于domain 类,不过 URL Mappings 和Command 对象同样支持Constraints(约束)。
在一个domain类中,constraints(约束) 是通过给constraints属性赋值代码块的形式来定义的:
class User { String login String password String email Integer agestatic constraints = { … } }
然后,通过与属性名匹配的方法调用,并结合命名参数来指定constraints(约束)
class User { ...static constraints = { login(size:5..15, blank:false, unique:true) password(size:5..15, blank:false) email(email:true, blank:false) age(min:18, nullable:false) } }
在这个示例中,我们声明login
属性必须在5-15个字符长度之间,不能为空,并且必须是唯一的。我们还可以为password
,email
和age
属性运用其他的约束.
现有约束的完整参考可以在参考指南中找到
你可以在任何实体中调用validate方法验证domain:
def user = new User(params)if(user.validate()) { // do something with user } else { user.errors.allErrors.each { println it } }
domain的errors
属性是一个Spring Errors 接口实例. Errors
提供用于导航验证错误以及取回原始值的方法。
Grails中本质上有2个验证阶段,第一个阶段是 data binding ,当你把请求参数绑定到实体上发生,例如:
def user = new User(params)
这时,因为类型转换(如String转换为Dates),在errors
属性可能已经出现错误。 你可以检查它们并通过使用Errors
API获得原始输入值:
if(user.hasErrors()) { if(user.errors.hasFieldErrors("login")) { println user.errors.getFieldError("login").rejectedValue } }
验证的第2阶段发生在当你调用 validate 或 save时。这时,Grails将会验证你在constraints 定义的约束值。比如,默认的持久方法save会在执行之前调用 validate
。因此,允许你像下面这样编码:
if(user.save()) { return user } else { user.errors.allErrors.each { println it } }
通常,当你得到一个验证错误后,你会重定向回页面渲染这些错误。这时,你就需要一些渲染错误的方法。 Grails 提供了一组丰富的标签,处理错误渲染。 如果只是想简单的渲染错误列表,可以使用renderErrors:
<g:renderErrors bean="${user}" />
假如,你需要更多的控制,可以使用 hasErrors 和 eachError:
<g:hasErrors bean="${user}"> <ul> <g:eachError var="err" bean="${user}"> <li>${err}</li> </g:eachError> </ul> </g:hasErrors>
当一个字段存在错误的输入时,一个红色块和一些提示符,对于高亮错误非常有用。这时通过把 hasErrors 当做方法调用来做到。 比如:
<div class='value ${hasErrors(bean:user,field:'login','errors')}'> <input type="text" name="login" value="${fieldValue(bean:user,field:'login')}"/> </div>
上面的代码做了什么?它会检查user
的login
字段是否存在任何错误,如果存在,就给 div
添加一个errors
CSS class,这样就可以让你使用CSS来高亮div
.
任何错误实际上是Spring中FieldError 类的实体,它会在内部保存原始输入值。通过fieldValue标签获取错误对象的原始输入值:
<input type="text" name="login" value="${fieldValue(bean:user,field:'login')}"/>
这段代码会查看,在User
bean中是否存在一个 FieldError
,如果是,就获取 login
字段的原始输入值。
Grails中另一个关于errors值得注意的重要事情是:错误消息的显示,无需任何的硬编码。Spring中的 FieldError类使用Grails的 i18n 支持,基本上解决了来自消息绑定的消息。
编码它们自己通过规约来规定,例如,考虑早前看到约束:
package com.mycompany.myappclass User { ...
static constraints = { login(size:5..15, blank:false, unique:true) password(size:5..15, blank:false) email(email:true, blank:false) age(min:18, nullable:false) } }
如果 blank
约束不合法, Grails将在form中通过规约查找消息编码:
[Class Name].[Property Name].[Constraint Code]
在这种情况下, blank
约束就会是 user.login.blank
因此,你需要在 grails-app/i18n/messages.properties
文件中包含下面这样的消息:
user.login.blank=Your login name must be specified!
它会查找带package或不带package的类名,带有package的将会优先。作为示例,com.mycompany.myapp.User.login.blank 将先于 user.login.blank使用。 当你domain 类的消息编码与插件产生冲突时,可以这样使用。
每个规约的编码参考可以参考参考指南 constraints refer to the reference guide for each constraint.
当你使用message标签时, renderErrors 标签将自动处理查找消息。 不过,假如你想获得更多的渲染控制,你需要自己编写代码:
<g:hasErrors bean="${user}"> <ul> <g:eachError var="err" bean="${user}"> <li><g:message error="${err}" /></li> </g:eachError> </ul> </g:hasErrors>
这个示例中, eachError 标签主体内,我们使用了 message 标签的 error
参数来读取给定的错误 。
Domain 类与 command objects(命令行对象)默认支持验证。其他类也可以在类中定义静态constraints 属性获得验证(如上所述),然后把它们告诉框架。 当应用程序在框架中注册验证类 是非常重要的。简单定义constraints属性是不够的。
任何定义了静态constraints属性和标有 @Validateable 接口的类可以在框架中被验证。考虑下面示例:
// src/groovy/com/mycompany/myapp/User.groovy package com.mycompany.myappimport org.codehaus.groovy.grails.validation.Validateable
@Validateable class User { ...
static constraints = { login(size:5..15, blank:false, unique:true) password(size:5..15, blank:false) email(email:true, blank:false) age(min:18, nullable:false) } }
默认情况下,框架会搜索所有带有@Validateable 注解的类。 你可以指定框架只搜索某个packages,通过给Config.groovy中的 grails.validateable.packages属性赋值一列字符串。
// grails-app/conf/Config.groovy...
grails.validateable.packages = ['com.mycompany.dto', 'com.mycompany.util']
...
假如grails.validateable.packages属性被设置,框架只会在这些packages中搜索 (和它们的子 packages) 标有@Validateable的类.
假如一个类没有被标为@Validateable,它仍然可能通过框架验证。 那就是必须在类中定义静态constraints 属性 (如上所述) ,然后,通过在Config.groovy中为grails.validateable.classes属性设置值来告诉框架。
// grails-app/conf/Config.groovy...
grails.validateable.classes = [com.mycompany.myapp.User, com.mycompany.dto.Account]
...