Java WEB开发实战 之 第六部分:Taglib基本知识和基本开发

来源:互联网 发布:系统优化对比报告 编辑:程序博客网 时间:2024/05/22 05:19
Taglib:自定义标签库,是一种Java Web开发的组件技术,通过在页面上使用自定义的标记,实现一些相应的功能处理的技术
Taglib有什么:任何一个Taglib都包含两个部分
1:标记库描述文件
2:所有相关的标记处理类
 
Taglib能干什么:
1:实现功能组件化,重用化
2:减少页面上的Java脚本,实现页面和逻辑相分离
 
相关说明:
1:JSP页面中使用的自定义标记处理器可以访问任一可在JSP页面中访问的对象,
如请求和会话范围的属性
2:自定义标记遵循XML标记规则
3:需要在JSP页面和Web应用程序的部署描述符中声明标记库
4:在JSP页面中可使用自定义的空标记,如:<mya id=“123” />
5:在JSP页面中使用自定义标记,可有条件地执行HTML响应的某部分
6:在JSP页面中使用自定义标记,可迭代执行HTML响应中的某部分
自定义标记使用XML语法:
1:标准标记(包含标记体):

java代码:
查看复制到剪贴板打印
  1. < prefix: name { attribute={” value”|’ value’}}*>  
  2. body  
  3. </ prefix: name>  
  4. 2:空标记:  
  5. < prefix: name { attribute={” value”|’ value’}}* />  
  6. 3:标记名、属性及其前缀都是大小写敏感的  
  7. 4:标记嵌套规则:  
  8. <tag1>  
  9.     <tag2>  
  10.     </tag2>  
  11. </tag1>  
标记处理器API允许创建自己的标记处理器类,相关API如下:

java代码:
查看复制到剪贴板打印
  1. Tag  
  2. TagSupport  
  3. PageContext  
 
开发基本的Taglib并不复杂,基本要求如下:
1:扩展TagSupport类
2:为每个标记属性提供一个私有的实例变量;为所有在标记定义中非强制的属性提供一个显式的缺省值
3:为每个标记属性创建setXyz(String)方法
4:覆盖doStartTag方法完成开始标记的处理
5:覆盖doEndTag方法将所有属性实例变量复位到其缺省值

java代码:
查看复制到剪贴板打印
  1. public class MyTag extends TagSupport {  
  2.   private String myName = "";  
  3.   public void setMyName(String s) {  
  4.     this.myName = s;  
  5.   }  
  6.   public int doStartTag() {  
  7.     ServletRequest request = pageContext.getRequest();  
  8.     JspWriter out = pageContext.getOut();  
  9.     try {  
  10.       out.println("haha,the myName="+myName);  
  11.     } catch (IOException e) {  
  12.       e.printStackTrace();  
  13.     }  
  14.     return this.SKIP_BODY;  
  15.   }  
  16.   //覆盖方法复位缺省属性值  
  17.   public int doEndTag() {  
  18.      this.myName = "";  
  19.   }  
  20. }  
  21.    
  22. <?xml version="1.0" encoding="UTF-8"?>  
  23. <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">  
  24. <taglib>  
  25.     <tlib-version>2.2.3</tlib-version>  
  26.     <jsp-version>1.2</jsp-version>  
  27.     <short-name>javass</short-name>  
  28.     <uri>/javass-tags</uri>  
  29.     <display-name>"Javass Tags"</display-name>  
  30.     <tag>  
  31.         <name>mytag</name>  
  32.         <tag-class>cn.javass.tag.MyTag</tag-class>  
  33.         <body-content>JSP</body-content>  
  34.         <description><![CDATA[test tag]]></description>  
  35.         <attribute>  
  36.               <name>myName</name>  
  37.               <required>false</required>  
  38.               <rtexprvalue>true</rtexprvalue>  
  39.               <description><![CDATA[my first tag]]></description>  
  40.         </attribute>  
  41.     </tag>  
  42. </taglib>  


nbody-content元素值:
1:empty:标记不接受任何标记体内容
2: JSP:标记可在其标记体中接受任意的JSP代码
3: tag-dependent:标记可在其标记体中接受任意内容。JSP引擎不处理标记体,但会将其直接传送给标记处理器
attribute元素包含三个子元素

