3

这是专门关于 grails 1.3.7 应用程序的,但希望答案也适用于较新的版本。下面的代码是所需内容的简化版本。accountService 正在被注入。下面的代码片段完成了它应该做的事情,但显然是重复的代码。这是位于 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
    }
  }
}    
4

2 回答 2

6

创建辅助方法的一种方法是在filters闭包之外创建它,并将实例传入。传入是行不通的,this因为那不是闭包而是UserFilters实例。而是传入闭包delegate,这是添加renderandredirect方法的地方,其中属性类似于paramsandcontrollerName是:

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

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

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

您还可以将逻辑移到服务中,然后将其重新注入。混合这样的层并在服务中包含 HTTP 逻辑通常不是一个好主意,但这会将逻辑保留在一个地方。您可以对委托使用相同的技巧,或者只传递会话/请求/响应/等。如所须。

于 2013-03-01T23:22:49.710 回答
0

您可以Closure在您的代码(控制器?)中声明 a 之后可能会调用它。

样本 :

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
  }
}    
于 2013-03-01T23:07:19.860 回答