html Grails约束[验证]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了html Grails约束[验证]相关的知识,希望对你有一定的参考价值。
# Constraints
Los constraints sirven para validar que los valores asignados a las propiedades sean válidos, además a través de GORM ayudan a la generación del esquema de la bd.
Los constraints se aplican en dos lugares:
* En el databinding (valida los datos de la vista) a través del método `validate()`.
* Cuando se guarda el domain class (valida los datos hacia la bd) a través del método `save()`.
# Constraints Defaults
Por defecto, todas las propiedades de un domain/command object son `nullable: false` (obligatorias) y la única manera de cambiarlo es sobreescribiendo la propiedad. Por lo tanto si se agrega un `validator` personalizado, se mantendrá el constraint `nullable:false`.
# Nullable vs Blank
Cuando se realiza databinding en los input sin valor estos vienen como cadenas vacías, sin embargo el databinder convierte dichas cadenas vacías a `null` para que aplique el constraint por default de todas las propiedades `nullable:false`. No importa si la cadena tiene espacios `" "`, dicha cadena será convertida a `null`. Por lo tanto, no tiene mucho sentido manejar el constraint `blank` si los databinding solo provienen del `request`.
El constraint `blank` sirve para validar que una propiedad no esté en blanco después de aplicar un `trim`, por lo que rechaza los valores `""` o `" "`. Utilice `blank` para garantizar que un valor no entre a la bd en blanco ya que del request nunca vendrá una cadena vacía.
# Constraints exclusivos para cadenas
Existen algunos constraints que únicamente aplican para propiedades de tipo `String`, por ejemplo: `creditCard`, `email`, `matches`, `blank`, etc.
# max vs maxSize
`max`: Asegura que el valor no exceda a `max`
`maxSize`: Asegura que el size de una colección no sobrepase a `maxSize`.
`min`: Asegura que el valor no sea menor a `min`
`minSize`: Asegura que el size de una colección no sea menor a `minSize`.
# size
Utiliza un `groovy range` para restringir el tamaño de una colección, un número o el length de un `String`
```
String telCelular
...
telCelular size: 8..15 // mínimo 8, máximo 15 (si acepta Strings de tamaño 8 y 15)
```
> Nota: Currently this constraint cannot be used in addition to blank or nullable. Use a custom validator for these combinations.
# Constraints property order
Los constraints de una propiedad se ejecutan en el orden que fueron definidos, en el siguiente ejemplo se ejecuta primero `email:true` y después el `validator`. Sin embargo todos los constraints son ejecutados y se van acumulando, es decir, aunque el nombre no sea un email válido se ejecutará el `validator`.
```
package com.testing
@Validateable
class Command1 {
String yourEmail;
static constraints = {
yourEmail email:true, validator: { value ->
if (value < 4) {
return "erroneo"
}
}
}
}
```
Esta regla no aplica para el constraint por default `nullable:false`, cuando no está presente es el primer constraint en evaluarse por lo tanto si la propiedad es `null` no se ejecutará ninguno de los subsecuentes constraints. Esto está bien para no estar evaluando valores `null` en las validaciones personalizadas.
Nota: Si se escribe el constraint `nullable:false` en una propiedad, no importa si está antes o después de un validator, siempre será el primero en evaluarse.
Las propiedades se escriben en el scaffolding de acuerdo a cómo aparecen en los constraints, se puede cambiar el orden de una propiedad declarándola con constraints vacíos:
```
@Validateable
class Command1 {
String nombre
String apellido
static constraints = {
nombre()
apellido()
}
}
```
# Validadores personalizados
Grails permite definir validadores personalizados en cualquier campo, para ello es necesario escribir un `validator` en los constraints el cual puede recibir 1, 2 o 3 parámetros, de acuerdo al número de parámetros es la manera como se agregan los mensajes de error.
# Validator con 1 parámetro
Utilicelo cuando solo necesite el valor del campo para realizar la validación:
```
package com.testing
@Validateable
class Command1 {
BigDecimal costoContrato = 0
static constraints = {
costoContrato validator: { value ->
if (value < 4) {
return "erroneo"
}
}
}
}
```
# Validator con 2 parámetros
El primer parámetro es el valor introducido por el usuario sobre el campo (`value`), el segundo la instancia de la clase (`command1`). _La instancia de la clase siempre tendrá todos los valores introducidos por el usuario en todos los campos._
Cuando el `validator` recibe 2 parámetros, el mensaje de error se agrega retornando el código de error:
```
package com.testing
@Validateable
class Command1 {
BigDecimal costoContrato = 0
int maxCosto = 90
static constraints = {
costoContrato validator: { value, command1 ->
if (value < command1.maxCosto) {
return "erroneo"
}
}
}
}
```
En el ejemplo anterior, la llave `"erroneo"` será buscada en `messages.properties` como:
`com.testing.Command1.erroneo` ó `erroneo`
# Validator con 2 parámetros y argumentos
```
package com.testing
@Validateable
class Command1 {
BigDecimal costoContrato = 0
static constraints = {
costoContrato validator: { value, command1 ->
if (value < 4) {
return ["erroneo", 97]
}
}
}
}
```
`erroneo=El valor {2} es erroneo`
Los posibles placeholders que se pueden utilizar en el key de `messages.properties` son:
`{0}`: nombre del campo
`{1}`: Nombre completo de la clase
`{2}`: Valor introducido en la propiedad
`{3}`: primer parámetro del array
`{4}`: segundo parámetro del array
`{N}`: parámetro N del array.
# Validator con 3 parámetros
El `validator` que recibe 3 parámetros, recibe los mismos parámetros que el validador de 2 parámetros y un tercero que es el objeto `errors`. Cuando se utiliza esta versión por convensión se está indicando a Grails que los errores serán introducidos directamente en el objeto `errors` por lo que ya no se deberá retornar el código de error. En esta versión la manera de terminar la ejecución del validador es con un `return`.
```
pagoPrimerManto nullable: true, validator: { value, _this, errors ->
// Cuando el número de mantenimientos del depósito inicial es 0, quiere decir que no se está incluyendo ningún
def pagoPrimerMantoRequired = _this.numMantosDepIni==0
if (pagoPrimerMantoRequired && value == null) {
errors.rejectValue("pagoPrimerManto", "pagoPrimerManto.notnull", null, "")
return
}
if (value[Calendar.YEAR] != _this.anioAReservar) {
errors.rejectValue("pagoPrimerManto", "diferent.message", null, "")
}
}
```
# Validator general en los constraints
Se puede escribir un `validator` a nivel de propiedad que valide los valores de distintas propiedades del objeto, sin embargo no es lo más entendible ya que un validator a nivel de propiedad se entiende que sirve para validar de manera personalizada la propiedad donde se define.
Una manera de lograrlo es agregando _al command_ una propiedad extra que se encargará de validar todas las propiedades del objeto:
```
@Validateable
class Command1 {
String nombre
String apellido
boolean customValidator
static constraints = {
customValidator nullable: true, validator: { value, command1, errors ->
if (command1.nombre.equals(command1.apellido)) {
errors.reject("nombreapellido.equals.error")
return
}
}
}
}
```
```
<g:form action="formSubmit">
<g:hasErrors bean="${command1}">
<div class="alert alert-danger">
<g:renderErrors bean="${command1}" as="list"/>
</div>
</g:hasErrors>
Nombre: <g:textField name="nombre" value="${fieldValue(bean: command1, field: "nombre")}"/><br/>
Apellido: <g:textField name="apellido" value="${fieldValue(bean: command1, field: "apellido")}"/><br/>
<g:submitButton name="enviar"/>
</g:form>
```
# FAQ
### ¿Cuando se valida un constraint de una propiedad y se utiliza `_this`, ya vienen rellenas todas las propiedades?
Si, todas las propiedades vienen rellenas, en esta etapa no se hace binding para pensar si vienen o no llenas, esta es una etapa de validación y por lo tanto se encuentran todos los valores puestos en las propiedades.
### ¿Cómo obtengo el valor antiguo de una propiedad?
```
class Persona {
String nombre
String apellido
static constraints = {
nombre validator: {value,_this->
def oldValue = _this.getPersistentValue('nombre')
}
apellido validator: {value,_this->
def oldValue = _this.getPersistentValue('apellido')
}
}
}
```
### ¿Cuando se escribe un constraint, se sobreescriben los constraints por default?
El único constraint por default es `nullable:false` y la única manera de sobreescribirlo es sobreescribiendo la propiedad `nullable`. Por lo tanto si se agrega un `validator` personalizado, se mantendrá el constraint `nullable:false`.
### ¿Cómo evitar que el argumento enviado se formatee como un integer y venga separado con comas ?
```
return ["mantosAcelerables.more1abono", String.valueOf(manto.year)]
```
# Referencia
http://docs.grails.org/2.5.x/ref/Constraints/validator.html
<!-- ------------------------------------ -->
<!-- Mostrar errores -->
<!-- ------------------------------------ -->
<g:hasErrors bean="${bean}">
<div class="alert alert-danger">
<g:renderErrors bean="${bean}" as="list"/>
</div>
</g:hasErrors>
以上是关于html Grails约束[验证]的主要内容,如果未能解决你的问题,请参考以下文章
Grails 使用 Spring Security Core Plugin 测试用户角色自定义验证约束