grails - 在 Grails 3 中使用 Sitemesh

标签 grails sitemesh grails-3.1

我正在将一组 grails 2.0.4 应用程序迁移到版本 3.x。它们都与许多java应用程序一起部署在同一台服务器上。两组 java 和 grails 应用程序都使用 sitemesh 和 freemarker 模板,具有共同的外观和感觉。 但在 grails 3.x 中,我无法使通用装饰工作,应用程序坚持使用 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:

资源.groovy:

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

但是,grails 3.x 应用程序坚持使用layouts/main.gsp 来呈现我的gsp 页面。看来decorators.xml 没有被处理。我错过了什么?

最佳答案

也许这是一个丑陋的黑客,但你可以将你的 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 工厂中的装饰器选择器,因为默认选择器是单例 (sic),并且 grails 已将其注册用于其内部 gsp 处理
  • 不应该重写内容处理器(initContentProcessor 方法),让 grails 使用默认的 sitemesh 工厂处理 gsp
  • 如果您想获得更多功能(例如排除的模式),则需要重写整个 doFilter 方法以在 contentProcessor.handles(webAppContext) 中使用新的 contentProcessor
  • 在 src/main/webapp/WEB-INF 中添加 my.sitemesh.xml 和decorators.xml
  • 我已在过滤器初始化中将 grailsApplication 添加到 servlet 上下文,以便您可以在 ftl 模板中使用它
  • 如果您想跳过某些布局,请在内部 grails 布局中按环境添加条件

关于grails - 在 Grails 3 中使用 Sitemesh,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35157053/

相关文章:

Grails Spring Security 3服务springSecurityService为空

Grails 2.x - 如何保留一个 URL 映射的文件扩展名?

grails - 如何排除Grails项目中某个jar依赖的特定包?

java - 每页 Sitemesh 自定义 javascript

grails - 将 Grails 3.1.1 部署到 Heroku

grails - 运行应用程序与 war 执行之间的不一致

grails - 有没有一种有效的方法可以从从数据库加载的字符串中调用 Grails 模板?

spring-mvc - 使用 Spring MVC、Sitemesh、Freemarker 导入 spring.ftl

rest - grails 3 Rest-api 配置文件 GET

grails - Jenkins的Grails 3.1.2项目:未知的命令行选项 '-n'