java代码:
查看复制到剪贴板打印
  1. 1: name:属性名(大小写敏感)  
  2. 2: required: JSP页面中的每个标记是否必须使用该属性  
  3. 3: rtexprvalue:属性值是否可在运行时由JSP代码生成。例如,如果有一个生成HTML标头的标记,则可能要包含一个属性level,其可以接收一个数值,如下:  
  4. <prefix:heading level=”<%= currentHeading %>”>  
  5.         Act IV - Romeo Awakes  
  6. </prefix:heading>  
  7. <%@taglib prefix="javass" uri="/javass-tags"%>  
  8.    
  9. haha:  
  10. <javass:mytag myName="cc">  
  11. abcdefg  
  12. </javass:mytag>  
注意:在标记中间的值会被忽略掉,因为标记类在实现的时候是做的跳过标记体
补充说明:
1:在doStartTag()方法中返回SKIP_BODY或EVAL_BODY_INCLUDE,用来标识是否处理标记的主体部分
2:在doEndTag()方法中返回 EVAL_PAGE 或 SKIP_PAGE,以决定是否处理页面的其余部分
如何使用已经开发好的Taglib呢?基本步骤和方法如下:
1.把自定义标记的类(jar)包放到WEB—INF文件下的classes(lib包) 下
2.把标签的描述文件(xx.tld)拷贝到WEB—INF的根目录下(如果不拷贝,到classpath下面进行搜寻)
3.在web.xml中无需进行标签的配置,会自动到整个classpath下根据uri去搜寻
4.页面使用步骤
  a.引入taglib:<%@ taglib prefix=”” uri=””%>
    一个页面中可以有任意个prefix,但不能重复,uri对应web.xml中的uri
  b.使用:<prefix名:标签名   属性><prefix名:标签名>
 
 
 
所谓条件标记:就是通知JSP页面,某一条件满足时包含标记体的标记
标记的条件部分通过doStartTag方法实现
如果条件为true,则doStartTag方法返回EVAL_BODY_INCLUDE
如果条件为false,则应返回SKIP_BODY

java代码:
查看复制到剪贴板打印
  1. public class MyIfTag extends TagSupport{  
  2.     private boolean flag = false;  
  3.     public void setFlag(boolean flag){  
  4.         this.flag = flag;  
  5.     }  
  6.     public int doStartTag(){  
  7.         if(this.flag){  
  8.             return this.EVAL_BODY_INCLUDE;  
  9.         }else{  
  10.             return this.SKIP_BODY;  
  11.         }  
  12.     }  
  13.     public void release() {this.flag = false;}  
  14. }  
  15. <tag>  
  16.     <name>myiftag</name>  
  17.     <tag-class>cn.javass.tag.MyIfTag</tag-class>  
  18.     <body-content>JSP</body-content>  
  19.     <description><![CDATA[test if tag]]></description>  
  20.     <attribute>  
  21.       <name>flag</name>  
  22.       <required>true</required>  
  23.       <rtexprvalue>true</rtexprvalue>  
  24.       <description><![CDATA[my if tag]]></description>  
  25.     </attribute>  
  26. </tag>  
  27.    
  28. <%@taglib prefix="javass" uri="/javass-tags"%>  
  29.    
  30. <javass:myiftag flag="<%=(5>3)%>">  
  31. 5>3  
  32. </javass:myiftag>  


所谓迭代标记:通知JSP页面,处理标记体多次,直到迭代完成
迭代的五个基本步骤:
Iterator elements = getIterator();   // 初始化
while ( elements.hasNext() ) {       // 迭代测试
    Object obj = elements.next();    // 获取下一个对象
    process(obj);                    // 处理对象
}                                    // 继续循环
编写自定义的迭代标记
1:doStartTag方法用于初始化迭代,执行首次测试,如果测试通过,获取迭代中的第一个对象
2:标记体中的JSP代码执行“标记体处理”
3:doAfterBody用于执行后续的迭代测试
迭代标记API: IteratorionTag接口添加了doAfterBody方法
 

