(快速参考)

验证器

用途

向字段添加自定义验证。

示例

even validator: {
    return (it % 2) == 0
}

// is equivalent to
even validator: { val ->
    return (val % 2) == 0
}

// Closure with two arguments, the second being the object itself
password1 validator: { val, obj ->
    obj.password2 == val
}

// Closure with three arguments, the third being the errors object
password1 validator: { val, obj, errors ->
    if (!(obj.password2 == val)) errors.rejectValue('password1', 'noMatch')
}

// Examples that pass arguments to the error message in message.properties

// Example 1: Using the "implicit" argument 0 (property name)

package demo

class Person {

    String name

    static constraints = {
        name validator: {
          if (!it) return ['entryMissing']
       }
}

// This maps to a message
// person.name.entryMissing=Please enter a name in the field {0}

// Example 2: Using the "implicit" arguments 0 (property name) and 2 (property value)
package demo

class Person {

    Integer yearOfBirth

    static constraints = {
        yearOfBirth validator: {
          if (yearOfBirth>2013) return ['yearTooBig']
       }
}

// This maps to a message
person.yearOfBirth.yearTooBig=The value {2} entered in the field {0} is not valid because it lies in the future.
// arguments are [property, class, value]. e.g. [yearOfBirth,class demo.Person, 2017]
// You will note when using this kind of message on Integers that years are displayed as 1,990 instead of 1990.
// This is addressed in the next example.

// Example 3: Much more complex
package demo

class Astronaut {

    Integer yearOfBirth
    Integer yearOfFirstSpaceTravel

    static constraints = {
        yearOfFirstSpaceTravel validator: { Integer val, Astronaut obj ->
            if (val < obj.yearOfBirth) {
                return ['datePriorTo', val.toString(), obj.yearOfBirth.toString()]
            } else if (val < (obj.yearOfBirth+18)) {
                ['maybeABitTooYoung', (val - obj.yearOfBirth)]
            }
        }
    }
}

// Respective messages
// Note that argument 3 is the property value converted toString to avoid the unwanted formatting as described before.
astronaut.yearOfFirstSpaceTravel.datePriorTo=The value {3} entered for the year of the first space travel is prior to the year of birth ({4}). Please correct the value.
// For yearOfBirth: 2017 and yearOfFirstSpaceTravel: 2012 arguments will be [yearOfFirstSpaceTravel,class demo.Astronaut,2012,2012,2017]
astronaut.yearOfFirstSpaceTravel.maybeABitTooYoung={3} years seems a bit young for travelling to space, dude!
// For yearOfBirth: 2012 and yearOfFirstSpaceTravel: 2017 arguments will be [yearOfFirstSpaceTravel,class demo.Astronaut,2017,5]

说明

可以通过闭包实现一个自定义验证器,该闭包最多接受三个参数。如果闭包接受零个或一个参数,则该参数值将是正在验证的值(在零参数闭包的情况下为“it”)。如果它接受两个参数,第一个是值,第二个是正在验证的领域类实例。当您的验证需要访问其他字段时,例如检查输入的两个密码是否同时,这很有用。如果它接受三个参数,第一个是值,第二个是实例,第三个是 Spring Errors 对象。

闭包可以返回

  • nulltrue(或没有返回值)以指示值有效

  • false 以指示无效值并使用默认消息代码

  • 字符串以指示要附加到 classname.propertyName 的错误代码。用于解析错误消息的字符串。如果无法解析与字段相关的消息,则将解析该错误代码本身,从而允许全局错误消息。

  • 包含上述字符串的列表,后跟任意数量的参数,它们用作 grails-app/i18n/message.properties 文件中的格式化消息参数。参数的映射如下:参数 0 到 2 自动映射到 0:属性名称,1:类名,2:属性值。其他参数从参数 3 开始映射。请注意,在最终的错误消息中,如果在 message.properties 文件中定义了此属性的标签,则此标签将被使用。否则,将使用类中定义的属性名称。

显式传递错误代码时,通常不需要使用“return”关键字返回错误代码,因为如果验证器从闭包返回,它将检查错误对象上是否已附加任何错误。这一点在期望直接更新Errors对象的三参数闭包的情况下尤为明显。