我需要从我的域对象中规范化某些字符串属性,因此我正在寻找一些以通用方式执行此操作的最佳实践。
class User {
String name
String email
String password
Integer age
Date dateCreated
static constraints = {
// some constraints
}
}
假设我要删除来自用户端的name
属性中的所有尾随和前导空格,或将email
字符串值转换为全部小写并删除所有空格。
将来还会有来自其他域对象的其他属性也需要进行规范化。因此,我不想为此功能创建静态工厂方法,并在每个从客户端接收适当属性的控制器中调用它。在这种情况下Annotation
会帮助我吗?
我正在使用Grails 2.2.4。
答案 0 :(得分:2)
另一种方法是设置Setters不一定是吸气剂。
class User {
String name
String email
String password
Integer age
Date dateCreated
void setName(String n) {
name=n.trim()
}
void setEmail(String e) {
email=e.toLowerCase()
}
}
当条目进入时它们会命中你的setName,只需记住在Java中你手动设置set / get条目。在Grails pogo中,所有这些都是为您生成的,但是为了您以后的情况需要屏蔽掉,以便在您的案例trim / lowerCase中使用。
我最近使用getter / setter进行了一些数据转换,
可以是seen here。
这不是domainClass,实际的对象类型是JSON。
它需要来自用户set as map的输入,所以想象这就是收集的最终结果,并最终将对象类型发送到domainClass。该映射链接中的setter接收映射并将数据类型转换为JSON
现在,当我希望表示JSON信息时,javascripts需要一个字符串值,(确切地说是一个json字符串)
所以getter现在将结果从json返回到String get actual JSON and show String
使用set转换输入并将db输出转换为所需的输出。
答案 1 :(得分:2)
您可以使用“Data Binding Event Listeners” DataBindingListener接口为侦听器提供了一种机制,可以通知数据绑定事件。界面如下所示:
package org.grails.databinding.events;
import org.grails.databinding.errors.BindingError;
public interface DataBindingListener {
/**
* @return true if the listener is interested in events for the specified type.
*/
boolean supports(Class<?> clazz);
/**
* Called when data binding is about to start.
*
* @param target The object data binding is being imposed upon
* @param errors the Spring Errors instance (a org.springframework.validation.BindingResult)
* @return true if data binding should continue
*/
Boolean beforeBinding(Object target, Object errors);
/**
* Called when data binding is about to imposed on a property
*
* @param target The object data binding is being imposed upon
* @param propertyName The name of the property being bound to
* @param value The value of the property being bound
* @param errors the Spring Errors instance (a org.springframework.validation.BindingResult)
* @return true if data binding should continue, otherwise return false
*/
Boolean beforeBinding(Object target, String propertyName, Object value, Object errors);
/**
* Called after data binding has been imposed on a property
*
* @param target The object data binding is being imposed upon
* @param propertyName The name of the property that was bound to
* @param errors the Spring Errors instance (a org.springframework.validation.BindingResult)
*/
void afterBinding(Object target, String propertyName, Object errors);
/**
* Called after data binding has finished.
*
* @param target The object data binding is being imposed upon
* @param errors the Spring Errors instance (a org.springframework.validation.BindingResult)
*/
void afterBinding(Object target, Object errors);
/**
* Called when an error occurs binding to a property
* @param error encapsulates information about the binding error
* @param errors the Spring Errors instance (a org.springframework.validation.BindingResult)
* @see BindingError
*/
void bindingError(BindingError error, Object errors);}
答案 2 :(得分:2)
使用注释来装饰字段和特征来装饰类:
我创建了2个注释以显示2种可能性;静态规范化以及使用注释中的闭包更动态的东西。
<强>注解强>
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Normalize {
Class value()
}
@Retention(RetentionPolicy.RUNTIME)
public @interface LowerCase {
}
<强>性状强>
添加beforeInsert
和beforeUpdate
来说明这两个注释。
trait Normalizer {
def beforeInsert() {
def props = AnnotationHelper.findAllPropertiesForClassWithAnotation(this, LowerCase)
props.each{ prop ->
this[prop.key] = prop.value.toLowerCase()
}
}
def beforeUpdate() {
def props = AnnotationHelper.findAllPropertiesForClassWithAnotation(this, Normalize)
props.each { prop ->
this[prop.key] = AnnotationHelper.getNormalizedValue(this, prop.key)
}
}
}
助手班级
findAllPropertiesForClassWithAnotation
方法直接来自@tim_yates(Link)
class AnnotationHelper {
public static def findAllPropertiesForClassWithAnotation( obj, annotClass ) {
obj.properties.findAll { prop ->
obj.getClass().declaredFields.find { field ->
field.name == prop.key && annotClass in field.declaredAnnotations*.annotationType()
}
}
}
public static def getNormalizedValue( obj, fieldName ) {
def matchingField = obj.getClass().declaredFields.find { it.name == fieldName }
def normAnnotation = matchingField.declaredAnnotations.find{ it.annotationType() == Normalize }
def normAnnotationValue = normAnnotation.value()
def closure = normAnnotationValue.newInstance(null, null)
matchingField.setAccessible(true)
return closure.call(matchingField.get(obj))
}
}
装饰课程
class User implements Normalizer {
@LowerCase
String name
@Normalize({ it -> it.toUpperCase() })
String email
String password
Integer age
Date dateCreated
}
根据您使用的groovy版本,特征可能不适用,您可能只需要使用抽象类和继承。 这不是经过战斗考验的&#39;以任何方式,我改变了原来的修剪标准化,使其更容易测试,但希望你能看到我正在做的事情。
答案 3 :(得分:0)
不知道这是否是最佳做法,但我会使用GORM events来进行这种单独的属性规范化。
这取决于您的用例选择哪个事件。
这是在插入数据库之前将email
设置为小写的示例。
class User {
String name
String email
String password
Integer age
Date dateCreated
def beforeInsert() {
email = email.toLowerCase()
}
}
答案 4 :(得分:0)
从技术上讲,您可以实现beforeUpdate()
和beforeInsert()
域类方法来清理输入。但是从最佳实践的角度来看,这不是一个好主意,因为域类应该关注持久性和工作单元(自私的)业务逻辑,而不是清理其输入。
应在接近引入位置的地方对数据进行消毒:控制器。 (不,这不是语法错误;数据是复数)
这并不意味着它必须在控制器本身内完成。控制器可以推迟到另一个对象。事实上,我的建议是采用类似Grails的方法。
答案 5 :(得分:0)
根据我的理解,如果你想在数据绑定期间这样做,可以使用以下配置来完成:
if(PropertyValueChanged != null)
PropertyValueChanged(with parameters defined on the signature of PropertyValueChangedEventHandler)
带有Closure参数的@BindUsing也可用于这些更改。