java代码:
查看复制到剪贴板打印
  1. public class MyIteratorTag extends TagSupport {  
  2.   private Collection col  = null;  
  3.   private Iterator it = null;  
  4.   private String colName = "";  
  5.   public void setColName(String name) {  
  6.     this.colName = name;  
  7.   }  
  8.   public int doStartTag() {  
  9.     col = (Collection)this.pageContext.getAttribute(this.colName,PageContext.REQUEST_SCOPE);  
  10.     if (this.col != null && this.col.size() > 0) {  
  11.       it = col.iterator();  
  12.       return this.EVAL_BODY_INCLUDE;  
  13.     } else {  
  14.       return this.SKIP_BODY;  
  15.     }  
  16.   }  
  17.    
  18.   public int doAfterBody() {  
  19.     if (this.col != null) {  
  20.       JspWriter out = this.pageContext.getOut();  
  21.       if (it.hasNext()) {  
  22.         try {  
  23.           out.println("the col value="+it.next()+"</br>");  
  24.         } catch (IOException e) {  
  25.           e.printStackTrace();  
  26.         }  
  27.         return this.EVAL_BODY_AGAIN;  
  28.       } else {  
  29.         return this.SKIP_BODY;  
  30.       }  
  31.     }  
  32.     return this.SKIP_BODY;  
  33.   }  
  34. public void release() {  
  35. this.col = null;  
  36. }  
  37. }  
  38.    
  39. <tag>  
  40.     <name>myittag</name>  
  41.     <tag-class>cn.javass.tag.MyIteratorTag</tag-class>  
  42.     <body-content>JSP</body-content>  
  43.     <description><![CDATA[test iterator tag]]></description>  
  44.     <attribute>  
  45.       <name>colName</name>  
  46.       <required>true</required>  
  47.       <rtexprvalue>true</rtexprvalue>  
  48.       <description><![CDATA[my iterator tag]]></description>  
  49.     </attribute>  
  50. </tag>  
  51. <%@ page import="java.util.*"%>  
  52. <%@taglib prefix="javass" uri="/javass-tags"%>  
  53. <%  
  54. Collection col = new ArrayList();  
  55. col.add("1");  
  56. col.add("2");  
  57. col.add("3");  
  58. col.add("4");  
  59. request.setAttribute("myCol",col);  
  60. %>  
  61. <javass:myittag colName="myCol">  
  62. </javass:myittag>  
  63.    


示例
功能:使用Taglib来实现自定义跳转
 
示例
功能:使用Taglib来实现动态生成Table,并填充数据。
传入表头字段个数、内容、table要显示的数据列表,然后循环执行标签体,最后动态生成一个Table。
要注意:
1:这个标签的实现还是很简单的功能,很多复杂的功能都没有考虑
2:实际应用开发中,可以考虑拆成多个标签组合使用,比如把表头单独做成一个标签等等
3:实际开发中,尽量不要在Tag里面直接拼接html,这样不利于添加CSS
示例
功能:使用Taglib来实现自定义跳转
 
示例
功能:使用Taglib来实现动态生成Table,并填充数据。
传入表头字段个数、内容、table要显示的数据列表,然后循环执行标签体,最后动态生成一个Table。
要注意:
1:这个标签的实现还是很简单的功能,很多复杂的功能都没有考虑
2:实际应用开发中,可以考虑拆成多个标签组合使用,比如把表头单独做成一个标签等等
3:实际开发中,尽量不要在Tag里面直接拼接html,这样不利于添加CSS
要编写能包含body体的标记,通常做法是:
1:让标记继承BodyTagSupport
 
2:在doStartTag方法里面进行标记体运行前的处理,并返回EVAL_BODY_BUFFERED,以前使用的EVAL_BODY_TAG已经废弃了。
 
3:在doAfterBody方法里面,可以使用this.getBodyContent()来得到body体运行过后返回的数据。并使用this.getBodyContent().getString()得到运行后的文本。
 
4:在doEndTag方法里面进行标记体运行后的处理,通常还需要清空公共的变量或是属性的值。
 
EL(表达式语言)是JSTL输出(输入)一个JAVA表达式的表示形式:
1:在JSTL中,EL语言只能在属性值中使用
2:EL语言只能通过建立表达式${exp1}来进行调用
3:在属性值中使用表达式有三种方式
(1): value属性包含一个表达式 
<some:tag value=“${expr}”/> 
在这种情况下,表达式值被计算出来并根据类型转换规则赋值给value属性。比如:<c:out value=“${username}” />中的${username}就是一个EL,它相当于JSP语句<%=request.getAttribute(“username”)%>或<%=session.getAttribute(“username”)%>
(2)value属性包含一个或多个属性,这些属性被文本分割或围绕 
<some:tag value=“some${expr}${expr}text${expr}”/> 
在这种情况下,表达式从左到右进行计算,并将结果转换为字符串型(根据类型转换规则),并将结果赋值给value属性
(3)value属性仅仅包含文本  <some:tag value="sometext"/> 
这种情况,字符串型属性value将根据类型转换规则转换为标签所希望的类型。
EL的操作符:
取得某个对象或集合中的属性值
为了获得集合中的属性,EL支持以下两种操作
1:使用.操作符来获得有名字的属性。例如表达式${user.username}表明对象user的username属性
2:使用[]操作符来获得有名字或按数字排列的属性。
      表达式${user[“username”]}和表达式${user. username }含义相同
