如何在 controller action 方法参数中使用枚举?

尝试

controller 代码如下:

def list(GuessType type, int max) {
}

报错

Could not find matching constructor for: chess_lottery.enumeration.GuessType()
groovy.lang.GroovyRuntimeException: Could not find matching constructor for: chess_lottery.enumeration.GuessType()
	at grails.artefact.Controller$Trait$Helper.initializeCommandObject(Controller.groovy:425)
	at org.grails.testing.runtime.support.ActionSettingMethodHandler.invoke(ActionSettingMethodHandler.groovy:29)
	at chess_api.GuessControllerSpec.测试枚举类型是否能正确绑定到action的参数(GuessControllerSpec.groovy:18)

搜索参考

  • https://stackoverflow.com/questions/7235183/data-binding-to-an-enum-on-a-command-in-grails
  • http://docs.grails.org/latest/ref/Controllers/bindData.html

需要研究 grails 的 data binding 实现。

代码:
grails.artefact.Controller#initializeCommandObject

最后 grails 创建这个枚举的代码是这样的:

grails.artefact.Controller#initializeCommandObject()

。。。
    } else if (requestMethod == HttpMethod.POST || !isDomainClass) {
        commandObjectInstance = type.newInstance()
    }
。。。

了解一下枚举是否可以实例化?
https://stackoverflow.com/questions/16851377/instantiate-enum-class
答:不能调用构造函数来实例化一个枚举,需要用 valueOf() 方法来获取 一个已经存在的枚举,因为枚举值在JVM中必须是唯一的。

结论

截止 Grails v4.0.3 版本,Controller 的 action 方法还不支持使用枚举类型作为参数进行 data binding。也就是说将枚举作为action的参数会导致抛出异常。

绕过方案:
在 action 参数中定义一个 int id 参数,用一个 command object 来进行参数绑定,然后自定义一个 set 方法,将 int id 转换为枚举,如果转换失败则设置相应的 validation errors。

class ListGuessCommand implements Validateable {
    /**
     * 竞猜类型,取值看 GuessType.id
     */
    int type
    /**
     * 最大记录数
     */
    int max = 20
    /**
     * 自动根据 type 转换而来
     */
    GuessType guessType

    def setType(int type){
        // 转换为枚举
        guessType = GuessType.valueOf(type)
        if (!guessType){
            errors.rejectValue("type", "无法找到type对应的 GuessType 枚举定义")
        }
    }
    static constraints = {
    }
}
原创文章 80 获赞 40 访问量 8万+

猜你喜欢

转载自blog.csdn.net/yangbo_hr/article/details/105555344