SiteMesh3整合SpringMVC+FreeMarker

  • SiteMesh3配置
    • 添加maven依赖
    • 添加filter
    • 配置servlet
    • 添加sitemesh配置文件 
    • decorator示例
    • SpringMVC、FreeMarker配置(404问题处理)
    • decorate源码

 

SiteMesh3文档 http://wiki.sitemesh.org/wiki/pages/viewpage.action?pageId=1081348

重新搭建项目偶然发现SiteMesh有了新版本SiteMesh3,本着用新不用旧原则果断升级,多少遇了点坑,顺便记录下

 

 

 

SiteMesh3整合SpringMVC+FreeMarker_第1张图片

SiteMesh3配置

 

  1. 添加maven依赖

    <dependency>
         <groupId>org.sitemesh</groupId>
         <artifactId>sitemesh</artifactId>
         <version> 3.0 . 1 </version>
    </dependency>
  2. 添加filter

    在web.xml中添加filter

    <filter>
         <filter-name>sitemesh</filter-name>
         <filter- class >org.sitemesh.config.ConfigurableSiteMeshFilter</filter- class >
    </filter>
    <filter-mapping>
         <filter-name>sitemesh</filter-name>
         <url-pattern>/*</url-pattern>
    </filter-mapping>
  3. 配置servlet

    <servlet-mapping>
         <servlet-name> default </servlet-name>
         <url-pattern>*.ftl</url-pattern>
    </servlet-mapping>
  4. 添加sitemesh配置文件 

    1. 添加配置文件 sitemesh3.xml
      默认配置文件路径为:/WEB-INF/sitemesh3.xml 

      sitemesh3.xml
      < sitemesh >
           <!--
           By default, SiteMesh will only intercept responses that set the Content-Type HTTP header to text/html
           This can be altered to allow SiteMesh to intercept responses for other types.
           默认 SiteMesh 只对HTTP响应头中Content-Type为 text/html 的类型进行拦截和装饰,若需要处理其它mime类型需要自行添加配置
           -->
           < mime-type >text/html</ mime-type >
           <!--
           Map default decorator. This shall be applied to all paths if no other paths match.
           配置装饰器,仅设置decorator参数时表示为默认的装饰器,当没有任何路径被匹配时会使用默认装饰器装配
            -->
           < mapping  decorator = "/WEB-INF/decorators/decorator.ftl" />
           <!--对不同的路径指定特定的装饰器-->
           <!--<mapping path="/admin/*" decorator="/WEB-INF/decorators/admin-decorator.ftl"/>-->
           <!--
           Alternative convention. This is more verbose but allows multiple decorators to be applied to a single path.
           对同一路径可以同时使用多个装饰器
           -->
           < mapping >
               < path >/category/*</ path >
               < decorator >/WEB-INF/decorators/common-decorator.ftl</ decorator >
               < decorator >/WEB-INF/decorators/menu-decorator.ftl</ decorator >
               < decorator >/WEB-INF/decorators/category-decorator.ftl</ decorator >
           </ mapping >
           <!--
           Exclude path from decoration.
           排除路径,只需将exclue设置为true即可
           -->
           < mapping  path = "/static/*"  exclue = "true" />
           <!--
           An advanced feature of SiteMesh is the ability to define custom rules that manipulate tags on a page.
           These are classes that implement org.sitemesh.content.tagrules.TagRuleBundle.
           默认SiteMesh仅支持title、head、meta、body等tag,可以自定义tag,实现TagRuleBundle接口即可
           -->
           < content-processor >
               < tag-rule-bundle  class = "com.sankuai.shangchao.util.HtmlTagRuleBundle" />
           </ content-processor >
      </ sitemesh >
    2. 修改配置文件路径
      默认配置文件路径为:/WEB-INF/sitemesh3.xml 若需要修改配置文件路径需要在filter里配置configFile参数 

      <filter>
           <filter-name>sitemesh</filter-name>
           <filter- class >org.sitemesh.config.ConfigurableSiteMeshFilter</filter- class >
           <init-param>
               <param-name>configFile</param-name>
               <param-value>/WEB-INF/sitemesh3.xml</param-value>
           </init-param>
      </filter>
    3. 自定义tag

      HtmlTagRuleBundle.java
      import  org.sitemesh.SiteMeshContext;
      import  org.sitemesh.content.ContentProperty;
      import  org.sitemesh.content.tagrules.TagRuleBundle;
      import  org.sitemesh.content.tagrules.html.ExportTagToContentRule;
      import  org.sitemesh.tagprocessor.State;
       
      /**
        * Description: FootTagRuleBundle
        * Author: liuzhao
        * Create: 2015-08-22 09:21
        */
      public  class  HtmlTagRuleBundle  implements  TagRuleBundle {
           @Override
           public  void  install(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
               defaultState.addRule( "foot" new  ExportTagToContentRule(siteMeshContext, contentProperty.getChild( "foot" ),  false ));
           }
       
           @Override
           public  void  cleanUp(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
       
           }
  5. decorator示例

    decorator配置页面布局layout,对应的tag会被进行装饰替换

    decorator.ftl
    <!DOCTYPE html>
    < html >
    < head >
         < title >
             < sitemesh:write  property = "title" />
         </ title >
         < sitemesh:write  property = 'head' />
    </ head >
    < body >
    < h1 >啦拉拉,我是卖报的小行家</ h1 >
    < sitemesh:write  property = 'body' />
    < sitemesh:write  property = "foot" />
    </ body >
    </ html >
  6. SpringMVC、FreeMarker配置(404问题处理)

    sitemesh3是完全独立的,不和任何框架进行偶合,因此SpringMVC、FreeMarker配置完全不需要考虑sitemesh3的兼容问题
    在加载装饰器的时候,会出现404问题,可能的原因是找不到ftl文件的解析器,所以需要配置下ftl使用默认的Servlet解析,在web.xml中添加如下配置

    <servlet-mapping>
         <servlet-name> default </servlet-name>
         <url-pattern>*.ftl</url-pattern>
    </servlet-mapping>

     

SiteMesh3整合SpringMVC+FreeMarker_第2张图片

  1. decorate源码

    @Override
    protected  boolean  postProcess(String contentType, CharBuffer buffer,
                                   HttpServletRequest request, HttpServletResponse response,
                                   ResponseMetaData metaData)
             throws  IOException, ServletException {
         WebAppContext context = createContext(contentType, request, response, metaData);
         Content content = contentProcessor.build(buffer, context);
         if  (content ==  null ) {
             return  false ;
         }
     
         String[] decoratorPaths = decoratorSelector.selectDecoratorPaths(content, context);
         //遍历装饰器进行装饰
         for  (String decoratorPath : decoratorPaths) {
             content = context.decorate(decoratorPath, content);
         }
     
         if  (content ==  null ) {
             return  false ;
         }
         try  {
             content.getData().writeValueTo(response.getWriter());
         catch  (IllegalStateException ise) {   // If getOutputStream() has already been called
             content.getData().writeValueTo( new  PrintStream(response.getOutputStream()));
         }
         return  true ;
    }
     
    public  Content decorate(String decoratorName, Content content)  throws  IOException {
         if  (decoratorName ==  null ) {
             return  null ;
         }
     
         class  CharBufferWriter  extends  CharArrayWriter {
             public  CharBuffer toCharBuffer() {
                 return  CharBuffer.wrap( this .buf,  0 this .count);
             }
         }
         CharBufferWriter out =  new  CharBufferWriter();
         decorate(decoratorName, content, out);
     
         CharBuffer decorated = out.toCharBuffer();
     
         Content lastContent = currentContent;
         currentContent = content;
         try  {
             return  contentProcessor.build(decorated,  this );
         finally  {
             currentContent = lastContent;
         }
    }
     
    @Override
    protected  void  decorate(String decoratorPath, Content content, Writer out)  throws  IOException {
         HttpServletRequest filterableRequest =  new  HttpServletRequestFilterable(request);
         // Wrap response so output gets buffered.
         HttpServletResponseBuffer responseBuffer =  new  HttpServletResponseBuffer(response, metaData,  new  BasicSelector( new  PathMapper<Boolean>(), includeErrorPages) {
             @Override
             public  boolean  shouldBufferForContentType(String contentType, String mimeType, String encoding) {
                 return  true // We know we should buffer.
             }
         });
         responseBuffer.setContentType(response.getContentType());  // Trigger buffering.
     
         // It's possible that this is reentrant, so we need to take a copy
         // of additional request attributes so we can restore them afterwards.
         Object oldContent = request.getAttribute(CONTENT_KEY);
         Object oldContext = request.getAttribute(CONTEXT_KEY);
     
         request.setAttribute(CONTENT_KEY, content);
         request.setAttribute(CONTEXT_KEY,  this );
     
         try  {
             // Main dispatch.
             dispatch(filterableRequest, responseBuffer, decoratorPath);
     
             // Write out the buffered output.
             CharBuffer buffer = responseBuffer.getBuffer();
             out.append(buffer);
         catch  (ServletException e) {
             //noinspection ThrowableInstanceNeverThrown
             throw  (IOException)  new  IOException( "Could not dispatch to decorator" ).initCause(e);
         finally  {
             // Restore previous state.
             request.setAttribute(CONTENT_KEY, oldContent);
             request.setAttribute(CONTEXT_KEY, oldContext);
         }
    }
     
    protected  void  dispatch(HttpServletRequest request, HttpServletResponse response, String path)
             throws  ServletException, IOException {
         //这里调用加载文件会出现404错误 /WEB-INF/decorators/decorator.ftl
         RequestDispatcher dispatcher = servletContext.getRequestDispatcher(path);
         if  (dispatcher ==  null ) {
             throw  new  ServletException( "Not found: "  + path);
         }
         dispatcher.forward(request, response);
    }



 

你可能感兴趣的:(SiteMesh3整合SpringMVC+FreeMarker)