学习编写标记文件(tag)下

接下来我们看一个属性的扩展功能 - 属性片段(attribute fragment), 先解译什么是片段, 大家可以
把片段看作一段jsp代码, JSP规范中所谓的jsp fragment, 例如我们之前使用了jsp:doBody读取的主
体内容就是一个片段. 我们可以将一段巳命名的片段(named fragment)作为一个标记的属性使用, 并
而在标记中多次或一次调用这个传入的片段. 要调用这个片段, 我们使用另一个标淮动作:

<jsp:invoke/>

它是一个空标记, 有以下的属性:

1) fragment - 要调用的片段名.

2) var - 给出变量名, 把片段经过jsp容器计算过之後的结果作为字符串保存.

3) varReader - 同上, 不过将结果作为一个java.io.Reader保存.

4) scope - 作用域= =, 有var就有它, 不多说了, 默认page.

当然, 叫做属性片段, 我们必须告诉jsp容器标记中那些标记属性的内容会是片段而不是静态文本. 我
们可以在属性元素上加上fragment="true"这个属性:

<%@ attribute name="name" fragment="true" %>

接下来我们再编写一个标记来演试一下属性片段的应用, 我们在others标记库中新增一个"invoke"
标记, 加上tag指令, 建立两个属性fragment1跟fragment2, 用来接收两个属性片段, 以下给出完整
代码, 大家也可以直接打开"/WEB-INF/tags/others/invoke.tag":

<%--
others标记库invoke标记

功能: 演试属性片段
--%>
<%@ tag body-content="scriptless" pageEncoding="UTF-8" %>
<%@ attribute name="fragment1" fragment="true" %>
<%@ attribute name="fragment2" fragment="true" %>

<%-- 调用标准动作jsp:invoke显示读取的属性片段 --%>
<p style="font-size:24px; font-weight:bold">这里输出属性片段一的计算结果:</p>
<jsp:invoke fragment="fragment1"/>
<p style="font-size:24px; font-weight:bold">这里输出属性片段二的计算结果:</p>
<jsp:invoke fragment="fragment2"/>
<%-- 调用标准动作jsp:doBody显示读取的主体内容 --%>
<p style="font-size:24px; font-weight:bold">这里输出主体内容:</p>
<jsp:doBody/>

上面可以看到我们调用了两次<jsp:invoke fragment="xxx"/>, 大家可以把它看作一个占位符, 它的
位置就是读取的属性片段的计算结果. 最後我们再一次调用<jsp:doBody/>来读取主体内容.

不懂? 没关系, 下面我们先把调用页面"invoke.jsp"建立好, 细心观察浏览器出来的效果, 大家就可
以了解为什么我会说把<jsp:invoke/>看作一个占位符, 其实<jsp:doBody/>也是同一个工作原理, 下
面给出"invoke.jsp"的完整代码, 同样大家可以直接打开"/invoke.jsp":


<%-- others标记库invoke标记的演试 --%>
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%-- 调用自定义标记库others --%>
<%@ taglib tagdir="/WEB-INF/tags/others" prefix="others" %>
<%-- 调用自定义标记库string --%>
<%@ taglib tagdir="/WEB-INF/tags/string" prefix="string" %>

<html>
<head>
<title>others标记库invoke标记演试</title>
</head>
<body>
<%-- 使用invoke标记 --%>
<others:invoke>
<jsp:attribute name="fragment1"> <%-- 第一个片段我们引用helloworld标记 --%>
<others:helloworld/>
</jsp:attribute>
<jsp:attribute name="fragment2"> <%-- 第二个片段我们引用trim标记 --%>
<string:trim>
I am a boy!
</string:trim>
</jsp:attribute>
<jsp:body> <%-- 这里就是主体内容 --%>
这里就是<font color="red" size="25">主体内容</font>啦
</jsp:body>
</others:invoke>
</body>
</html>

(上面代码的排版有点乱, 注释本来是自己开新行的, 但是属性之间如果插入注释, 服务器会报错= =)

