在 Grails 3 中使用 Sitemesh

Posted

技术标签:

【中文标题】在 Grails 3 中使用 Sitemesh【英文标题】:Use of Sitemesh in Grails 3 【发布时间】:2016-05-11 11:16:18 【问题描述】:

我正在将一组 grails 2.0.4 应用程序迁移到 3.x 版。所有这些都部署在同一台服务器上,并与许多 java 应用程序一起。两组 java 和 grails 应用程序使用 sitemesh 和 freemarker 模板具有共同的外观和感觉。 但是对于 grails 3.x,我无法使 commond 装饰工作,应用程序坚持使用 layouts/main.gsp 来渲染我的 gsp。

到目前为止(grails 2.0.4)提供一个通用的装饰是相当直接的;每个 grails 应用程序的 /WEB-INF/decorators.xml 文件都提供了对适用的 freemarker 模板的引用。而 web.xml 包括 sitemesh 过滤器和 freemarker 装饰器 servlet 声明和映射

装饰器.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】:

也许是一个丑陋的 hack,但您可以将您的站点网格处理叠加到 grails 上:

在 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 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; 添加自定义站点网格过滤器: 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 如果您想获得更多功能(如排除模式),您需要覆盖整个 doFilter 方法以使用 contentProcessor.handles(webAppContext) 中的新 contentProcessor 在 src/main/webapp/WEB-INF 中添加您的 my.sitemesh.xml 和 decorators.xml 我已在过滤器初始化中将 grailsApplication 添加到 servlet 上下文,以便您可以在 ftl 模板中使用它 如果您想跳过某些布局,请在内部 grails 布局中按环境添加条件

【讨论】:

也许不是最好的解决方案,但它确实有效!非常感谢!

以上是关于在 Grails 3 中使用 Sitemesh的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Grails 3.0 中使用 jQuery

我如何在 grails 2.3.1 中使用控制器来休息 api?

IntelliJ 中的 Grails 3 调试

在 Grails 3.3.11 中无法使用 Spring Security 运行应用程序

Grails 3 - 资源插件

在Grails 3中运行Grails功能测试