为什么要自定义开发标签
相信很多人很好奇为啥有现成的标签库,还要去自定义开发标签,举个例子:我们在jsp使用修改时,传值给界面单选按钮是否选中,是这样的:
<c:if test="${ name=='男' }">
<input type="radio" checked="checked" value="男">
</c:if>
那如果是爱好类型的复选框呢?爱好有几百种,打个比方,那页面上就全是标签代码了,所以,了解掌握自定义标签开发出适合自己项目的标签,可以减少多余的代码,页面更加直观简洁
标签的语言特点
我们比较常用的标签就是jstl标准标签库---->c标签,我们自定义jsp标签是在此基础上,开发出符合自己的标签使用,它有哪些语言特点,下面带大家看看:
<开始标签 属性="属性值">标签体</结束标签>
空标签 : <br/><hr/> <开始标签></结束标签> <开始标签/>
标签的类型
标签的类型大概有三种:
ui标签,例如:<c:out value=""></c:out>
控制标签,例如:<c:if test="">标签体</c:if>
数据标签,例如自定义的数据显示标签:<x:select/>,c标签的<c:set var="" value=""></c:set>
开发和使用步骤
- 第一:
每个标签,必须创建一个标签助手类(继承BodyTagSupport),标签属性必须和助手类的属性对应、且要提供对应get/set方法
例如自定义一个<x:if test=" ">标签体</c:if>
标签:
package com.xiaoyang;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class IfTag extends BodyTagSupport{
private boolean test;//属性
public boolean isTest() {
return test;
}
public void setTest(boolean test) {
this.test = test;
}
}
- 第二:
创建标签库描述文件(tld),添加自定义标签的配置,而且tld文件必须保存到WEB-INF目录或其子目录
我自定义这个标签的tld配置:
<tag>
<name>if</name>//标签名
<tag-class>com.xiaoyang.IfTag</tag-class>//助手类路径
<body-content>JSP</body-content>
<attribute>//属性
<name>test</name>//属性名
<required>true</required>//是否为必填项
<rtexprvalue>true</rtexprvalue>//是否支持表达式
</attribute>
</tag>
然后把文件放在:
3.第三:
在JSP通过taglib指令导入标签库,并通过指定后缀访问自定义标签
从我们常用的·jstl核心标签库开始入手:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
如上,我们在使用c标签库时,不仅要导入jar包,还要在页面引入一行代码。接下来点击uri
地址,我们可以看到:
<description>JSTL 1.1 core library</description>
<display-name>JSTL core</display-name>
<tlib-version>1.1</tlib-version>
<short-name>c</short-name>
<uri>http://java.sun.com/jsp/jstl/core</uri>
这里的<short-name>c</short-name>
就是我们在页面引入时的prefix="c"
,<uri>http://java.sun.com/jsp/jstl/core</uri>
就是页面引入的uri="http://java.sun.com/jsp/jstl/core" %>
看完c标签的引入方式后,那么,我们自定义标签也可以这样配置tld:
<description>JSTL 1.1 core library</description>
<display-name>JSTL core</display-name>
<tlib-version>1.1</tlib-version>
<short-name>x</short-name>
<uri>/xiaoyang</uri>
在页面引入:
<%@taglib prefix="x" uri="/xiaoyang" %>
自定义标签的生命周期
在完成上面的步骤后,开发自定义标签,还必须要掌握它的生命周期的流转:
标签的几个生命阶段:
doStartTag()
对应的阶段方法有:
SKIP_BODY(跳过主体)、EVAL_BODY_INCLUDE(计算主体内容并输出)
doEndTag()
对应的阶段方法:
EVAL_PAGE(计算页面后续内容)、SKIP_PAGE(跳过页面后续内容)
doAfterBody()
对应的阶段方法:
EVAL_BODY_AGAIN(再次计算主体)、EVAL_PAGE(计算页面后续内容)
如图:
案例结合
了解完自定义标签的开发和使用步骤以及它的一个生命周期后,我们结合一个案例,更好的去了解它,这里我自定义开发了
x:out、x:foreach、x:if、x:set
首先看x:if
:
在开发时,首先仿照c:if
分析:
那么我们就可以开始编码了:
首先是助手类:
package com.xiaoyang;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class IfTag extends BodyTagSupport{
private boolean test;//属性
public boolean isTest() {
return test;
}
public void setTest(boolean test) {
this.test = test;
}
@Override
public int doStartTag() throws JspException {
//如果为真则计算主体输出,否则跳过主体
return test ? EVAL_BODY_INCLUDE:SKIP_BODY;
}
}
然后在tld文件中配置好:
<tag>
<name>if</name>
<tag-class>com.xiaoyang.IfTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
然后我们页面引入tld文件后,就可以使用了:
<x:if test="true">男</x:if>
<x:if test="false">女</x:if>
输出结果:
然后是x:out、x:set
标签,一样的套路,参照c标签分析:
x:out助手类:
package com.xiaoyang;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class OutTag extends BodyTagSupport{
private Object value;//内容
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
@Override
public int doStartTag() throws JspException {
//out标签直接输出value内容
JspWriter out = pageContext.getOut();
try {
out.print(value);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return SKIP_BODY;
}
}
tld配置
<tag>
<name>out</name>
<tag-class>com.xiaoyang.OutTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>boolean</type>
</attribute>
</tag>
x:set助手类:
package com.xiaoyang;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class SetTag extends BodyTagSupport{
private String var;//属性,相当于键
private Object value;//内容
public String getVar() {
return var;
}
public void setVar(String var) {
this.var = var;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
@Override
public int doStartTag() throws JspException {
//存入页面,以var作为键,存入值value
pageContext.setAttribute(var, value);
return SKIP_BODY;
}
}
tld配置
<tag>
<name>set</name>
<tag-class>com.xiaoyang.SetTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
调用:
<x:set var="sex" value="男"></x:set>
<x:out value="${sex }"></x:out>
结果:
最后就是x:foreach
标签了:
助手类:
package com.xiaoyang;
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 String var;//保存当前数据到作用域的一个键
private List<Object> items;//数据源
public String getVar() {
return var;
}
public void setVar(String var) {
this.var = var;
}
public List<Object> getItems() {
return items;
}
public void setItems(List<Object> items) {
this.items = items;
}
@Override
public int doStartTag() throws JspException {
if(items==null||items.size()==0) {//如果数据源为空,跳过主体,不执行遍历
return SKIP_BODY;
}
//有数据则取值
Iterator<Object> iterator = items.iterator();
Object next = iterator.next();
pageContext.setAttribute(var, next);
//将剩下的值存入作用域
pageContext.setAttribute("ite", iterator);
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
//取出作用域剩余的值
Iterator<Object> attribute =(Iterator<Object>)pageContext.getAttribute("ite");
//迭代遍历
while(attribute.hasNext()) {
pageContext.setAttribute(var, attribute.next());
return EVAL_BODY_AGAIN;
}
//遍历完计算页面后续内容
return EVAL_PAGE;
}
}
配置tld:
<tag>
<name>foreach</name>
<tag-class>com.xiaoyang.ForeachTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
调用:
<%
List<String> ls=new ArrayList<String>();
ls.add("1");
ls.add("2");
request.setAttribute("ls", ls);
%>
<x:foreach items="${ls }" var="a">
${a }
</x:foreach>
结果:
尾言
搞定,溜了溜了…