这个jsp页面包含我们今天所建立的另外两个标记"helloworld"跟"trim", 它们分别就是两个属性片段
的内容, 另外大家会看到<jsp:body>...</jsp:body>这个没介绍过的标准动作, 因为一个标记的主体
如果巳经包含了<jsp:attribute/>元素的话, 主体的内容就必须放到<jsp:body/>之内, jsp容器才可
正常的分别到哪些是属性, 哪个是主体, 所以以下的语法是不容许的:

<others:invoke>
<jsp:attribute name="fragment1">
属性一的内容
</jsp:attribute>
<jsp:attribute name="fragment2">
属性二的内容
</jsp:attribute>
<p>这里是主体内容...</p>
</others:invoke>

下来留一个小测试给大家, 打开"/invoke.jsp", 在<jsp:body/>标记内加上这一段代码:

${"a" == "a"}

重载"/invoke.jsp", 大家会发现在网页的末尾, 出现了"true"一字, 然後我们来开"/WEB/INF/
tags/others/invoke.tag", 把tag指令中的body-content属性改为"tagdependent", 重载
"/invoke.jsp"看有什么不一样?

接下来这个会是个难点, 这个部份希望大家可以返覆多看几遍, 试著修改一下例题来了解一下参数不
同会产生什么不一样的结果.

我们一直的工作流程都是, 一个jsp页面调用一个自定义的标记, 给它一些属性, 我们在标记里读取它
们, 然後处理代码, 返回给jsp容器, jsp容器计算结果後给jsp页面输出静态的文本, 那我们可不可以
在处理代码後, 把结果以变量的形式返回呢? 就好像我们写一个有返回值的函数一样? 可能大家会想
想我们有<c:set/>这个声明/赋值的标准动作, 但是想一下, 标记文件跟jsp页面是两个不同的page作
用域, 我们如果要传递变量的话就只有把变量放在session/application中了, 那不是很麻烦? 万一我
在jsp接收变量後没有把这个变量的内存空间释放掉, 那服务器有10GB内存也不够用了, 所以JSP规范
中提供了一个指令:

<%@ variable %>

它可以让我们在标记文件中的声明一个输出变量, 让jsp页面读取, 它有以下的属性:

1) name-given - 给这个变量取名.

2) name-from-attribute - 这个变量名由一个属性来决定(跟name-given只可选一).

3) alias - 给输出变量取别名(配合name-from-attribute使用).

4) variable-class - 给出输出变量类型, jsp容器会自动转换, 如果没指定为String.

5) scope - 输出变量在jsp页面上的更新模式, 可取值为: AT_BEGIN/AT_END/NESTED, 默认
为"NESTED".

相信第1,4属性大家都看懂, 第2,3属性我们在下一个例子中再说明, 我们来说明一下scope属性.

scope的3个可取值代表什么意思呢?

1) AT_BEGIN - 输出变量在标记文件的<jsp:doBody/>/<jsp:invoke/>之前及标记文件执行结
束後更新输出变量的值.

2) AT_END - 输出变量只有在标记文件执行结束後更新输出变量的值.

3) NESTED - 输出变量在标记文件的<jsp:doBody/>/<jsp:invoke/>之前更新输出变量的值,
在标记文件结束後, 将会把输出变量还原到在调用标记前的值

不懂? 我也搞了4个小时, 返覆的试验才清楚这三个取值有什么不一样. 现在不了解没有关系, 它们关
系到在标记文件中使用到<jsp:doBody/>/<jsp:invoke/>时, 其他的代码在这些动作之前之後的不同,
我们现在只需要记得一个不同就好了. 如果你需要把输出变量输出到jsp页面上(= =不然呢?), 就用
"AT_BEGIN", 如果你只需要在标记执行中在jsp页面读取到输出变量, 那就用"NESTED".

可能大家还是会搞混了, 我不就是为了输出一个变量到jsp页面吗? 你给我一个"NESTED"干吗? 其实输
出变量还有一个用途, 就是让标记文件可以把变量传到另一个标记文件上. 如果我的标记文体主体内
容是另一个标记, 我想把值传给它而巳, 并没有需要传到jsp页面的作用域上时, "NESTED"就有用了,
因为还原的意思是, 如果调用的jsp页面本来就没有声明这个输出变量, 那就代表输出变量只有在标记
主体执行时出现过, 结束後它就卸载了.

