目录
一、介绍
1.是什么
JSP 的自定义标签(Custom Tag)是指开发者自行扩展 JSP 页面标签库(Tag Library),通过封装一些常用的功能模块,以更加简洁和直观的方式实现 JSP 页面的开发。
JSP 自定义标签通常使用 Java 类来实现自己的业务逻辑,然后被打包成为一个 JAR 文件,以供 JSP 页面和其他 Web 应用共享使用。通过使用自定标签,开发者可以把页面中重复的逻辑封装起来,以更加轻松的方式实现页面的编写。
JSP 自定义标签可以分为两种类型:基于标签的自定义标签和基于标签体的自定义标签。
基于标签的自定义标签必须在 JSP 中使用尖括号指定标签名称来调用,例如 <test:customTag />。在 JSP 页面中,使用基于标签的自定义标签可以让开发者自定义标签外观,并控制标签输出的方式。
基于标签体的自定义标签是定义在带有标签体的 JSP 标签中的,类似于 <c:forEach> 标签。与基于标签的自定义标签不同的是,基于标签体的自定义标签有一个特殊的标签体,可以包含更多的内容。基于标签体的自定义标签的主要用途是处理大量重复的结构化 HTML 代码。
总之,通过自定义标签,程序员能够在 JSP 页面中扩展自己的标签库,以更加高效和简洁的方式实现 JSP 页面的开发。
2.作用
JSP 的自定义标签具有如下作用:
1. 封装重复的业务逻辑:在 JSP 页面中,可能会存在大量重复的业务逻辑,例如数据的格式化展示、表单的校验等,使用自定义标签可以将这些重复的逻辑封装到一个标签中,方便重复使用。
2. 降低代码耦合度:在 JSP 中,通常需要在 JSP 页面中散布大量的 Java 代码,将业务逻辑和页面的展示耦合在一起,给维护和升级带来困难。自定义标签可以实现将业务逻辑和页面分离,避免代码耦合度增加。
3. 极大提高页面的可维护性:自定义标签将代码封装在一起,使代码变得更易读,更简洁,更可维护。
4. 提高开发效率:使用 JSP 的自定义标签可以帮助开发者编写出更加简洁和易维护的代码,并且能够提高开发的效率,减少繁琐的代码编写,增强代码的可重用性。
总之,JSP 自定义标签可以让开发者更好的进行页面开发和维护,减少代码冗余和每次开发都需要编写重复的代码的问题,同时还能够提高开发效率。
二、自定义标签
1.标签的生命周期
2.流程
JSP 的标准标签库(JSTL)提供了创建和使用自定义标签的方法。下面是在 JSP 中创建自定义标签的一般流程:
1.创建标签处理类:标签处理类实现了自定义标签类所需的逻辑。创建一个 Java 类并实现 Tag 或 BodyTag 接口,这两个接口分别对应无需返回标签体内容和需要返回标签体内容的标签类型。
例如:
public class MyTagHandler implements Tag {
private PageContext pageContext;
private Tag parentTag;
//实现接口的方法,包括doStartTag, doEndTag, setParent等方法。
//...
}
2.在 WEB-INF 目录下创建标签库描述符文件(TLD文件):该文件声明了标签库中所有标签的属性、名称和标签处理类的位置等信息。例如:
<taglib>
<tlib-version>1.0</tlib-version>
<uri>http://www.test.com/mytags</uri>
<tag>
<name>test</name>
<tag-class>com.test.MyTagHandler</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
其中,uri 唯一标识了标签库,并且在 JSP 页面的 <%@ taglib %> 指令中被引用,tag 名称则是该标签库中标签的名称,tag-class 指定了标签处理类的完整限定名。
3.在 JSP 页面中引用标签库:在需要使用标签库中自定义标签的 JSP 页面中,使用 <%@ taglib %> 指令引用标签库,例如:
<%@ taglib prefix="t" uri="http://www.test.com/mytags" %>
其中 prefix 是引用标签库的前缀,uri 是标签库的唯一标识。
4.在 JSP 页面中使用自定义标签:在 JSP 页面中使用自定义标签,例如:
<t:test />
其中,test:test 是自定义标签的标签名称,前缀为 test,后缀为 test,该标签对应的实现是在 TLD 文件中定义的 MyTagHandler 类。
以上是在 JSP 中创建自定义标签的一般流程。需要注意的是,具体操作可能会根据不同的应用或工具有所不同。
三、Dept实例
3.1数据测试类
Person类(对象类):
package com.Jun.Customlabels;
/**
* @author Cloud.Jun
* @com.Jun.Customlabels
* @Person(说明):Person(数据测试辅助类)
*/
public class Person {
private String pid;
private String name;
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(String pid, String name) {
super();
this.pid = pid;
this.name = name;
}
public Person() {
super();
}
@Override
public String toString() {
return "Person [pid=" + pid + ", name=" + name + "]";
}
}
存放数据类
package com.Jun.Customlabels;
import java.util.ArrayList;
import java.util.List;
/**
* @author Cloud.Jun
* @com.Jun.Customlabels
* @Text01(说明):数据测试辅助类
*/
public class Text01 {
public static List<Person> getPerson(){
List<Person> pelist= new ArrayList<>();
Person p1 = new Person("p01","爱德花");
Person p2= new Person("p02","独孤贱");
Person p3 = new Person("p03","小孔龙");
pelist.add(p1);
pelist.add(p2);
pelist.add(p3);
return pelist;
}
}
3.2标签助手类
DeptTag(类):
package com.CloudJun.Customlabels;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* @author Cloud.Jun
* @com.CloudJun.Customlabels
* @DeptTag(说明):存放数据标签(自定义标签)
*/
public class DeptTag extends BodyTagSupport {
private List<Object> list ;//定义要存放发数据容器
private String val;//以该属性进行数据显示
@Override
public int doStartTag() throws JspException {
//获取数据进行保存
pageContext.setAttribute(val, list);
return SKIP_BODY;
}
public List<Object> getList() {
return list;
}
public void setList(List<Object> list) {
this.list = list;
}
public DeptTag() {
super();
}
public String getVal() {
return val;
}
public void setVal(String val) {
this.val = val;
}
public DeptTag(List<Object> list, String val) {
super();
this.list = list;
this.val = val;
}
}
3.3描述符文件(TLD文件)
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>Simple Tags</short-name>
<uri>http://mytag</uri>
<tag>
<!-- 标签名 -->
<name>dept</name>
<!-- 标签助手类 -->
<tag-class>com.CloudJun.Customlabels.DeptTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>empty</body-content>
<attribute>
<!-- 属性名, deptTag类中的val属性相匹配 -->
<name>val</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>接收数据到val中,进行显示</description>
</attribute>
<attribute>
<!-- 属性名,deptTag类中的val属性相匹配 -->
<name>list</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>将集合数据放入list属性中</description>
</attribute>
</tag>
</taglib>
3.4引用标签库
<%@ taglib prefix="o" uri="http://mytag" %>
3.5jsp页面使用
<o:dept list="${list }" val="l"/>
${l }
四、Select实例
4.1标签助手类
package com.CloudJun.Customlabels;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* @author Cloud.Jun
* @com.CloudJun.Customlabels
* @SelectTag(说明):Select类(下拉框)
*/
public class SelectTag extends BodyTagSupport{
//传进集合数据
private List<Object> items;
//根据数据里的对象编号设置option标签的值
private String optionval;
//根据数据里的对象名称设置option标签的文本内容
private String optiontext;
//初次进入将选中将option标签
private String selected;
@Override
public int doStartTag() throws JspException {
JspWriter out = pageContext.getOut();
try {
out.println(toHTML());
} catch (IOException e) {
e.printStackTrace();
}
return SKIP_BODY ;
}
/**
* 在页面要显示的内容
* @return str
*/
private StringBuffer toHTML() {
StringBuffer str = new StringBuffer("<select>");
//循环传进的集合数据
for (Object object : items) {
try {
//获取该对象的属性值
String val= getObjAttrVal(object,optionval);
String text= getObjAttrVal(object,optiontext);
//在下拉框里循环增加option标签
//selected判断初次进入页面的选中指定的option标签
str.append("<option value='"+val+"' "+(val==selected?"selected":"")+">"+text+"</option>");
} catch (Exception e) {
e.printStackTrace();
}
}
str.append("</select>");
return str;
}
/**
* @param object 对象
* @param val 属性
* @return 根据属性(val)获取对象(object)相对应属性值
* @throws SecurityException
* @throws NoSuchFieldException
*/
private String getObjAttrVal(Object object, String val) throws Exception {
Class cl = object.getClass();
//获取该对象的val属性
Field field = cl.getDeclaredField(val);
//打开权限
field.setAccessible(true);
return field.get(object).toString();
}
public List<Object> getItems() {
return items;
}
public void setItems(List<Object> items) {
this.items = items;
}
public String getOptionval() {
return optionval;
}
public void setOptionval(String optionval) {
this.optionval = optionval;
}
public String getOptiontext() {
return optiontext;
}
public void setOptiontext(String optiontext) {
this.optiontext = optiontext;
}
public String getSelected() {
return selected;
}
public void setSelected(String selected) {
this.selected = selected;
}
}
4.2描述符文件(TLD文件)
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>Simple Tags</short-name>
<uri>http://mytag</uri>
<tag>
<!-- 标签名 -->
<name>select</name>
<!-- 标签助手类 -->
<tag-class>com.CloudJun.Customlabels.SelectTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>jsp</body-content>
<attribute>
<!-- 属性名, selectTag类中的items属性相匹配 -->
<name>items</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>将数据放入items属性中</description>
</attribute>
<attribute>
<!-- 属性名, selectTag类中的optionval属性相匹配 -->
<name>optionval</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>option标签的value值</description>
</attribute>
<attribute>
<!-- 属性名, selectTag类中的optionval属性相匹配 -->
<name>optiontext</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>option标签的文本内容</description>
</attribute>
<attribute>
<!-- 属性名, selectTag类中的selected属性相匹配 -->
<name>selected</name>
<!-- 表示该属性为必要的属性 -->
<required>false</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>初次进入要设置选中的option</description>
</attribute>
</tag>
</taglib>
4.3引用标签库
<%@ taglib prefix="o" uri="http://mytag" %>
4.4jsp页面使用
<br>
<o:select optionval="pid" optiontext="name" items="${list }" ></o:select>
<o:select optionval="pid" optiontext="name" items="${list }" selected="p02"></o:select>
<o:select optionval="pid" optiontext="name" items="${list }" selected="p03"></o:select>
<hr>
五.综合测试
5.1整合代码
标签库描述符文件(TLD文件):
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>Simple Tags</short-name>
<uri>http://mytag</uri>
<tag>
<!-- 标签名 -->
<name>foreach</name>
<!-- 标签助手类 -->
<tag-class>com.Jun.Customlabels.ForeachTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>jsp</body-content>
<attribute>
<!-- 属性名, IfTag类中的val属性相匹配 -->
<name>items</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>items是保存数据的集合</description>
</attribute>
<attribute>
<!-- 属性名, IfTag类中的val属性相匹配 -->
<name>var</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>将集合数据放入var,在jsp中进行显示,如:${var.pid}</description>
</attribute>
</tag>
<tag>
<!-- 标签名 -->
<name>dept</name>
<!-- 标签助手类 -->
<tag-class>com.CloudJun.Customlabels.DeptTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>empty</body-content>
<attribute>
<!-- 属性名, deptTag类中的val属性相匹配 -->
<name>val</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>接收数据到val中,进行显示</description>
</attribute>
<attribute>
<!-- 属性名,deptTag类中的val属性相匹配 -->
<name>list</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>将集合数据放入list属性中</description>
</attribute>
</tag>
<tag>
<!-- 标签名 -->
<name>select</name>
<!-- 标签助手类 -->
<tag-class>com.CloudJun.Customlabels.SelectTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>jsp</body-content>
<attribute>
<!-- 属性名, selectTag类中的items属性相匹配 -->
<name>items</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>将数据放入items属性中</description>
</attribute>
<attribute>
<!-- 属性名, selectTag类中的optionval属性相匹配 -->
<name>optionval</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>option标签的value值</description>
</attribute>
<attribute>
<!-- 属性名, selectTag类中的optionval属性相匹配 -->
<name>optiontext</name>
<!-- 表示该属性为必要的属性 -->
<required>true</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>option标签的文本内容</description>
</attribute>
<attribute>
<!-- 属性名, selectTag类中的selected属性相匹配 -->
<name>selected</name>
<!-- 表示该属性为必要的属性 -->
<required>false</required>
<!-- 该属性可以接受EL表示式的值 -->
<rtexprvalue>true</rtexprvalue>
<!-- 标签描述,用于说明标签的作用 -->
<description>初次进入要设置选中的option</description>
</attribute>
</tag>
</taglib>
jsp页面:
<%@page import="com.Jun.Customlabels.Text01"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="o" uri="http://mytag" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 调用Text01的方法获取数据 -->
<%request.setAttribute("list",Text01.getPerson());%>
<hr>
<o:foreach items="${list }" var="p">
<p>${p.pid }----${p.name }</p>
</o:foreach>
<br>
<o:dept list="${list }" val="l"/>
${l }
<br>
<br>
<o:select optionval="pid" optiontext="name" items="${list }" ></o:select>
<o:select optionval="pid" optiontext="name" items="${list }" selected="p02"></o:select>
<o:select optionval="pid" optiontext="name" items="${list }" selected="p03"></o:select>
<hr>
</body>
</html>
5.2综合输出
5.3小知识
JSP 的自定义标签理念旨在将 JSP 页面与业务逻辑分离,实现更好的模块化和可重用性。具体来说,自定义标签理念包括以下几个方面:
1. 基于组件的开发思想:自定义标签是基于组件的开发思想,将 JSP 页面分解成可以重用的小组件,封装了常见的功能和逻辑,提高了页面的复用性和可扩展性。
2. 页面和业务逻辑分离:使用自定义标签可以将页面与业务逻辑分离,将重复的业务逻辑统一封装到标签中,以便更好的维护和更新,同时也便于后续开发对页面的扩展和维护。
3. 具有自我描述性:自定义标签应该具有良好的自我描述性,在标签声明时应该为标签提供文档信息,包括名称、用途、属性和操作等信息,以便其他开发人员快速了解这个自定义标签的作用和使用方法。
4. 具有普适性:自定义标签应该是具有普适性的,处理的是常规的任务而不是某个应用特定的问题,以便让它们在多个项目中进行重用。
总之,通过自定义标签的理念,开发人员可以更好的管理和开发 JSP 页面,提高代码的可重用性和可维护性。