【问题标题】:How do I DRY out common logic from a grails filter?如何从 grails 过滤器中干燥出常见的逻辑?
【发布时间】:2013-03-01 22:39:07
【问题描述】:

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

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

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
    }
  }
}    

【问题讨论】:

    标签: grails grails-filters


    【解决方案1】:

    创建辅助方法的一种方法是在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
       }
    }
    

    您还可以在controlleraction 参数中使用| 字符来跨控制器执行通用工作。它不能直接在这里工作,因为您将 * 用于管理控制器并且仅适用于用户控制器中的 list 操作,但您可以对此进行显式控制器/操作名称检查:

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

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

    【讨论】:

      【解决方案2】:

      你可以在你的代码(控制器?)中声明一个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
        }
      }    
      

      【讨论】:

        猜你喜欢
        • 2016-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-13
        • 1970-01-01
        • 1970-01-01
        • 2014-12-13
        • 1970-01-01
        相关资源
        最近更新 更多