2011-11-25 39 views
11

我正在寻找如何清理我的Grails控制器代码的方法。在各种控制器我或多或少具有相同的逻辑..让Grails控制器更干吗?

  • 获取对象
  • 检查它是否存在
  • 等。

是否有使控制器操作的建议方法重用通用代码?

---解决---

所有问题的答案对我们实施的解决方案作出了贡献。

我们使用Mixin方法创建了一个在我们的控制器中使用的类。 mixin公开的方法之一是withObject方法。此方法从控制器获取域名,并将此用于该方法的基础。这个行为当然可以被覆盖!

def withObject(object=this.getClass().getName()-"Controller", id="id", Closure c) { 
    assert object 
    def obj = grailsApplication.classLoader.loadClass(object).get(params[id]) 
    if(obj) { 
     c.call obj 
    } else { 
     flash.message = "The object was not found" 
     redirect action: "list" 
    } 
} 

所以所有的答案都有助于解决方案!非常感谢!

+4

请编辑该问题并添加代码示例。目前这个问题非常模糊。 – ordnungswidrig

回答

8

我总是拔出这篇博客时,这个问题来了:

http://mrpaulwoods.wordpress.com/2011/01/23/a-pattern-to-simplify-grails-controllers/

基本上你在你的控制器各个领域的私人助手。

private def withPerson(id="id", Closure c) { 
    def person = Person.get(params[id]) 
    if(person) { 
     c.call person 
    } else { 
     flash.message = "The person was not found." 
     redirect action:"list" 
    } 
} 

你的代码,吸气的方式是非常灵活,对我来说是典型的使用(即不包括在博客)是一个用于编辑等。

我通常这样的代码(我喜欢它的明确分工和可读性模式):

def editIssue() { 
    withIssue { Issue issue -> 
     def issueTypes = IssueTypeEnum.values().collect {it.text } 
     [issueTypes:issueTypes,activePage:"issue", issue: issue] 
    } 
} 

def doEditIssue(IssueCommand cmd) { 
    if(cmd.validate()) { 
     withIssue { Issue issue -> 
      issue.updateIssue(cmd) 
      redirect(action: "show", id: issue.id) 
     } 
    } 
    else { 
     def issueTypes = IssueTypeEnum.values().collect {it.text } 
     render(view: "edit", model:[issueTypes:issueTypes,issue:cmd,activePage:"issue"]) 
    } 
} 

用我的getter帮手之中:

private def withIssue(Closure c) { 
    def issue = Issue.get(params.id) 
    if(issue) { 
     c.call issue 
    } 
    else { 
     response.sendError(404) 
    } 
} 

我确实认为混入方法(非常类似于'扩展通用抽象控制器'的方式)也不错,但是这种方式给出了两个优点:

  1. 你可以键入帮助程序,就像你看到我在关闭时给你的方法等在STS/IDEA(未测试Netbeans)
  2. 重复不是很高,并且能够改变getter(用于例如BarDomain.findByFoo(params.id)等)

在我绑定到编辑视图()我只是把在<g:form>id="${issue.id}"和它的作品完美。

+0

感谢您的评论,我或多或少地将此线程中的一些答案与我身边的工作解决方案结合在一起。我将mixin策略与某种通用的withObject方法一起使用。我将用我现在使用的代码更新我的问题。 – Marco

0

使用常用方法实现抽象控制器(使用'受保护'指令)并从中扩展您的真实控制器。不要在此方法名称的开头使用'get'和'set'字样。不好,但它有效。

+1

为什么你建议不要在此方法名称的开头使用'get'和'set'字样? – gotomanners

+0

以避免将它们识别为“吸气剂”或“吸气剂”。 – jenk

6

我不会推荐继承,因为你不能在几个超类中传播泛型方法。如果你有很多控制器,你的抽象类很快就会变得混乱。您不能使用组合(例如使用服务),因为您无法直接从那里访问responserenderparams

我使用的方法是通过Mixins注入泛型方法。

@Mixin(ControllerGenericActions) 
@Mixin(ControllerUtil) 
class BookController { 
    def show = &genericShow.curry(Book) 

    def exists = { 
    render(idExists(Book)) 
    } 
} 

第一动作show使用通用方法在ControllerGenericActions.groovy,具有绑定到它的参数。 mixin idExists方法的第二次使用在控制器操作中。

下面是在这种情况下src/groovy/ControllerGenericActions.groovy

class ControllerGeneric { 
    def genericShow(Class clazz) { 
    render clazz.get(params.id) as XML 
    } 
} 

的示例代码和src/groovy/ControllerUtil.groovy

class ControllerUtil { 
    def idExists (Class clazz) { 
    return clazz.get(params.id) != null 
    } 

不是很有用,但你的想法。

+0

我并没有真正使用闭包,所以请原谅如果我犯了一个错误。但是,如果像'genericShow(Class clazz)'这样创建一个方法,你可以使用这种方法吗?我总是觉得一种方法不能被搞咖啡,但是可以关闭。 – Marco

+0

这就是在方法名前使用&的原因:它将一个方法变成了一个闭包。 – Antoine

+0

我对此解决方案有疑问:ControllerGeneric mixin单元是否可测试?我问,因为'渲染'是由Grails提供的一种方法,同时增强了控制器。 –