域对象的字符串字段自动修剪的最佳实践

时间:2015-11-24 14:11:39

标签: string grails normalization

我需要从我的域对象中规范化某些字符串属性,因此我正在寻找一些以通用方式执行此操作的最佳实践。

class User {
   String name
   String email
   String password
   Integer age
   Date dateCreated

   static constraints = {
//        some constraints
   }
}

假设我要删除来自用户端的name属性中的所有尾随和前导空格,或将email字符串值转换为全部小写并删除所有空格。

将来还会有来自其他域对象的其他属性也需要进行规范化。因此,我不想为此功能创建静态工厂方法,并在每个从客户端接收适当属性的控制器中调用它。在这种情况下Annotation会帮助我吗?

我正在使用Grails 2.2.4。

6 个答案:

答案 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 {    
}

<强>性状
添加beforeInsertbeforeUpdate来说明这两个注释。

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的方法。

  1. 使用自定义dsl在静态Closure中声明域类中的卫生规则。
  2. 实施dsl。
  3. 在保存域类实例之前,请使用控制器中的dsl。

答案 5 :(得分:0)

根据我的理解,如果你想在数据绑定期间这样做,可以使用以下配置来完成:

if(PropertyValueChanged != null)
       PropertyValueChanged(with parameters defined on the signature of PropertyValueChangedEventHandler)
带有Closure参数的@BindUsing也可用于这些更改。

http://grails.1312388.n4.nabble.com/Grails-2-3-Data-Binding-String-Trimming-And-Null-Conversions-td4645255.html