jsp改造之sitemesh注意事项


title: jsp改造之sitemesh注意事项 tags:

  • sitemesh
  • jsp
  • html
  • body categories: 工作日志 date: 2017-12-23 10:50:38

背景

  1. 现在各种现代化的浏览器确实惯坏了开发者 智能纠错 无论是忘记关闭标签甚至重复等等都有可能被chrome这些浏览器智能纠错===》chrome会合并多个body
  2. 使用jsp开发的小伙伴新开一个新的组件页面时可能从原先的页面拷贝而来 那么里面包含了如下一些
        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
        <html>
        <head>
            <base href="<%=basePath%>">
            <meta http-equiv="pragma" content="no-cache">
            <meta http-equiv="cache-control" content="no-cache">
            <meta http-equiv="expires" content="0">
            <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
         
            <meta http-equiv="description" content="首页">
            <jsp:include page="${path}/WEB-INF/page/common/reference.jsp"/>
            <script type="text/javascript" src="${staticPath}/js/index/index.js"></script>
            <script type="text/javascript" src="${staticPath}/js/index/scroll.js"></script>
            <script type="text/javascript" src="<%=path%>/plugins/slider/slider.js"></script>
            <script type="text/javascript">
                var sessionIdOrg = "${sessionScope.organization.pkId}";
            </script>
        </head>
        <body class="mainBody">
        </body>
        </html>
复制代码
 
复制代码

这样造成一个页面从jsp处理完毕后输出的响应流会包含多个

可以参考

一个html文档可以有两组标签吗?

 

问题

多个body对于chrome来说会做自动忽略,那么对于我们使用sitemesh呢???

这个问题自然是存在的 否则也就不会有这篇博客了!

sitemesh的工作原理很单纯 使用filter对响应进行拦截,如果返回的是html那么判断是否需要进行装饰。如果需要找到合适的装饰模板进行装饰 并返回新的响应!

代码

对于sitemesh 默认来说会注入规则CoreHtmlTagRuleBundle

    public void install(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
        // Core rules for SiteMesh to be functional.
        defaultState.addRule("head", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("head"), false));
        defaultState.addRule("title", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("title"), false));
        defaultState.addRule("body", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("body"), false));
        defaultState.addRule("meta", new MetaTagRule(contentProperty.getChild("meta")));
     
        // Ensure that while in <xml> tag, none of the other rules kick in.
        // For example <xml><book><title>hello</title></book></xml> should not affect the title of the page.
        defaultState.addRule("xml", new StateTransitionRule(new State()));
    }
     
    public void cleanUp(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
        // In the event that no <body> tag was captured, use the default buffer contents instead
        // (i.e. the whole document, except anything that was written to other buffers).
        if (!contentProperty.getChild("body").hasValue()) {
            contentProperty.getChild("body").setValue(contentProperty.getValue());
        }
    }
复制代码

从这边可以看出body使用的规则是ExportTagToContentRule

