title: sitemesh的script提取 tags:
- sitemesh
- jsp
- template
- script categories: 工作日志 date: 2017-12-23 10:50:38
背景
前文交代了一些使用sitemesh的背景土鳖的jsp改造
那么本着怎么简单怎么来的原则首先创建了一个通用模板
实现
- 修改pom文件引入sitemesh
<dependency>
<groupId>org.sitemesh</groupId>
<artifactId>sitemesh</artifactId>
<version>3.0.1</version>
</dependency>
复制代码
复制代码
- 修改webxml增加对应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>
复制代码
复制代码
- 新建sitemesh3.xml
<sitemesh>
<!-- 默认的装饰路径。如果没有配置其他的路径将启用默认路径,这个可以适用于所有路径 -->
<!-- Map default decorator. This shall be applied to all paths if no other paths match. -->
<mapping decorator="/WEB-INF/sitemesh/main.jsp"/>
<!-- 配置 不被装饰 的路径 -->
<!-- Exclude path from decoration. -->
<mapping path="/login/**" exclue="true"/>
<!-- 默认情况下,
sitemesh 只对 HTTP 响应头中 Content-Type 为 text/html 的类型进行拦截和装饰,
我们也可以添加更多的 mime 类型 -->
<mime-type>text/html</mime-type>
<mime-type>application/vnd.wap.xhtml+xml</mime-type>
<mime-type>application/xhtml+xml</mime-type>
<!--
Sitemesh 3 默认只提供了 body,title,head 种 tag 类型
我们可以添加自定义的tag规则 -->
</sitemesh>
复制代码
- 我们除了登录之外的所有html页面进行装饰
- 定义模板文件
<%@ page contentType="text/html; charset=utf-8" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>
<sitemesh:write property='title'/>
</title>
<sitemesh:write property='head'/>
</head>
<body class="mainBody">
<sitemesh:write property='body'/>
</body>
</html>
复制代码
- 这样很轻易就定义了一套模板
- 我们的目的是将script下沉到body的结尾 因此考虑增加scipt的提取
- 在sitemesh3.xml定义如下
<content-processor>
<tag-rule-bundle class="com.air.tqb.decorator.ScriptTagRuleBundle"/>
</content-processor>
复制代码
复制代码
- 新建sciptTag
/**
* @author qixiaobo
*/
public class ScriptTagRuleBundle implements TagRuleBundle {
private static final String TAG_SCRIPT = "script";
@Override
public void install(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
defaultState.addRule(TAG_SCRIPT, new ExportTagToContentRule(siteMeshContext, contentProperty.getChild(TAG_SCRIPT), false));
}
@Override
public void cleanUp(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
}
}
复制代码
- 修改main.jsp为
<%@ page contentType="text/html; charset=utf-8" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>
<sitemesh:write property='title'/>
</title>
<sitemesh:write property='head'/>
</head>
<body class="mainBody">
<sitemesh:write property='body'/>
<sitemesh:write property='script'/>
</body>
</html>
复制代码
复制代码
- 不过考虑可能存在一些问题 scipt提取出来 那么其中的一些src要复写等等 还比较麻烦
- 重启服务后结果大失所望 script并没有被提取
- 检索发现也有国外小伙伴和我的思路一样 stackoverflow.com/questions/1… 【不过已经是8年前的啦 当时还是sitemesh2吧】
- 考虑一下为啥script并没有被识别成tag呢?
- 查看源码后发现 sitemesh将script标签识别成
<YYINITIAL> {
"<!--" [^\[] ~"-->" { return TagTokenizer.Token.TEXT; } /* All comments unless they start with <!--[ */
"<!---->" { return TagTokenizer.Token.TEXT; }
"<?" ~"?>" { return TagTokenizer.Token.TEXT; }
"<!" [^\[\-] ~">" { return TagTokenizer.Token.TEXT; }
"<![CDATA[" ~"]]>" { return TagTokenizer.Token.TEXT; }
"<xmp" ~"</xmp" ~">" { return TagTokenizer.Token.TEXT; }
"<script" ~"</script" ~">" { return TagTokenizer.Token.TEXT; }
[^<]+ { return TagTokenizer.Token.TEXT; }
"<" { yybegin(ELEMENT); return TagTokenizer.Token.LT; }
"<!--[" { yybegin(ELEMENT); return TagTokenizer.Token.LT_OPEN_MAGIC_COMMENT; }
"<![" { yybegin(ELEMENT); return TagTokenizer.Token.LT_CLOSE_MAGIC_COMMENT; }
}
复制代码
- 原来sitemesh不能支持script标签啊!
- 似乎走到了绝路
- 不过假设真的支持script 那么一些属性的设置也很麻烦啊 比如src 比如async等等
- 灵光一闪 既然script不支持 那么我们可以仿照jsp定义自己的标签啊!
- 定义f6scriprt标签 该标签表示f6script中的数据将会移到body的末尾
- 那么思路豁然开朗 我们将之前reference中的一些js拆分 【jQuery等依然可以放在前面加载 大部分js依赖】非必须js 比如百度统计 比如客服js等等我们放在f6script块中
- 改造scriptTag
package com.air.tqb.decorator;
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;
/**
* @author qixiaobo
*/
public class ScriptTagRuleBundle implements TagRuleBundle {
private static final String TAG_SCRIPT = "f6script";
@Override
public void install(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
defaultState.addRule(TAG_SCRIPT, new ExportTagToContentRule(siteMeshContext, contentProperty.getChild(TAG_SCRIPT), false));
}
@Override
public void cleanUp(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
}
}
复制代码
- 修改模板文件为
<%@ page contentType="text/html; charset=utf-8" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>
<sitemesh:write property='title'/>
</title>
<sitemesh:write property='head'/>
</head>
<body class="mainBody">
<sitemesh:write property='body'/>
<sitemesh:write property='f6script'/>
</body>
</html>
复制代码
复制代码
- 在需要包装到结尾的js做如下处理 使用进行包装
- js会乖乖的跑到了body结束符前