Grails将请求参数绑定到枚举类型

12

我的Grails应用程序有许多看起来像这样的枚举:

public enum Rating {
    BEST("be"), GOOD("go"), AVERAGE("av"), BAD("ba"), WORST("wo")
    final String id

    private RateType(String id) {
        this.id = id
    }

    static public RateType getEnumFromId(String value) {
        values().find {it.id == value }
    }   
}

如果我有这样一个命令对象:

class MyCommand {
    Rating rating
}

我想要(例如)自动将请求参数的值“wo”转换为Rating.WORST。

定义自定义转换器的过程在这里描述(将字符串转换为日期的上下文中)。尽管此过程有效,但我不想为我的每个枚举创建实现PropertyEditorSupport的类。是否有更好的选择?

2个回答

12

我找到了一个解决方案,感到非常满意。

步骤1:创建一个PropertyEditorSupport的实现,用于将文本转换为相应的Enum并进行相互转换

public class EnumEditor extends PropertyEditorSupport {

    private Class<? extends Enum<?>> clazz

    public EnumEditor(Class<? extends Enum<?>> clazz) {
        this.clazz = clazz
    }

    public String getAsText() {
        return value?.id
    }

    public void setAsText(String text) {
        value = clazz.getEnumFromId(text)
    }
}

步骤2:定义一个类,将EnumEditor注册为各种枚举类的转换器。要更改可通过ID绑定的枚举类列表,请修改BINDABLE_ENUMS

public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {

    private static final String REQUIRED_METHOD_NAME = 'getEnumFromId'

    // Add any enums that you want to bind to by ID into this list
    private static final BINDABLE_ENUMS = [Rating, SomeOtherEnum, SomeOtherEnum2]

    public void registerCustomEditors(PropertyEditorRegistry registry) {            

        BINDABLE_ENUMS.each {enumClass ->
            registerEnum(registry, enumClass)
        }
    }

    /**
     * Register an enum to be bound by ID from a request parameter
     * @param registry Registry of types eligible for data binding
     * @param enumClass Class of the enum
     */
    private registerEnum(PropertyEditorRegistry registry, Class<? extends Enum<?>> enumClass) {

        boolean hasRequiredMethod = enumClass.metaClass.methods.any {MetaMethod method ->
            method.isStatic() && method.name == REQUIRED_METHOD_NAME && method.parameterTypes.size() == 1
        }

        if (!hasRequiredMethod) {
            throw new MissingMethodException(REQUIRED_METHOD_NAME, enumClass, [String].toArray())
        }
        registry.registerCustomEditor(enumClass, new EnumEditor(enumClass))
    }
}

第三步:通过在grails-app/conf/spring/resources.groovy中定义以下Spring bean,使Spring意识到上面的注册表。

customPropertyEditorRegistrar(CustomPropertyEditorRegistrar)

干得好!我也在为同样的问题苦苦挣扎。为什么这不是Grails标准的一部分?Grails绑定请求参数到领域/命令对象的支持真的很糟糕。 - mcv
3
Grails支持将请求参数绑定到枚举类型,但默认按名称绑定。如果您想按照其他枚举属性进行绑定(例如按ID进行绑定,如上所示),则需要自己定义绑定。 - Dónal

11

因此,默认的数据绑定是绑定在枚举名称上,而不是枚举的另外定义属性上。您可以创建自己的属性编辑器,就像您所提到的那样,或者采用类似于以下的解决方法:

class MyCommand {
 String ratingId
    Rating getRating() {
     return Rating.getEnumFromId(this.ratingId)
    }
    static constraints = {
     ratingId(validator:{val, obj -> Rating.getEnumFromId(val) != null })
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接