表达式${row[0]} 表明row集合的第一个条目。
在这里user是一个类的对象,它的属性username必须符合标准JavaBean的规范,即必须为username属性定义相应的getter、setter方法。
Empty操作符(空值检查)
使用empty操作符来决定对象、集合或字符串变量是否为空或null。例如: 
${empty param.username} 
如果request的参数列表中的username值为null,则表达式的值为true。 EL也可以直接使用比较操作符与null进行比较。如${param.firstname == null}。
 
比较操作符 :
  操作符                     描述
  ==或eq                 相等检查
  !=或ne                  不等检查
  <或lt                     小于检查
  >或gt                    大于检查
  <=或le                  小于等于检查
  >=或ge                 大于等于检查
 
数字运算符与逻辑运算符均与JAVA语言相同,不再啰嗦了
JSTL的EL也有隐含对象,共有11个,如下所示:
Jsp类别:pageContext ,表示PageContext 实例,对应于当前页面的处理
n作用域类别:
1:pageScope ,与页面作用域属性的名称和值相关联的 Map 类
2:requestScope ,与请求作用域属性的名称和值相关联的 Map 类
3:sessionScope ,与会话作用域属性的名称和值相关联的 Map 类
4:applicationScope ,与应用程序作用域属性的名称和值相关联的 Map 类
请求参数类别:
1:param ,按名称存储请求参数的主要值的 Map 类
2:paramValues ,将请求参数的所有值作为 String 数组存储的 Map 类
n请求头类别:
1:header ,按名称存储请求头主要值的 Map 类
2:headerValues ,将请求头的所有值作为 String 数组存储的 Map 类
nCookie类别:cookie,按名称存储请求附带的 cookie 的 Map 类
初始化参数类别:initParam ,按名称存储Web应用上下文初始化参数的 Map类
 
 
 
 

java代码:
查看复制到剪贴板打印
  1. <c:if test="${user.wealthy}">  
  2.     user.wealthy is true.  
  3. </c:if>  
  4. 如果user.wealthy值true,则显示user.wealthy is true.  
  5. <c:choose>  
  6.   <c:when test="${user.generous}">  
  7.     user.generous is true.  
  8.   </c:when>   
  9.   <c:when test="${user.stingy}">  
  10.     user.stingy is true.  
  11.   </c:when>  
  12.   <c:otherwise>  
  13.     user.generous and user.stingy are false.  
  14.   </c:otherwise>  
  15. </c:choose>  
只有当条件user.generous返回值是true时,才显示user.generous is true. 
只有当条件user.stingy返回值是true时,才显示user.stingy is true. 
其它所有的情况(即user.generous和user.stingy的值都不为true)全部显示user.generous and user.stingy are false. 
由于JSTL没有形如if (){…} else {…}的条件语句,所以这种形式的语句只能用<c:choose>、<c:when>和<c:otherwise>标签共同来完成了。
 
 
由varStatus属性命名的变量并不存储当前索引值或当前元素,而是赋予 javax.servlet.jsp.jstl.core.LoopTagStatus 类的实例。该类定义了一组特性,它们描述了迭代的当前状态,如下所示:
1:current  :当前这次迭代的集合中的项
2:index    :当前这次迭代从 0 开始的迭代索引
3:count    :当前这次迭代从 1 开始的迭代计
4:first    :当前这轮迭代是否为第一次迭代的标志
5:last     : 当前这轮迭代是否为最后一次迭代的标志
6:begin    : begin 属性值
7:end      : end 属性值
8:step     : step 属性值 
 
由varStatus属性命名的变量并不存储当前索引值或当前元素,而是赋予 javax.servlet.jsp.jstl.core.LoopTagStatus 类的实例。该类定义了一组特性,它们描述了迭代的当前状态,如下所示:
1:current  :当前这次迭代的集合中的项
2:index    :当前这次迭代从 0 开始的迭代索引
3:count    :当前这次迭代从 1 开始的迭代计
4:first    :当前这轮迭代是否为第一次迭代的标志
5:last     : 当前这轮迭代是否为最后一次迭代的标志
6:begin    : begin 属性值
7:end      : end 属性值
8:step     : step 属性值 
 

