Делать контроллеры Grails более сухими? - PullRequest
11 голосов
/ 25 ноября 2011

Я ищу способы очистки кода моего контроллера 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"
    }
}

Так что все ответы внесли свой вклад в решение!Большое спасибо!

Ответы [ 3 ]

8 голосов
/ 25 ноября 2011

Я всегда вытаскиваю это сообщение в блоге, когда возникает этот вопрос:

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"])
    }
}

С моим помощником-получателем:

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

Я действительно считаю, что метод mixin (очень похож на способ «расширить общий абстрактный контроллер»)) тоже неплохо, но этот способ дает два преимущества:

  1. Вы можете напечатать помощника, как вы видите в закрытии, что дает вам доступ к методам и т. д. в STS / IDEA (не проверено Netbeans)
  2. Повторяемость не очень высокая, и возможность менять геттер (использовать, например, BarDomain.findByFoo (params.id) и т. Д.)

В представлении, которое я связываюдля редактирования () я просто положил id="${issue.id}" в <g:form>d это работает без проблем.

6 голосов
/ 25 ноября 2011

Я бы не рекомендовал наследование для этого, так как вы не можете распространять универсальные методы в нескольких суперклассах. Ваш абстрактный класс быстро станет беспорядочным, если у вас будет много контроллеров. Вы не можете использовать композицию (например, используя Сервис), потому что у вас нет доступа к response, render или params непосредственно оттуда.

Подход, который я использую, заключается в том, чтобы вводить универсальные методы через 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 голосов
/ 25 ноября 2011

Реализуйте абстрактный контроллер с помощью распространенных методов (используйте директиву protected) и расширяйте его до реальных контроллеров. Не используйте слова «get» и «set» в начале имен этого метода. Не хорошо, но это работает.

...