zoukankan      html  css  js  c++  java
  • SiteMesh3整合SpringMVC+FreeMarker

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

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

    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>

    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, 0this.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);
      }



  • 相关阅读:
    podium服务器端的微前端开发框架
    几个java proxy servlet 工具
    Presto Infrastructure at Lyft
    cube.js 通过presto-gateway 进行连接
    presto-gateway nodejs client
    presto-gateway 试用以及docker 镜像制作
    presto-gateway lyft 团队开源的prestodb 的负载均衡、代理、网关工具
    Singer 修改tap-s3-csv 支持minio 连接
    plotly-dash 简单使用(一)
    smashing 三方widgets 使用
  • 原文地址:https://www.cnblogs.com/lzrabbit/p/5176992.html
Copyright © 2011-2022 走看看