一、前言
1.什么是自定义标签
在了解什么是自定义标签之前,我们先了解什么是标签。
标签(Tag):是一种特殊的语言构造,通常用于在一些具有特定功能的语言中指定标记或元数据,从而实现一些特殊的效果或功能。很多与“ML”结尾的语言都是标记语言,比如:HTML,XML,XHTML,VML等等。标记语言与其他语言一样,也需要运行它们的环境,比如HTML的运行环境时浏览器,XML也要自己的解析和运行的环境。
自定义标签(Custom Tag):是指在JSP中,开发者自行定义的可扩展标记(Tag),用于扩展和增强JSP的功能。可以使用自定义标签可以实现一些自定义逻辑,如访问Web服务、执行数据库操作、生成HTML代码、进行数据处理等复杂操作;还可以实现基于标签的流程控制、数据模型、动态样式等功能。
2.自定义标签的两种类型
简单标签
指不包含主体内容的标签,简单标签的处理一般是基于标签的属性和参数,例如<br>、<hr>
标签体标签
是指包含主体内容的标签,标签体标签的处理需要对标签的主体内容进行解析和处理,例如<if>标签和<foreach>标签等。
3.为什么要使用自定义标签
1.易于维护和重用
自定义标签将复杂的逻辑封装在单一的标签中。这使得代码更易于维护和重用,可以将一些常用的逻辑封装在标签中,避免代码重复和冗余。
2.提高代码的可读性
通过使用自定义标签,可以将业务逻辑和代码标签化,从而提高代码的可读性和可维护性。标签化的代码更符合人类的思维模式,理解和调试也更为方便。
3.分离业务和呈现逻辑
使用自定义标签可以分离业务逻辑和呈现逻辑,帮助开发者更好地实现MVC(Model-View-Controller)设计模式,提高应用程序的可扩展性和重用性。
4.提高应用程序的性能
使用自定义标签可以将需要多次重复执行的代码封装在标签中,从而减少代码重复和冗余,提高应用程序的性能。
4.使用场景
我们在做Web项目的时候,肯定是多人开发,但是有很多的代码是相同的,为了减少代码冗余,我们就可以自定义标签,共大家使用,提高效率也方便维护。
二、自定义标签的使用
1自定义标签的生命周期
由图可知我们大致分为四个阶段
实例化阶段、初始化阶段、使用阶段和实例释放阶段
2.创建自定义标签
看图很难理解,所以我们接下来直接上代码。
模拟c标签中的out标签
2.1.编写助手类
package c; import java.io.IOException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyTagSupport; /** * 自定义标签继承BodyTagSupport 作用:用于在jsp页面输出内容 * * @author Java方文山 * */ public class OutTag extends BodyTagSupport { private String val;// out标签需要输出的属性值 private String defaultVal;// out标签默认输出属性值 public void setVal(String val) { this.val = val; } public void setDefaultVal(String defaultVal) { this.defaultVal = defaultVal; } // 重写doStartTag方法 @Override public int doStartTag() { // 因为要在页面输出内容,所以先获取out对象 JspWriter out = this.pageContext.getOut(); try { // 判断标签属性有无值 if (this.val == null || "".equals(this.val)) { // 标签属性为空输出默认值 out.print(this.defaultVal); } else { // 标签属性不为空输出标签属性值 out.print(this.val); } } catch (IOException e) { e.printStackTrace(); } // 跳过主体 return SKIP_BODY; /* * SKIP_BODY以后最后用这种写法来写(成员变量), 不然别的程序员看不懂你写的代码,利用成员变量更加理解以及维护代码。 * */ } }
2.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路径--> <uri>/xw</uri> <tag> <!-- 标签名 --> <name>out</name> <!-- 标签助手类 --> <tag-class>c.OutTag</tag-class> <!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 --> <body-content>empty</body-content> <attribute> <!-- 属性名, OutTag类中的val属性相匹配 --> <name>val</name> <!-- 表示该属性是否为必要的属性 --> <required>true</required> <!-- 该属性是否可以接受EL表示式的值 --> <rtexprvalue>true</rtexprvalue> <!-- 标签描述,用于说明标签的作用 --> <description>out标签val属性,用于输出val的值</description> </attribute> <attribute> <!-- 属性名, OutTag类中的defaultVal属性相匹配 --> <name>defaultVal</name> <!-- 表示该属性为必要的属性 --> <required>false</required> <!-- 该属性可以接受EL表示式的值 --> <rtexprvalue>false</rtexprvalue> <!-- 标签描述,用于说明标签的作用 --> <description>out标签,如val属性值为空,则输出该默认值</description> </attribute> </tag> </taglib>
2.3.jsp页面引用标签
<%@page import="c.TestForeach"%> <%@page import="c.Student"%> <%@page import="java.util.List"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- 引入自定义标签--> <%@taglib prefix="xw" uri="/xw" %> <!DOCTYPE> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>自定义标签</title> </head> <body> <!--自定义out标签输出 --> <xw:out val="你好我是自定义标签out,val属性输出"/> <br> <!--自定义out标签EL表达式使用 --> <% request.setAttribute("name", "我是在作用域的文件,利用EL表达式获取"); %> <xw:out val="${name }"/> <br> <!--自定义out标签defaultVal属性输出 --> <% request.setAttribute("x", null); %> <xw:out val="${x}" defaultVal="我是out标签的默认值输出1"/> <xw:out val="" defaultVal="我是out标签的默认值输出2"/> <br> <hr> </body> </html> </body> </html>
浏览器输出结果
2.4.总结
由上可知,我们自定义标签只需要三步,①编写助手类②编写tld文件③页面引入自定义。
①编写助手类:编写一个普通的Java类继承BodyTagSupport类,为什么这里是继承类而不是是实现接口,因为BodyTagSupport类里的功能,开发人员可能不需要,实现接口就必须重写方法,可能会出错,而继承则是开发人员重写自己所需要的方法即可。在助手类里面定义自定义标签所需的属性,并编写set方法(后期需要通过反射往实例里面插入值)。重写doStartTag方法,并加上@Override注解。
②编写tld文件:tld文件可变内容就是<tag>里的元素,其他内容“cv”操作即可,自定义标签的属性名字必须和助手类一致,而且自定义标签的助手类路径名必须是正确的全路径名。
③页面引入自定义:直接在需要自定义标签的地方<%@taglib prefix="xw" uri="/xw" %>引用即可,uri就是自己在tld文件所写的。
三、解析自定义标签
助手类里的return值
返回值 | 含义 |
SKIP_BODY | 跳过主体 |
EVAL_BODY_INCLUDE | 计算标签主体内容并输出 |
EVAL_BODY_AGAIN | 再次计算主体一次 |
EVAL_PAGE | 计算页面的后续部分 |
SKIP_PAGE | 跳过页面的后续部分 |
1.为什么要重写doStartTag方法?
在自定义标签处理器中,doStartTag()方法是必须要实现的,因为它是JSP引擎在解析页面时调用的第一个方法,并且用于处理标签的开始标记。
如果不重写doStartTag()方法,那么JSP引擎会默认返回 SKIP_BODY 的值,也就是说,页面在遇到自定义标签时,标签体内的所有内容都将被略过不被执行。
2.自定义标签的工作流程
编译器看不懂“jsp文件”,它会先转成java文件,然后先通过jsp页面的引用自定义标签路径,找到tld文件,然后通过找到使用<tag>编写的标签找到指定的<tag-class>,通过里面的全路径名反射实例(助手类)调用doStartTag方法对标签进行处理。