I'm migrating a set of grails 2.0.4 applications to version 3.x. All of them are deployed in the same server together with a number of java applications. Both sets of java and grails applications have a common look and feel using sitemesh and freemarker templates. But with grails 3.x I can't make the commond decoration work, the application insists in using layouts/main.gsp to render my gsp instead.
So far (grails 2.0.4) providing a common decoration is rather straight; the file /WEB-INF/decorators.xml of each grails application provides with references to the applicable freemarker templates. And the web.xml includes the sitemesh filter and the freemarker decorator servlet declarations and mappings
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>
Sitemesh filter and freemarker servlet from 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>
What I've tried:
resources.groovy:
beans = {
sitemeshFreemarkerServlet(ServletRegistrationBean) {
servlet = bean(FreemarkerDecoratorServlet)
urlMappings = ["*.ftl"]
loadOnStartup = 2
}
}
However, the grails 3.x applications insists in using layouts/main.gsp to render my gsp pages. It seems that decorators.xml is not being processed. What am I missing?
Maybe is a ugly hack, but you could superpose your sitemesh processing to grails one:
@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;
}
@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());
}
}
contentProcessor.handles(webAppContext)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With