SiteMesh3整合SpringMVC+FreeMarker

 

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

從新搭建項目偶然發現SiteMesh有了新版本SiteMesh3,本着用新不用舊原則果斷升級,多少遇了點坑,順便記錄下java

 

 

 

SiteMesh3配置

 

  1. 添加maven依賴

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

    在web.xml中添加filterweb

    <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 app

      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. 自定義tagmaven

      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會被進行裝飾替換ide

    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>

     

  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);
    }
相關文章
相關標籤/搜索