如何从grails过滤器中删除常用逻辑?

时间:2013-03-01 22:39:08

标签: grails grails-filters

这是关于grails 1.3.7应用程序,但希望答案也适用于较新版本。下面的代码是所需内容的简化版本。正在注入accountService。下面的片段做了它应该做的事情,但显然是重复的代码。这是位于grails-app / conf

中的UserFilter类

如何从我的过滤器中提取常用逻辑并保持重定向和检查会话的功能?我已经尝试将一个方法提取到过滤器类中,传入会话和flash,但重定向仍然给我带来了问题。

def filters = {
  // ... other filters ...
  adminAllCheck(controller: 'administration', action: '*') {
    before = {
      if(!session.isAdmin) {
        if(accountService.isAdmin()) {
          session.isAdmin = true
        } else {
          flash.message = 'Non admin'
          redirect(controller: 'home', action: 'index')
          return false
        }
      }
      true
    }
  }
  userListCheck(controller: 'user', action: 'list') {
    before = {
      if(!session.isAdmin) {
        if(accountService.isAdmin()) {
          session.isAdmin = true
        } else {
          flash.message = 'Non admin'
          redirect(controller: 'home', action: 'index')
          return false
        }
      }
      true
    }
  }
}    

2 个答案:

答案 0 :(得分:6)

创建辅助方法的一种方法是在filters闭包之外创建它,然后传入实例。它不能传入this因为那不是闭包而是UserFilters个实例。而是传递封闭的delegate,这是添加renderredirect方法的地方,其中paramscontrollerName等属性是:

class UserFilters {
   def filters = {
      // ... other filters ...
      adminAllCheck(controller: 'administration', action: '*') {
         before = {
            doAdminCheck(delegate)
         }
      }
      userListCheck(controller: 'user', action: 'list') {
         before = {
            doAdminCheck(delegate)
         }
      }
   }

   private boolean doAdminCheck(filters) {
      if (!filters.session.isAdmin) {
         if (accountService.isAdmin()) {
            filters.session.isAdmin = true
         }
         else {
            filters.flash.message = 'Non admin'
            filters.redirect(controller: 'home', action: 'index')
            return false
         }
      }
      true
   }
}

您还可以使用|controller参数中的action字符来跨控制器执行常见工作。它不会直接在这里工作,因为您对管理控制器使用*并且仅应用于用户控制器中的list操作,但您可以对此执行显式控制器/操作名称检查:< / p>

adminCheck(controller: 'administration|user', action: '*') {
   if (controllerName == 'user' && actionName != 'list') {
      return true
   }
   // common logic here
}

你也可以将逻辑移动到一个服务并依赖注入 - 这通常不是一个好主意混合这样的层并在服务中使用HTTP逻辑,但这会将逻辑保持在一个地方。您可以对委托使用相同的技巧,或者只是传入会话/请求/响应/等。根据需要。

答案 1 :(得分:0)

你可以在你的代码(控制器?)中声明一个可能被调用的Closure

示例:

private def ensureSessionAdmin = {
  if(!session.isAdmin) {
    if(accountService.isAdmin()) {
      session.isAdmin = true
    } else {
      flash.message = 'Non admin'
      redirect(controller: 'home', action: 'index')
      return false
    }
  }
  true
}
def filters = {
  // ... other filters ...
  adminAllCheck(controller: 'administration', action: '*') {
    before = ensureSessionAdmin
  }
  userListCheck(controller: 'user', action: 'list') {
    before = ensureSessionAdmin
  }
}