Использование Sitemesh в Grails 3

Я переношу набор приложений Grails 2.0.4 на версию 3.x. Все они развернуты на одном сервере вместе с рядом java-приложений. Оба набора приложений Java и Grails имеют общий внешний вид, используя шаблоны sitemesh и freemarker. Но с grails 3.x я не могу заставить работать общее оформление, приложение настаивает на использовании layouts/main.gsp вместо этого для отображения моего gsp.

До сих пор (grails 2.0.4) предоставление общего оформления было довольно простым; файл /WEB-INF/decorators.xml каждого приложения Grails содержит ссылки на применимые шаблоны freemarker. И web.xml включает в себя фильтр sitemesh и объявления и сопоставления сервлета декоратора freemarker.

декораторы.xml:

<?xml version="1.0" encoding="UTF-8"?>
<decorators defaultdir="/">
    <excludes>
        <pattern>/ND/*</pattern>
        <pattern>/*/ND/*</pattern>
     </excludes>
     <decorator name="freemarker" page="myftl.ftl">
         <pattern>/*</pattern>
     </decorator>
</decorators>

Фильтр Sitemesh и сервлет freemarker из web.xml:

<filter>
    <filter-name>sitemesh</filter-name>
    <filter-class>org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
<servlet>
    <servlet-name>sitemesh-freemarker</servlet-name>
    <servlet-class>com.opensymphony.module.sitemesh.freemarker.FreemarkerDecoratorServlet</servlet-class>
    <init-param>
      <param-name>TemplatePath</param-name>
      <param-value>class://</param-value>
    </init-param>    
    <init-param>
      <param-name>default_encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>          
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>sitemesh-freemarker</servlet-name>
    <url-pattern>*.ftl</url-pattern>
</servlet-mapping>

Что я пробовал:

  • Я переместил decorators.xml в папку src/main/webapp/WEB-INF.
  • В Grails 3.x фильтр sitemesh больше не присутствует, поэтому я удалил sitemesh.xml.
  • web.xml не используется, поэтому я определил сервлет freemarker в spring/resources.groovy:

ресурсы.groovy:

beans = {
    sitemeshFreemarkerServlet(ServletRegistrationBean) {
        servlet = bean(FreemarkerDecoratorServlet)
        urlMappings = ["*.ftl"]
        loadOnStartup = 2
    }
}

Однако приложения Grails 3.x настаивают на использовании layouts/main.gsp для отображения моих gsp-страниц. Кажется, что decorators.xml не обрабатывается. Что мне не хватает?


person Juan López    schedule 02.02.2016    source источник


Ответы (1)


Может быть, это уродливый хак, но вы можете наложить свою обработку сетки сайта на обработку Grails:

  • Зарегистрируйте пользовательский фильтр sitemesh в классе Application (или spring/resources.groovy):

    @Bean
    FilterRegistrationBean sitemeshFilterRegistrationBean() {
        FilterRegistrationBean reg=new FilterRegistrationBean()
        reg.setFilter(new MySitemeshFilter());
        reg.setInitParameters(["configFile":"WEB-INF/my.sitemesh.xml"])
        reg.setUrlPatterns(["/*"])
        reg.setDispatcherTypes(DispatcherType.REQUEST,DispatcherType.ERROR);
        reg.setOrder(0);
        return reg;
    }

  • Конфигурация sitemesh не должна быть стандартной, потому что Grails продолжает ее читать.
  • Зарегистрируйте сервлет freemarker для обработки ftl:

    @Bean
    ServletRegistrationBean freeMarkerServletRegistrationBean(){
        ServletRegistrationBean reg=new ServletRegistrationBean(new 
          FreemarkerDecoratorServlet(),"*.ftl");
        reg.addInitParameter("TemplatePath", "class://");
        reg.addInitParameter("default_encoding", "UTF-8");
        // etc
        return reg;
    }

  • Добавьте пользовательский фильтр sitemesh:
 
import com.opensymphony.module.sitemesh.Config;
import com.opensymphony.module.sitemesh.Factory
import com.opensymphony.module.sitemesh.factory.DefaultFactory;
import com.opensymphony.sitemesh.ContentProcessor;
import com.opensymphony.sitemesh.DecoratorSelector;
import com.opensymphony.sitemesh.compatability.DecoratorMapper2DecoratorSelector;
import com.opensymphony.sitemesh.webapp.SiteMeshWebAppContext;

import grails.util.Holders;
import javax.servlet.FilterConfig

class MySitemeshFilter extends com.opensymphony.sitemesh.webapp.SiteMeshFilter {

    private static final String MY_SITEMESH_FACTORY = "my.sitemesh.factory";
    private FilterConfig filterConfig;
    @Override   
    public void init(FilterConfig filterConfig) {
        super.init(filterConfig);
        filterConfig.getServletContext().setAttribute("grailsApplication", Holders.grailsApplication);
        this.filterConfig=filterConfig;
    }

    protected Factory getFactory(FilterConfig filterConfig) {
        Config config=new Config(filterConfig)
        Factory f=(Factory)config.getServletContext().getAttribute(MY_SITEMESH_FACTORY);
        if (f==null) {
            f=new DefaultFactory(config);
            config.getServletContext().setAttribute(MY_SITEMESH_FACTORY, f);
        }
        return f;
    }

    @Override
    protected DecoratorSelector initDecoratorSelector(SiteMeshWebAppContext webAppContext) {
        Factory factory = getFactory(filterConfig);
        factory.refresh();
        return new DecoratorMapper2DecoratorSelector(factory.getDecoratorMapper());
    }
}

  • В этом фильтре вы должны переопределить селектор декоратора в новой фабрике сетки сайта, потому что по умолчанию используется синглтон (sic), и Grails уже зарегистрировал его для своей внутренней обработки gsp.
  • Вы не должны переопределять обработчик содержимого (метод initContentProcessor), чтобы позволить Grails обрабатывать gsp с фабрикой sitemesh по умолчанию.
  • Если вы хотите получить больше функций (например, исключенные шаблоны), вам нужно будет переопределить весь метод doFilter, чтобы использовать ваш новый contentProcessor в contentProcessor.handles(webAppContext).
  • Добавьте свои my.sitemesh.xml и decorators.xml в src/main/webapp/WEB-INF.
  • Я добавил GrailsApplication в контекст сервлета при инициализации фильтра, чтобы вы могли использовать его в шаблонах ftl.
  • Если вы хотите пропустить некоторые макеты, добавьте условия по среде во внутренний макет Grails.
person jneira    schedule 09.02.2016
comment
Возможно, это не лучшее решение, но оно работает! Большое спасибо! - person Juan López; 09.02.2016