下面我们就来看一个例子吧(还是不懂? 就只用"AT_BEGIN"吧, 管它还不还原), 以下建立了一个新的
标记文件"variable.tag"在others标记库中, 同样的加入tag指令, 导入核心标记库(?), 以下给出完
整代码, 大家也可以直接打开"/WEB-INF/tags/others/variable.tag":

<%--
others标记库variable标记

功能: 演试variable指令输出变量的功能
--%>
<%@ tag body-content="empty" pageEncoding="UTF-8" %>
<%-- 导入核心标记库 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%-- 声明一个输出变量, 取名为"v" --%>
<%@ variable name-given="v" scope="AT_BEGIN" %>
<%-- 对输出变量赋值 --%>
<c:set var="v" value="这个就是标记文件的输出的内容"/>

为什么要使用要<c:set/>动作呢? 因为variable指令只是声明了一个变量, 我们还需要给它赋值, 下
面同样我们再建立一个"/variable.jsp", 看看jsp页面是如何读取到这个变量, 以下给出完整代码,
大家也可以直接打开"/variable.jsp":

<%-- others标记库variable标记的演试 --%>
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%-- 导入others标记库 --%>
<%@ taglib tagdir="/WEB-INF/tags/others" prefix="others" %>

<html>
<head>
<title>others标记库variable标记演试</title>
</head>
<body>
<%-- 调用variable标记并显示 --%>
<others:variable/>
输出变量v: ${v}
</body>
</html>

有了variable指令, 我们就可以把一个标记文件处理後的结果, 放到输出变量中, 再给它指定一个类
型, 作为另一个标记文件的属性传递, 是不是很方便呢?

但是问题来了, 这个输出变量的取名是标记文件定义的, 如果调用它的页面也有这个变量那怎办? 所
以我们下面来了解一下variable指令上"name-from-attribute"跟"alias"这两个属性, 怎样可以达成
"取别名"的效果.

我们来新建一个标记文件"alias"在"others"标记库中, 同样加入tag指令, 导入核心标记库, 然後我
声明一个属性, 它的作用就是用来存放输出变量的取名, 让调用页面可以传入一个字符值来决定输出
变量的取名, 然後我们使用variable指令:

<%@ variable name-from-attribute="output" alias="v" scope="AT_END" %>

"name-from-attribute"属性告诉jsp容器这个输出变量的取名为那个属性的值, 而"alias"属性就为
这个输出变量取一个别名, 以便在标记里使用这个变量, 以下给出完整代码, 大家也可以直接打开
"/WEB-INF/tags/others/alias.tag":

<%--
others标记库alias标记

功能: 演试variable指令的取别名功能
--%>
<%@ tag body-content="empty" pageEncoding="UTF-8" %>
<%-- 导入核心标记库 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%-- 存放输出变量的名称, 记得这个属性必须为静态文本及必须的 --%>
<%@ attribute name="output" required="true" rtexprvalue="false" %>
<%-- 声明输出变量, 在标记文件中使用别名为"v", 而在调用页面上的名称则
由属性output决定 --%>
<%@ variable name-from-attribute="output" alias="v" scope="AT_END" %>

<%-- 为输出变量赋值 --%>
<c:set var="v" value="<p>这个就是标记文件的输出的内容</p>"/>

同样的, 我们建立一个"/alias.jsp"来演试一下, 以下给出完整代码, 大家也可以直接打开
"/variable.jsp":

<%-- others标记库alias标记的演试 --%>
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%-- 导入others标记库 --%>
<%@ taglib tagdir="/WEB-INF/tags/others" prefix="others" %>

<html>
<head>
<title>others标记库alias标记的演试</title>
</head>
<body>
<%-- 调用alias标记, 对output属性赋值就可以自定义输出变量名 --%>
<others:alias output="super"/>
${super}
<%-- 试一下用别的名称 --%>
<others:alias output="haha"/>
${haha}
</body>
</html>