java代码:
查看复制到剪贴板打印
  1.    
  2. <c:forTokens items="a:b:c:d" delims=":" var="token">  
  3.     <c:out value="${token}"/>  
  4. </c:forTokens>  


这个标签的使用相当于java.util.StringTokenizer类。在这里将字符串a:b:c:d以:分开循环四次,token是循环到当前分割到的字符串。
nURL的操作
<c:url> :输出一个url地址,它有以下属性
1:value :url地址 , 必须要
2:context:上下文名称
3:var :把生成的url当作值,存放在var指定的变量中
4:scope : 变量存储的范围
 
<c:url>有如下三个特别有用的功能:
1:在前面附加当前 servlet 上下文的名称
2:为会话管理重写 URL
3:请求参数名称和值的 URL 编码
例子:
简单如:
<a href="<c:url value="/index.jsp"/>">这是一个超链接</a>
 
稍复杂点:

java代码:
查看复制到剪贴板打印
  1. <c:url value="/javass/test.jsp" var="test">  
  2.   <c:param name="param1" value="abc"/>  
  3.   <c:param name="param2" value="中文字符"/>  
  4. </c:url>  
  5.    
  6. <c:out value="${test}"/>  
  
JSTL提供了函数库,来实现一些常用的功能,在页面引入函数库的语句是:<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
fn:contains(string, substring)
如果参数string中包含参数substring,返回true
示例:<c:if test="${fn:contains(name, searchString)}">
或者是: ${fn:contains(name, searchString)}
fn:containsIgnoreCase(string, substring)
如果参数string中包含参数substring(忽略大小写),返回true
fn:endsWith(string, suffix)
如果参数 string 以参数suffix结尾,返回true
fn:escapeXml(string) 
将有特殊意义的XML (和HTML)转换为对应的XML实体
fn:indexOf(string, substring) 
返回参数substring在参数string中第一次出现的位置
 
 
fn:join(array, separator)
将一个给定的数组array用给定的间隔符separator串在一起,组成一个新的字符串并返回。
fn:length(item) 
返回参数item中包含元素的数量。参数Item类型是数组、collection或者String。如果是String类型,返回值是String中的字符数。
fn:replace(string, before, after) 
返回一个String对象。用参数after字符串替换参数string中所有出现参数before字符串的地方,并返回替换后的结果
fn:split(string, separator) 
返回一个数组,以参数separator 为分割符分割参数string,分割后的每一部分就是数组的一个元素
fn:startsWith(string, prefix) 
如果参数string以参数prefix开头,返回true
fn:substring(string, begin, end) 
返回参数string部分字符串, 从参数begin开始到参数end位置,包括end位置的字符
fn:substringAfter(string, substring) 
返回参数substring在参数string中后面的那一部分字符串
fn:substringBefore(string, substring) 
返回参数substring在参数string中前面的那一部分字符串
fn:toLowerCase(string) 
将参数string所有的字符变为小写,并将其返回
fn:toUpperCase(string) 
将参数string所有的字符变为大写,并将其返回
fn:trim(string) 
去除参数string 首尾的空格,并将其返回
 
在以前的作业基础上,把JSTL添加上
按照每天学习累加的方式,已经逐步学习了Jsp+Servlet+JavaBean+JSTL+Taglib开发的基本知识。
联合开发的这个示例要完成的功能:
1:分成前台和后台
2:后台完成对商品的CRUD,最简单的那个就可以了
3:前台展示数据,不带翻页
4:前台用户能把数据添加到购物车
5:用户能查看购物车的数据
 
本节课完成对商品CRUD的后台部分
  
在以前的作业基础上,把JSTL添加上
按照每天学习累加的方式,已经逐步学习了Jsp+Servlet+JavaBean+JSTL+Taglib开发的基本知识。
联合开发的这个示例要完成的功能:
1:分成前台和后台
2:后台完成对商品的CRUD,最简单的那个就可以了
3:前台展示数据,不带翻页
4:前台用户能把数据添加到购物车
5:用户能查看购物车的数据
 
本节课完成对商品CRUD的后台部分
 
 
视频配套PPT,视频地址【  Java WEB开发实战视频课程 】
原创内容 转自请注明【 http://sishuok.com/forum/blogPost/list/0/2517.html#7242】 
0 0
原创粉丝点击