我们细看一下ExportTagToContentRulede的源码

    /**
     * Exports the contents of a match tag to property of the passed in {@link ContentProperty}.
     *
     * Additionally, if this tag has attributes, they will be written as child properties.
     *
     * <h3>Example</h3>
     *
     * <pre>
     * // Java
     * myState.addRule("foo", new ExportTagToContentRule(content, "bar");
     *
     * // Input
     * <foo x=1 b=2>hello&lt/foo>
     *
     * // Exported properties of Content
     * bar=hello
     * bar.x=1
     * bar.b=2
     * </pre>
     *
     * @author Joe Walnes
     */
    public class ExportTagToContentRule extends BasicBlockRule {
     
        private final ContentProperty targetProperty;
        private final boolean includeInContent;
        private final SiteMeshContext context;
    ;
        /**
         * @param targetProperty   ContentProperty to export tag contents to.
         * @param includeInContent Whether the tag should be included in the content (if false, it will be stripped
         *                         from the current ContentProperty that is being written to.
         * @see ExportTagToContentRule
         */
        public ExportTagToContentRule(SiteMeshContext context, ContentProperty targetProperty, boolean includeInContent) {
            this.targetProperty = targetProperty;
            this.includeInContent = includeInContent;
            this.context = context;
        }
     
        @Override
        protected Object processStart(Tag tag) throws IOException {
            // Some terminology:
            // Given a tag: '<foo>hello</foo>'
            // INNER contents refers to 'hello'
            // OUTER contents refers to '<foo>hello</foo>'
             
            Tag t = tag;
     
            // Export all attributes of the opening tag as child nodes on the target ContentProperty.
            for (int i = 0; i < t.getAttributeCount(); i++) {
                // attributes of tags using this rule doesn't expand sitemesh:write
                // https://github.com/sitemesh/sitemesh3/issues/23
                String value = t.getAttributeValue(i);
                 
                // only if there might be another tag inside the attribute
                if(value != null && (value.indexOf('<') < value.indexOf('>'))){
                    StringBuilder sb = new StringBuilder();
                    context.getContentProcessor().build(CharBuffer.wrap(value), context).getData().writeValueTo(sb);
                    value = sb.toString();
                     
                    if(!(t instanceof CustomTag)){
                        t = new CustomTag(t);
                    }
                       
                    CustomTag custom = (CustomTag) t;
                    custom.setAttributeValue(i, value);
                     
                }
                     
                targetProperty.getChild(t.getAttributeName(i)).setValue(value);
            }
     
            // Push a buffer for the OUTER contents.
            if (!includeInContent) {
                // If the tag should NOT be included in the contents, we use a data-only buffer,
                // which means that although the contents won't be written
                // back to the ContentProperty, they will be available in the main Content data.
                // See Content.createDataOnlyBuffer()
                tagProcessorContext.pushBuffer(targetProperty.getOwningContent().createDataOnlyBuffer());
            } else {
                tagProcessorContext.pushBuffer();
            }
     
            // Write opening tag to OUTER buffer.
            t.writeTo(tagProcessorContext.currentBuffer());
     
            // Push a new buffer for storing the INNER contents.
            tagProcessorContext.pushBuffer();
            return null;
        }
     
        @Override
        protected void processEnd(Tag tag, Object data) throws IOException {
            // Get INNER content, and pop the buffer for INNER contents.
            CharSequence innerContent = tagProcessorContext.currentBufferContents();
            tagProcessorContext.popBuffer();
     
            // Write the INNER content and closing tag, to OUTER buffer and pop it.
            tagProcessorContext.currentBuffer().append(innerContent);
            if (tag.getType() != Tag.Type.EMPTY) { // if the tag is empty we have already written it in processStart().
                tag.writeTo(tagProcessorContext.currentBuffer());
            }
            CharSequence outerContent = tagProcessorContext.currentBufferContents();
            tagProcessorContext.popBuffer();
     
            // Write the OUTER contents to the current buffer, which is now the buffer before the
            // tag was processed. Note that if !includeInContent, this buffer will not be written
            // to the ContentProperty (though it will be available in Content.getData()).
            // See comment in processStart().
            tagProcessorContext.currentBuffer().append(outerContent);
     
            // Export the tag's inner contents to
            if (!targetProperty.hasValue()) {
                targetProperty.setValue(innerContent);
            }
        }
    }
复制代码

可以看到export的最后做了判断为

    if (!targetProperty.hasValue()) {
               targetProperty.setValue(innerContent);
           }
复制代码

可以看到当页面上存在多个body标签时sitemesh只会输出第一个body里面的内容!!!

措施

虽然chrome如此智能,虽然我们也不用考虑对其他老旧慢浏览器的支持。但是对于一个合格的后端开发来说

html的输出格式还是要注意的。因此考虑将多余的body删除【大量引入popup的jsp的都包含了一整套的html body】

那么需要清除一些jsp中的多余的body

建议

新建的jsp如果不是页面【是指将会被include其他的jsp中】那么而建议用_打头

比如一个关于左侧导航的可以考虑使用_left.jsp

以_打头的jsp中不允许出现html body 等标签

小问题

有小伙伴发现sitemesh的script提取 也有同样的问题么?^_^

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值