Использовать несколько шаблонов / скинов GSP с плагином для нескольких арендаторов Grails? - PullRequest
2 голосов
/ 14 сентября 2011

У меня есть приложение, которое использует плагин multi-tenant core Grails для размещения нескольких версий сайта. Я хочу иметь возможность создавать собственные GSP для каждого сайта, помимо того, что мне позволяет делать простой скиннинг. По сути, я хочу, чтобы моя папка grails-app/views выглядела примерно так:

views
|
|__template1
|  |
|  |__layouts
|  |  |
|  |  |__main.gsp
|  |  
|  |__controller1
|     |    
|     |__index.gsp
|
|__template 2
   |
   |__layouts
   |  |
   |  |__main.gsp
   |  
   |__controller1
      |    
      |__index.gsp

А затем настройте конкретного клиента для использования определенного набора GSP. Я использую преобразователь DNS, который сохраняется в моей базе данных, поэтому я могу добавить свойство к классу домена DomainTenantMap, которое присваивает свойство templateDir конкретному арендатору, и распределить условную логику повсюду в моих GSP и контроллерах , (за этим следует чувство «не могу ... получить ... чистоту»)

Мне не удалось найти существующий плагин, который обеспечивает эту функциональность. Другие варианты, которые я рассмотрел, по-видимому, включают в себя настройку довольно основных частей grails (тег Render, движок шаблонов и т. Д.), Что заставляет меня нервничать.

Я понимаю, что это довольно широкий вопрос; приветствуются как конкретные решения, так и общие предложения.

EDIT:

Я нашел другой возможный подход, создав плагин и метапрограммирование по новому методу:

def configureTemplateRenderer(application, applicationContext) {
    for (controllerClass in application.controllerClasses) {

        controllerClass.metaClass.newRender = { args ->
            println 'something'
            if(args.view) {
                args.view = "/somedir/${args.view}"
            }
            if(args.template) {
                args.template = "/somedir/${args.template}"
            }
            delegate.render(args)
        }
    }
}

Это просто подтверждение концепции, чтобы увидеть, могу ли я вызвать стандартный метод render через свой новый (могу). В идеале, я мог бы полностью переопределить метод render, чтобы изменить свойства args.view и args.template на основе своего рода сопоставления арендатора / шаблона (не показано). Однако я не смог успешно переопределить метод render, поэтому это решение на самом деле лишь незначительно лучше, чем просто добавление некоторой переменной пути к вызовам render.

Решение!

Я закончил тем, что создал отдельный плагин, который сводится к переопределению метода рендеринга с тем, который проверяет карту клиента / шаблона. Все еще тестирую, но пока это выглядит многообещающе, вот суть этого:

def overrideRender = { application ->
    for (controllerClass in application.controllerClasses) {
        def original = controllerClass.metaClass.getMetaMethod("render", [Map] as Class[])
        def originalRender = original.getClosure()

        controllerClass.metaClass.originalRender = originalRender

        controllerClass.metaClass.render = { Map atts ->
            def templatePath = // some code to lookup against a TenantTenantMap
            if(templatePath) {
                if(atts.view) {
                    atts.view = "${templatePath}${atts?.view}"
                }
                if(atts.template) {
                    atts.template = "${templatePath}${atts?.template}"
                }
            }
            delegate.originalRender(atts)
        }
    }
}

Единственным недостатком является то, что мне приходится использовать немного более уродливую структуру каталогов, чем я хотел: views/controller/$template/action вместо объединения всех шаблонов gsps вместе в views/$template/controller/action. Я думаю, что могу жить с этим сейчас.

Ответы [ 2 ]

1 голос
/ 29 февраля 2012

Решение, которое я использовал:

def overrideRender = { application ->
    for (controllerClass in application.controllerClasses) {
        def original = controllerClass.metaClass.getMetaMethod("render", [Map] as Class[])
        def originalRender = original.getClosure()

        controllerClass.metaClass.originalRender = originalRender

        controllerClass.metaClass.render = { Map atts ->
            def templatePath = // some code to lookup against a TenantTenantMap
            if(templatePath) {
                if(atts.view) {
                    atts.view = "${templatePath}${atts?.view}"
                }
                if(atts.template) {
                    atts.template = "${templatePath}${atts?.template}"
                }
            }
            delegate.originalRender(atts)
        }
    }
}
0 голосов
/ 21 ноября 2011

Вы можете попробовать реализовать свой собственный Spring ViewResolver: http://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/web/servlet/ViewResolver.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...