一. 什么是自定义标签
一般我们说自定义标签是指JSP自定义标签。
自定义标签在功能上逻辑上与javaBean 类似,都封装Java 代码。自定义标签是可重用的组件代码,并且允许开发人员为复杂的操作提供逻辑名称。
JSP开发人员使用标签库创建标签.标签库是按照功能或实现进行分组的自定义标签的集合。
网络上常见的CMS内容管理系统都是采用模板的形式来实现,基本上所有的CMS系统都有一套自己的模板标签书写方法,简称自定义标签。
标签基本概念
1.1 标签(Tag):
标签是一种XML元素,通过标签可以使JSP网页变得简洁并且易于维护,还可以方便地实现同一个JSP文件支持多种语言版本。由于标签是XML元素,所以它的名称和属性都是大小写敏感的。
1.2 标签库(Tag library):
由一系列功能相似、逻辑上互相联系的标签构成的集合称为标签库。
1.3 标签库描述文件(Tag Library Descriptor):
标签库描述文件是一个XML文件,这个文件提供了标签库中类和JSP中对标签引用的映射关系。它是一个配置文件,和web.xml是类似的。
二. 自定义标签的语言特点
标准标签:
<开始标签 属性=“属性值”>标签体</结束标签>
空标签:
<开始标签/>
三. 自定义标签的创作流程
1. 创建一个标签助手类(继承BodyTagSupport)
2. 编写标签库描述文件(tld),在tld中对标签进行描述
3. JSP通过taglib指令导入标签库,在页面中使用自定义标签
四. 自定义foreach标签
foreach标签助手类
package com.xissl.tag; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; public class ForeachTag extends BodyTagSupport { private List<Object> items = new ArrayList<Object>(); private String var; public List<Object> getItems() { return items; } public void setItems(List<Object> items) { this.items = items; } public String getVar() { return var; } public void setVar(String var) { this.var = var; } @Override public int doStartTag() throws JspException { //如果items为空,就跳过 if(items == null || items.size()==0) return SKIP_BODY; //获取第一个数据 Iterator<Object> it = items.iterator(); pageContext.setAttribute(var, it.next()); pageContext.setAttribute("it", it); return EVAL_BODY_INCLUDE; } @Override public int doAfterBody() throws JspException { Iterator<Object> it = (Iterator<Object>) pageContext.getAttribute("it"); if(it.hasNext()) { //获取后面的数据 pageContext.setAttribute(var, it.next()); pageContext.setAttribute("it", it); return EVAL_BODY_AGAIN; } return SKIP_BODY; } }
tld文件
<tag> <name>foreach</name> <tag-class>com.xissl.tag.ForeachTag</tag-class> <body-content>jsp</body-content> <attribute> <name>items</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>var</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> </tag>
注意:tld文件一定要放在WEB-INF目录下或者子目录。
在页面中使用
<% List<Dept> list = new ArrayList<Dept>(); list.add(new Dept(1,"sa")); list.add(new Dept(2,"yh")); list.add(new Dept(3,"wh")); request.setAttribute("list", list); %> <p>自定义foreach标签</p> <l:foreach items="${list }" var="l"> ${l } </l:foreach>
运行结果如下:
五. 自定义dept数据标签
标签助手类
package com.xissl.tag; import java.util.ArrayList; import java.util.List; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; import com.xissl.entity.Dept; public class DeptTag extends BodyTagSupport { private String var; public String getVar() { return var; } public void setVar(String var) { this.var = var; } @Override public int doStartTag() throws JspException { //模拟数据库访问的过程 List<Dept> list = new ArrayList<Dept>(); list.add(new Dept(1,"sa")); list.add(new Dept(2,"yh")); list.add(new Dept(3,"wh")); //将数据放入var中 pageContext.setAttribute(var, list); return SKIP_BODY; } }
tld文件
<tag> <name>dept</name> <tag-class>com.xissl.tag.DeptTag</tag-class> <!-- 该标签有标签体 --> <body-content>jsp</body-content> <attribute> <name>var</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> </tag>
页面展示
<p>自定义dept数据标签</p> <l:dept var="ds"></l:dept> ${ds }
运行结果:
六. select标签
标签助手类
package com.xissl.tag; import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyTagSupport; public class SelectTag extends BodyTagSupport{ // 下拉框的数据源 private List<Object> items = new ArrayList<Object>(); // 下拉框下的option的value值 private String optionValue; // 下拉框下的option的标签体内容 private String optionText; // 数据库中存储的数据,用于下拉框的回显 private String selectedVal; public String getSelectedVal() { return selectedVal; } public void setSelectedVal(String selectedVal) { this.selectedVal = selectedVal; } public List<Object> getItems() { return items; } public void setItems(List<Object> items) { this.items = items; } public String getOptionValue() { return optionValue; } public void setOptionValue(String optionValue) { this.optionValue = optionValue; } public String getOptionText() { return optionText; } public void setOptionText(String optionText) { this.optionText = optionText; } @Override public int doStartTag() throws JspException { // 因为select标签没有标签体,页面又要输出下拉框内容,所有要用到流对象 JspWriter out = pageContext.getOut(); try { out.print(toHTML()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return super.doStartTag(); } private String toHTML() throws Exception { StringBuffer sb = new StringBuffer("<select>"); for (Object object : items) { String val = getObjAttrVal(object,optionValue); String Text = getObjAttrVal(object,optionText); sb.append("<option "+(val.equals(selectedVal)? "selected":"")+" value='"+val+"'>"+Text+"</option>"); } sb.append("</select>"); return sb.toString(); } private String getObjAttrVal(Object object, String optionVal) throws Exception{ // 一切反射从类类开始 Class class1 = object.getClass(); Field f = class1.getDeclaredField(optionVal); f.setAccessible(true); return f.get(object).toString(); } }
tld文件
<tag> <name>select</name> <tag-class>com.xissl.tag.SelectTag</tag-class> <!-- 该标签有标签体 --> <body-content>jsp</body-content> <attribute> <name>items</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>optionValue</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <name>optionText</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <name>selectedVal</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
页面展示
<p>自定义select标签</p> <l:select items="${list }" optionText="name" optionValue="id" selectedVal="2"></l:select>
运行结果如下: