JSP自定义标签

目录

一、JSP自定义标签

1.什么是标签

2. 什么是自定义标签

3. 标签语言的特点

二。自定义的标签的编写和使用步骤

1. 标签库

2. 函数库

3.自定义标签的使用步骤

3.1先建一个.tld文件(必须在)在WEB-INF目录下

3.2,引用标签库类

3.3 每一个标签都必须有一个对于的助手类,继承BodyTagSupport

3.4测试

三、标签的生命周期

1. JSP自定义标签生命周期图

2. 案例论证

 四、标签的开发实例

1. if 标签

1.1 进入.tld文夹定义if标签并对自定义标签进行描述

1.2 编写助手类

1.3 编写jsp页面进行测试

2. set和out标签

2.1 进入.tld文夹定义set和out标签并对自定义标签进行描述

2.1编写助手类

 3. foreach 标签

3.1 进入.tld文夹定义foreach标签并对自定义标签进行描述

3.2 创建助手类

3.3jsp测试

4. select 标签

4.1 进入.tld文夹定义select标签并对自定义标签进行描述

4.2 创建助手类


一、JSP自定义标签

1.什么是标签

标记语言,是一种注释文本的语言,以便于计算机可以操作。很多与“ML”结尾的语言都是标记语言,比如:HTML,XML,XHTML,VML等等。
标记语言与其他语言一样,也需要运行它们的环境,比如HTML的运行环境时浏览器,XML也要自己的解析和运行的环境。

2. 什么是自定义标签

  自定义标签是用户定义的JSP语言元素。当包含自定义标签的JSP页面转换为servlet时,这个标签就转换为一个名为tag handler的对象上的操作。之后当JSP页面的servlet执行时,Web容器就调用这些操作。

3. 标签语言的特点

1.标准:<开始标签 属性="属性值">标签体</结束标签>

2.类别

空标签br、hr...
ui标签input、table...
控制标签if、foreach...
数据标签out

二。自定义的标签的编写和使用步骤

JSP自定义标签可以分为两种类型:标记库和函数库。

1. 标签库


        标记库是由一组标记组成的集合,这些标记可用于在JSP页面上执行各种操作。开发人员可以根据自己的需求创建自定义标记,并将其打包到一个标记库中。这个标记库可以在多个JSP页面中共享,并且可以轻松地部署和维护。

        简单来说是标记库一个JSP标签集合,它封装了JSP应用的通用核心功能, 基于JSP标签我们可以理解为,是JSP应该通用功能的一种封装方式。

2. 函数库


        函数库是一组函数的集合,这些函数可以在JSP页面上调用。开发人员可以根据自己的需求创建自定义函数,并将它们打包到一个函数库中。这个函数库可以在多个JSP页面中共享,并且可以轻松地部署和维护。

创建函数库需要以下步骤:

创建一个名为“tld”的XML文件,并在其中定义函数库的属性,如名称、URI等。
在JSP页面中引用这个XML文件,以便可以使用函数库中的函数。
创建函数
创建函数需要以下步骤:

创建一个Java类,其中包含所需的函数。
在tld文件中定义函数,并指定函数的名称、类、描述等信息。

3.自定义标签的使用步骤

3.1先建一个.tld文件(必须在)在WEB-INF目录下

<!-- mytag.tld -->
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
	version="2.0">
	<description>My custom tag library</description>
	<display-name>My Tag Library</display-name>
	<tlib-version>1.0</tlib-version><!-- 代表标签库的版本号 -->
	<short-name>mtl</short-name><!-- 你的标签库简称 -->
    <uri>com.ycxw</uri><!-- taglib引入标签名字 -->
	<tag>
		<name>HelloTag</name><!-- 代表自定义标签的名字 -->
		<tag-class>com.ycxw.DemoTag</tag-class><!-- 对应的标签处理程序(助手类):包名+类名 -->
		<body-content>JSP</body-content><!-- 标签体内容的格式 -->
		<attribute>
			<name>test</name><!-- 自定义标签的属性名称 -->
			<required>true</required><!-- 该属性是否必填 -->
			<rtexprvalue>true</rtexprvalue><!-- 该属性值是否支持表达式 -->
		</attribute>
	</tag>
</taglib>

注:tld文件就是C标签的定义配置文件

  • 自定义标签是与 .tld文件相关的
  • 标签中的标签与 .tld中的tag元素相关,也就是tag元素对应的助手类有关

3.2,引用标签库类

<%@taglib prefix="l" uri="com.xzs" %>

3.3 每一个标签都必须有一个对于的助手类,继承BodyTagSupport

package com.xzs;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
 
/**
 * 
 * @author
 *
 */
public class DemoTag extends BodyTagSupport{
	@Override
	public int doStartTag() throws JspException {
		System.out.println("—— doStartTag ——");
		return super.doStartTag();
	}
	
	@Override
	public int doAfterBody() throws JspException {
		System.out.println("—— doAfterBody ——");
		return super.doAfterBody();
	}
	
	@Override
	public int doEndTag() throws JspException {
		System.out.println("—— doEndTag ——");
		return super.doEndTag();
	}
}

3.4测试

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 引入标签库 -->
<%@taglib prefix="c" uri="com.ycxw" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>MyTag Text</title>
</head>
<body>
<c:HelloTag></c:HelloTag>
</body>
</html>

没有标签体内容运行结果:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 引入标签库 -->
<%@taglib prefix="c" uri="com.ycxw" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>MyTag Text</title>
</head>
<body>
<c:HelloTag>hello</c:HelloTag>
</body>
</html>

有标签体的内容是:

 下面将解释方法运行结果原因 —— 标签的生命周期

三、标签的生命周期

1. JSP自定义标签生命周期图

 返回值作用:

SKIP_BODY跳过主体
EVAL_BODY_INCLUDE计算主体内容并输出
EVAL_BODY_AGAIN再次计算主体一次
EVAL_PAGE计算后续内容
SKIP_PAGE

跳过页面后续内容

2. 案例论证

 根据上一案例有标签体的情况下,默认会调用助手类doStartTag、doAfterBody、doEndTag方法。

1. 如果将doStartTag方法返回值改成SKIP_BODY,则doAfterBogy方法会跳过,不会运行。 

@Override
	public int doStartTag() throws JspException {
		System.out.println("—— doStartTag ——");
		return SKIP_BODY;
	}

2. 如果将doStartTag方法返回值改成EVAL_BODY_INCLUDE,则doAfterBogy方法就会运行。

3. 如果将doAfterBody方法返回值修改成EVAL_BODY_AGAIN, 就会一直调用该方法进入死循环

4. 如果将doEndTag方法返回值修改成SKIP_PAGE, 则会跳过页面后的内容
修改前:

 修改后:

 四、标签的开发实例

1. if 标签

1.1 进入.tld文夹定义if标签并对自定义标签进行描述

    <tag>
		<name>if</name>
		<tag-class>com.xzs.Demo2Tag</tag-class>
		<body-content>JSP</body-content>
		<attribute>
			<name>text</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>

1.2 编写助手类

package com.xzs;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
 
/**
 * if 控制标签
 * 
 * @author
 *
 */
public class Demo2Tag extends BodyTagSupport{
	//接受自定义属性
	private boolean text;
	
	public boolean isText() {
		return text;
	}
 
	public void setText(boolean text) {
		this.text = text;
	}
 
	@Override
	public int doStartTag() throws JspException {
		//如果text为true就运行doaftertage,否则就跳过
		return text ? EVAL_BODY_INCLUDE : SKIP_BODY;
	}
	
}

1.3 编写jsp页面进行测试

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 引入标签库 -->
<%@taglib prefix="w" uri="com.ycxw" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>MyTag Text</title>
</head>
<body>
<w:if text="true">拉拉</w:if>
<w:if text="false">琪琪</w:if>
</body>
</html>

2. set和out标签

2.1 进入.tld文夹定义set和out标签并对自定义标签进行描述

<!-- settag -->
	<tag>
		<name>set</name>
		<tag-class>com.ycxw.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>
	<!-- outtag -->
	<tag>
		<name>out</name>
		<tag-class>com.ycxw.OutTag</tag-class>
		<body-content>JSP</body-content>
		<attribute>
			<name>value</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>

2.1编写助手类

package com.xzs;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
 
/**
 * set 数据标签 
 * 作用:储存数据
 * 
 * @author 
 *
 */
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 {
		// 要存储数据,需通过键值对方法进行储存,这里不考虑数据库只用pageContext作用域
		pageContext.setAttribute(var, value);
		return super.doStartTag();
	}
 
}
package com.xzs;
 
import java.io.IOException;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
 
/**
 * out 数据标签 
 * 作用:输出数据,首先要拿到输出流
 * 
 * @author 
 *
 */
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 {
		JspWriter out = pageContext.getOut();
		try {
			out.print(value);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return super.doStartTag();
	}
}

2.3 编写jsp页面进行测试:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 引入标签库 -->
<%@taglib prefix="w" uri="com.ycxw" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>MyTag Text</title>
</head>
<body>
<w:set var="name" value="ikun"></w:set>
<w:out value="${name }"></w:out>
</body>
</html>

得到的结果为:

 3. foreach 标签

3.1 进入.tld文夹定义foreach标签并对自定义标签进行描述
<!-- foreach -->
	<tag>
		<name>foreach</name>
		<tag-class>com.ycxw.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>
3.2 创建助手类
package com.xzs;
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
 
/**
 * foreach 标签
 * 
 * @author 
 *
 */
public class ForeachTag extends BodyTagSupport {
	private String var;
	private List<Object> items = new ArrayList<Object>();
 
	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 {
		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;
		} else {
			//没有就跳过
			return EVAL_PAGE;
		}
	}
}

实体类:

package com.xzs;
 
/**
 * 实体类
 * 
 * @author
 *
 */
public class Person {
	private int id;
	private String name;
	private int age;
 
	public int getId() {
		return id;
	}
 
	public void setId(int id) {
		this.id = id;
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public int getAge() {
		return age;
	}
 
	public void setAge(int age) {
		this.age = age;
	}
 
	public Person(int id, String name, int age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}
 
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
	}
 
}
3.3jsp测试
<%@page import="java.util.ArrayList"%>
<%@page import="com.xzs.Person"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="com.ycxw" prefix="w" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<% 
		List<Person> list = new ArrayList<Person>();
		list.add(new Person(1,"小黑宝",19));
		list.add(new Person(2,"纯路人",21));
		list.add(new Person(3,"ikun",27));
		request.setAttribute("list", list);
	%>
<w:foreach items="${list }" var="p">
	${p }
</w:foreach>
</body>
</html>

4. select 标签

4.1 进入.tld文夹定义select标签并对自定义标签进行描述
    <tag>
        <name>select</name>
        <tag-class>com.xzs.SelectTag</tag-class>
        <body-content>JSP</body-content>
        <attribute>
            <name>id</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <!--数据源-->
        <attribute>
            <name>items</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>textKey</name>
            <required>true</required>
            <rtexprvalue>false</rtexprvalue>
        </attribute>
        <attribute>
            <name>textVal</name>
            <required>true</required>
            <rtexprvalue>false</rtexprvalue>
        </attribute>
        <!--不是从数据库加载出来的数据,下拉框的头一个选项的value值-->
        <attribute>
            <name>headertextKey</name>
            <required>true</required>
            <rtexprvalue>false</rtexprvalue>
        </attribute>
        <!--不是从数据库加载出来的数据,下拉框的头一个选项的展示值-->
        <attribute>
            <name>headertextVal</name>
            <required>true</required>
            <rtexprvalue>false</rtexprvalue>
        </attribute>
        <attribute>
            <name>selectedVal</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
4.2 创建助手类
package com.xzs;
 
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;
 
import org.apache.commons.beanutils.PropertyUtils;
 
/**
 * select 标签 
 * 分析: 
 * 1.后台需要遍历->数据源 items 
 * 2.需要一个对象的属性代表下拉框对应的展示内容->textVal
 * 3.需要一个对象属性代表下拉框对应的value值 ->textKey 
 * 4.默认的头部选项展示内容 ->headerTextVal 
 * 5.默认的头部选项值->headerTextKey 
 * 6.数据中存储的值,为了方便做数据回显 -> selectedVal 
 * 7.方便获取获取标签设置样式...等等标记 id、name
 * 
 * @author 云村小威
 *
 */
public class SelectTag extends BodyTagSupport {
	private static final long serialVersionUID = 1L;
	
	private List<Object> items;
	private String textVal;
	private String textKey;
	private String headertextVal;
	private String headertextKey;
	private String selectedVal;
	private String id;
 
	public List<Object> getItems() {
		return items;
	}
 
	public void setItems(List<Object> items) {
		this.items = items;
	}
 
	public String getTextVal() {
		return textVal;
	}
 
	public void setTextVal(String textVal) {
		this.textVal = textVal;
	}
 
	public String getTextKey() {
		return textKey;
	}
 
	public void setTextKey(String textKey) {
		this.textKey = textKey;
	}
 
	public String getHeadertextVal() {
		return headertextVal;
	}
 
	public void setHeadertextVal(String headertextVal) {
		this.headertextVal = headertextVal;
	}
 
	public String getHeadertextKey() {
		return headertextKey;
	}
 
	public void setHeadertextKey(String headertextKey) {
		this.headertextKey = headertextKey;
	}
 
	public String getSelectedVal() {
		return selectedVal;
	}
 
	public void setSelectedVal(String selectedVal) {
		this.selectedVal = selectedVal;
	}
 
	public String getId() {
		return id;
	}
 
	public void setId(String id) {
		this.id = id;
	}
 
	@Override
	public int doStartTag() throws JspException {
		// 获取io流
		JspWriter out = pageContext.getOut();
		try {
			out.print(toHTML());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return super.doStartTag();
	}
 
	/**
	 * 数据回显方法
	 * @return
	 * @throws Exception 
	 */
	private String toHTML() throws Exception {
		// 利用stringbuffer拼接标签
		StringBuffer sb = new StringBuffer();
		sb.append("<select id='"+id+"'>");
		//判断不为空就给头部加默认选项
		if(headertextVal != null && !"".equals(headertextVal)) {
			sb.append("<option value='"+headertextKey+"'>"+headertextVal+"</option>");
		}
		//当集合有东西时才执行
		if (items.size() > 0) {
			for (Object obj : items) {
				// 利用反射获取到页面传过来的属性名对应的属性值(id)
				Field f = obj.getClass().getDeclaredField(textKey);
				//打开修饰符访问权限
				f.setAccessible(true);
				if(selectedVal != null && !"".equals(selectedVal) && selectedVal.equals(f.get(obj))) {
					sb.append("<option selected value='"+f.get(obj)+"'>"+PropertyUtils.getProperty(obj, textVal)+"</option>");
				}else {
					sb.append("<option value='"+f.get(obj)+"'>"+PropertyUtils.getProperty(obj, textVal)+"</option>");
				}
			}
		}
		sb.append("</select>");
		return sb.toString();
	}
 
}

4.3jsp页面测试:

<%@page import="java.util.ArrayList"%>
<%@page import="com.xzs.Person"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib uri="com.xzs" prefix="w"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%
		List<Person> list = new ArrayList<Person>();
		list.add(new Person(1, "小黑宝", 19));
		list.add(new Person(2, "纯路人", 21));
		list.add(new Person(3, "ikun", 27));
		request.setAttribute("list", list);
	%>
	<w:select headertextVal="请选择" textVal="name" items="${list }"
		selectedVal="-1" headertextKey="-1" textKey="id"></w:select>
</body>
</html>

结果为:

 最后总结:开发自定义标签的目的就是给我们带来更方便的操作

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值