使用了"name-from-attribute"就可以避免命名冲突了, 记得存放输出变量取名的属性必须把
"rtexprvalue"设为假, 不然服务器也会报错的.

以上就是JSP规范2.0中新增的标记文件的语法介绍了^^

3. 打包

今天计一下我们都创建了8个自定义动作, 如果我们想要跟人家分享我的作品, 或者要去第三方部署的
话, 那就麻烦了, 所以以下我们学习怎样去把我们的标记库打包.

第一步, 我们先改变一下文件结构, 在网站根目录下, 创建一个"META-INF"文件夹, 然後把"WEB-INF"
里面的"tags"文件夹复制过去, 形成以下文件结构:

网站根目录/
META-INF/
tags/
maths/
...tag文件...
others/
...tag文件...
string/
...tag文件...
WEB-INF/
...tag文件夹...
...jsp文件...

我们先打包string标记库, 所以把"maths"跟"others"文件夹删除, 然後我们需要创建一个tld标签描
述文件(对, 又是它, XML又来了)在"META-INF"下, 复制下面的内容到文件开始:

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLScheme-instance"
xsi:schemeLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/sml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">

<!-- 标记库版本 -->
<tlib-version>1.0</tlib-version>
<!-- 命名空间前缀 -->
<short-name>string</short-name>
<!-- 文件夹名 -->
<uri>string</uri>

<!-- 包含的标记 -->

<tag-file>
<!-- 标记名 -->
<name>show</name>
<!-- 路径 -->
<path>/META-INF/tags/string/show.tag</path>
</tag-file>
<tag-file>
<name>trim</name>
<path>/META-INF/tags/string/trim.tag</path>
</tag-file>
</taglib>

taglib元素的一大串属性不用管它, 这个不是我们的讨论范围, 以後要写tld文件就复制过去就对了,
版本跟命名空间前缀也可以不管, 那个是给设计工具使用的, 没什么影响, uri元素必须为标记库的
文件夹名, 之後的tag-file元素声明了这个标签库里面有什么标记, 语法为:

...
<tag-file>
<name>标记名</name>
<path>相对路径</path>
</tag-file>
...

完成後打开"命令提示符", 转到网站的根目录, 输入下面的命令:

jar cvf string.jar META-INF

完成後大家就会看到根目录下新增了一个jar文件"string.jar", 把它放到"/WEB-INF/lib"之下就OK
了. 那我们再新建一个jsp页面来调用这个巳经打包好的标记库吧, 以下为"jar.jsp"的完整代码,
同样大家可以直接打开"/jar.jsp":

<%-- 使用jar文件导入标记库的演试 --%>
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%-- 导入string标记库包 --%>
<%@ taglib uri="string" prefix="string" %>

<html>
<head>
<title>使用jar文件导入标记库的演试</title>
</head>
<body>
<%-- 调用trim标记 --%>
<string:trim>
Please trim me!
</string:trim>

</body>
</html>

看到我们这一次taglib指令不再使用tagdir属性了, 直接用uri属性.

以上就是打包的全部讲解^^

P.S. 写在最後

因为开始要编写毕业的项目, 我发现班上有很多同学都没有能真正的掌握自定义标记的用法, 所以才
试著编写一篇讲解标记文件的文章, 顺便也可以放到BLOG上, 没想到一写就写了六百多行@"@. 但是
过程是非常愉快的, 写到一些知识点上发生自己也没搞清楚, 就跑去翻翻资料, 看看文献, 对自己本
身的能力也加强了好多, 毕竟我也是一个初学者.

希望这篇文章可以帮忙大家在标记文件的学习, 另外有很多的专业名词的翻译可能会跟大家认识有出
入, 希望大家见谅^^, 如果有其他问题可以在我的BLOG上留言, 我会尽可能的帮忙的, 谢谢.

 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bGiraffe/archive/2007/06/23/1663467.aspx

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值