在Grails 3中使用Sitemesh

6
我正在将一组Grails 2.0.4应用程序迁移到3.x版本。所有这些应用程序都与一些Java应用程序一起部署在同一台服务器上。使用Sitemesh和Freemarker模板,两组Java和Grails应用程序具有共同的外观和感觉。 但是,在Grails 3.x中,我无法使常见的装饰工作,该应用程序坚持使用layouts/main.gsp来渲染我的GSP。
到目前为止(Grails 2.0.4),提供共同的装饰相当简单;每个Grails应用程序的/WEB-INF/decorators.xml文件提供对适用的Freemarker模板的引用。而web.xml包括Sitemesh过滤器和Freemarker装饰器servlet声明和映射。
decorators.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>

在web.xml中添加Sitemesh过滤器和Freemarker Servlet:

<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未被使用,因此现在我在spring/resources.groovy中定义了freemarker servlet:

resources.groovy:

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

然而,Grails 3.x 应用程序坚持使用 layouts/main.gsp 来呈现我的 GSP 页面。看起来 decorators.xml 没有被处理。我错过了什么吗?
1个回答

4
也许这是一个丑陋的hack,但是你可以将你的sitemesh处理与grails合并:
  • 在Application类(或spring/resources.groovy)中注册自定义的sitemesh过滤器:

    @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 servlet以处理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()); } }
  • 在这个过滤器中,你需要在一个新的sitemesh工厂中重写装饰器选择器,因为默认的工厂是单例的,并且Grails已经为其内部的GSP处理注册了它。
  • 为了让Grails使用默认的sitemesh工厂处理GSP页面,你不应该覆盖内容处理器(initContentProcessor方法)。
  • 如果你想要获取更多功能(比如排除模式),你需要覆盖整个doFilter方法,用你的新contentProcessor在contentProcessor.handles(webAppContext)中进行处理。
  • 将my.sitemesh.xml和decorators.xml添加到src/main/webapp/WEB-INF中。
  • 我在过滤器初始化中将grailsApplication添加到servlet上下文中,以便你可以在ftl模板中使用它。
  • 如果你想跳过某些布局,请在内部Grails布局中根据环境添加条件。

也许不是最好的解决方案,但它能够工作!非常感谢! - Juan López

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接