Grails 命令对象 - 是否有通用模式?

标签 grails

我想知道在 grails 应用程序中使用命令对象是否有任何首选模式。特别是我是否应该定义另一种方法来保存对象或使用相同的 Controller 方法来呈现表单和保存?

让我展示一个示例,其中包含呈现表单和保存对象的不同方法

def user(int id) {} // shows the edit user form - user.gsp. Submit takes us to saveUser method
def saveUser(UserCommand cmd) {} // actually saves the user, then redirects somewehre else

一切都应该正常,但是:

如果存在验证错误,saveUser 方法将必须执行 user 方法执行的整个逻辑。如果在显示用户表单之前我们必须从数据库加载额外的对象,执行一些计算等......它必须在另一次完成,因为我们必须再次显示表单并包括验证错误。这会导致不必要的代码重复。当验证失败时,我无法重定向到 user 方法,因为我会丢失命令对象和与之相关的任何错误。因此我将无法显示验证错误。

另一个使用相同方法保存和呈现表单的例子

def user(UserCommand cmd, Integer id) {
   def u=User.load(id)
   if (request.method=="POST"&&cmd.validate()) {
      // populate u with command object values and save in database
      // then redirect somewhere
   }
}

此示例消除了代码重复的需要。只有在有 POST 请求时才会保存用户,在其他情况下只会显示表单。如果出现验证错误,它们可以访问并显示在 gsp 页面上。

主要问题是,即使有一个GET 请求到用户页面(这意味着显示了 user.gsp 表单),也会创建并验证一个空的命令对象实例(因为它在同一个 Controller 中定义)。因此,每次显示表单时,都会出现提供的值为空的验证错误(因为命令对象为空)

这两种情况都可以很容易地修改以正常工作(例如:在场景 1 中在 session 中重定向之前保存命令对象,并且如果在场景 2 中有 POST 请求则只显示验证错误)但是它需要额外的代码并且看起来不是很优雅。

这个问题是否有更简单、更“grails”的解决方案?

最佳答案

下面是我通常在这种情况下所做的示例:

def create(MeetingCommand cmdMtn) {
    switch (request.method) {
    case 'GET':
        cmdMtn = new MeetingCommand() 
        bindData cmdMtn, params, [include: boundProperties]
        createEditModel(cmdMtn: cmdMtn)
        break
    case 'POST':
            def meetingInstance
            Meeting.withTransaction { status ->
                try{
                    Boolean okValidated = (cmdMtn.validate() && !cmdMtn.hasErrors())
                    if (okValidated) {
                        meetingInstance = meetingService.bindInstance(cmdMtn)
                        flashMessage 'meeting.created', FLASH_CLASS_SUCCESS, [meetingInstance.id], 'Meeting creato'  
                        redirect action: ACTION_SHOW, id: meetingInstance.id
                    }
                    else {
                        log.error cmdMtn
                        log.error cmdMtn.errors
                        status.setRollbackOnly()
                        createEditModel(cmdMtn: cmdMtn)
                    }
                } catch (e){
                    status.setRollbackOnly()
                    log.error e
                    createEditModel(cmdMtn: cmdMtn)
                }
            }
        break
    }
}
protected createEditModel(mdl = [:]) {
    mdl
}

我的灵感来自 http://blog.freeside.co/post/41774629876/semi-restful-scaffolded-controllers域持久化逻辑已移至服务层。

关于Grails 命令对象 - 是否有通用模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12514444/

相关文章:

hibernate - Grails/GORM,禁用一级缓存

grails - 如何将 id 列表绑定(bind)到 grails 中的命令对象?

grails - 如何在特定数据源上调用 Grails namedQuery?

grails - Grails 集成测试名副其实吗?

grails - Grails 中按关联计数排序

grails - 启动grails应用程序时出现问题

facebook-graph-api - Grails Spring Security如何在自定义身份验证中记住Me?

grails - 有什么方法可以将Grails的message.properties文件中的消息链接在一起?

grails - 日期参数形式问题

java - 如何从 Grails 插件更改 jar 版本?