JSP-自定义标签

一、基础

1.1 目的

目的:取代JSP文件中的脚本代码,避免JSP 脚本和 HTML 代码混杂。

取代前取代后
难以阅读。易于阅读
维护成本高。便于维护
美工人员难以参与开发。便于协同开发

1.2 含义

设计自己的JSP标签库,使用自己的标签。

1.3 步骤

第一步:开发自定义标签处理类;
第二步:建立一个 myFirstTagLib.tld 文件。每个 myFirstTagLib.tld 文件对应一个标签库,每个标签库对应多个标签;
第三步:在 JSP 文件中使用自定义标签。

1.4 自定义标签继承结构

在这里插入图片描述

二、修改标签体内容案例

2.1 开发自定义标签处理类

注意:如果标签类包含属性,每个属性都有对应的 getter 和 setter 方法。

2.1.1 BodyTagSupport开发

这是JSP 1.1 版中,不推荐,原因太烦锁。推荐JSP 2 ,SimpleTagSupport开发。
实现:extends BodyTagSupport,重写doEndTag()。

常量含义
EVAL_BODY_INCLUDE执行标签体里的内容。
SKIP_BODY跳过标签体里的内容。
EVAL_PAGE继续后面操作
SKIP_PAGE跳过后面操作

BodyTagSupportDemo.java

import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
// 功能:修改标签体的内容。
public class BodyTagSupportDemo extends BodyTagSupport{
	// 存储标签体中的内容。
	private BodyContent bodyContent; 
	// 重写setBodyContent()方法。
	// 目的:接收外部传来的标签体,以便后续对变迁体的操作。
	@Override
	public void setBodyContent(BodyContent b){
		this.bodyContent = b;
	}
	// 设置结束标签的方法。
	@Override
	public int doEndTag() throws JspException,IOException{
		//获取标签体中的内容。
		String content = bodyContent.getString(); 
		// 向控制台输出
		System.out.println(content);
		//修改后的内容。
		String newStr = "这是新的内容"; 				
		//获取页面输出流。
		JspWriter jspWriter = bodyContent.getEnclosingWriter(); 
		// 将修改后的内容再写回到页面中。
		jspWriter.write(newStr); 
		// 继续后面操作。
		return EVAL_PAGE;
	}
}

2.1.2 SimpleTagSupport开发

推荐JSP 2 ,SimpleTagSupport开发。
实现:extends SimpleTagSupport,重写doTag()。
注意: doTag() 方法负责生成页面内容。
SimpleTagSupport.java

package com.my.EL;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
// 功能:修改标签体的内容。
public class SimpleTagSupportDemo3 extends SimpleTagSupport{
	@Override
	public void doTag() throws JspException,IOException{
		// ========获得标签体中的内容。===============
		JspFragment jspFragment = getJspBody(); // 放入缓冲区中。		
		// 2.但JspFragment类对象无法取到缓冲区的数据。因此使用StringWright类对象获取。
		StringWriter stringWriter = new StringWriter();		
		// 3.JspFragment类对象转移标签体内容至StringWright类对象中。A.invoke(B),将A中内容写入到B中。映射关系,同时变化。
		jspFragment.invoke(stringWriter);	
		// 4.获取标签体内容。
		String content = stringWriter.toString();
		// ================更改标签体中的内容。===============
		// 5. 更改标签体内容。
		content = "更改标签体内容后的内容";
		// ================输出标签体中的内容。======================
		// 6.输出新内容。先写如PageContext类对象中。
		PageContext pageContext = (PageContext) getJspContext();		
		// 7.输出到网页上。利用输出流类。
		JspWriter out = pageContext.getOut();		
		// 8. 输出到网页上。
		out.write(content);
	}
}

2.2 建立 TLD 文件

TLD : Tag Library Definition。
每个 TLD 文件对应一个标签库,一个标签库中可包含多个标签,TLD 文件也称为标签库定义文件。
路径:放置到 Web 应用的 WEB-INF/ 路径,或 WEB-INF 的任意子路径下。
myFirstTagLib.tld :

<?xml version="1.0" encoding="UTF-8" ?>
<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 http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
    
    <description>A tag library exercising SimpleTag handlers.</description>
    <!-- 指定该标签库实现的版本,这是一个作为标识的内部版本号,对程序没有太大的作用。 -->
    <tlib-version>1.0</tlib-version>
    <!-- 该标签库的默认短名,该名称通常也没有太大的用处。 -->
    <short-name>SimpleTagLibrary</short-name>
    <!-- 非常重要,它指定该标签库的 URI,相当于指定该标签库的唯一标识。 -->
    <uri>firstTag</uri>
    
    <!-- 自定义标签1:输出当前日期 -->
    <tag>
    	<!-- 非常重要。该标签的名称,JSP 页面中就是根据该名称来使用此标签的。 -->
        <name>nowFormat</name>
        <!-- 非常重要。指定标签的处理类,指定了标签由哪个 Java 类来处理。 -->
        <tag-class>com.my.EL.NowFormat</tag-class>
        <!-- 非常重要。指定标签体内容。 -->
        <body-content>empty</body-content>
        <!--
        empty:禁止标签中写入内容。
        scriptless:允许写入内容(文本、EL表达式或JSP动作)。
        JSP:允许出现脚本代码。不推荐。
        tagdependent:标签体内容可以写入到<boy-content>,由自定义标签体类处理,即传参。不推荐。 -->
    </tag>
    
     <!-- 自定义标签2: 控制标签体内容是否显示。-->
    <tag>
        <name>skipBodyOrEvalBodyInclude</name>
        <tag-class>com.my.EL.SkipBodyOrEvalBodyIncludeTag</tag-class> 
        <body-content>scriptless</body-content>
    </tag>
    
    <!-- 自定义标签3 :控制标签结束后,结后标签后面的代码是否执行。-->
    <tag>
        <name>skipPageOrEvalPage</name>
        <tag-class>com.my.EL.SkipPageOrEvalPageTag</tag-class> 
        <body-content>empty</body-content>
    </tag>
    
    <!-- 自定义标签4 -->
    <tag>
        <name>dbConnectionTag</name>
        <tag-class>com.my.EL.DBConnectionTag</tag-class> 
        <body-content>empty</body-content>
        <attribute>
        	<name>driver</name>
        	<!-- 设置是否为必须属性 -->
        	<required>true</required>
        	<!-- 设置属性中属性值是否可以用EL表达式 -->
        	<rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
        	<name>url</name>
        	<required>true</required>
        	<rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
        	<name>user</name>
        	<required>true</required>
        	<rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
        	<name>password</name>
        	<required>true</required>
        	<rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
        	<name>sql</name>
        	<required>true</required>
        	<rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
    
    <!-- 自定义标签5 :控制标签体的内容是否重复执行。循环结构。-->
    <tag>
        <name>iterationTag</name>
        <tag-class>com.my.EL.IterationTag</tag-class> 
        <body-content>scriptless</body-content>
        <attribute>
        	<name>var</name>
        	<required>true</required>
        </attribute>
        <attribute>
        	<name>items</name>
        	<required>true</required>
        	<rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
    <!-- 自定义标签6 :修改标签体内容,输出新内容。-->
    <tag>
        <name>bodyTagSupportTag</name>
        <tag-class>com.my.EL.BodyTagSupportDemo</tag-class> 
        <body-content>scriptless</body-content>
    </tag>
    
    <!-- 自定义标签7 -->
    <tag>
        <name>simpleTagSupportDemoTag</name>
        <tag-class>com.my.EL.SimpleTagSupportDemo</tag-class> 
        <body-content>empty</body-content>
    </tag>
    <!-- 自定义标签8 -->
    <tag>
        <name>simpleTagSupportDemo2Tag</name>
        <tag-class>com.my.EL.SimpleTagSupportDemo2</tag-class> 
        <body-content>scriptless</body-content>
    </tag>
     <!-- 自定义标签9 -->
    <tag>
        <name>simpleTagSupportDemo3Tag</name>
        <tag-class>com.my.EL.SimpleTagSupportDemo3</tag-class> 
        <body-content>scriptless</body-content>
    </tag>
    <!-- 自定义标签10 -->
    <tag>
        <name>IfTag</name>
        <tag-class>com.my.EL.IfTag</tag-class> 
        <body-content>scriptless</body-content>
        <attribute>
        	<name>test</name>
        	<required>true</required>
        	<rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
    <!-- 自定义标签11 -->
    <tag>
        <name>chooseTag</name>
        <tag-class>com.my.EL.ChooseTag</tag-class> 
        <body-content>scriptless</body-content>
    </tag>
    <!-- 自定义标签12 -->
    <tag>
        <name>whenTag</name>
        <tag-class>com.my.EL.WhenTag</tag-class> 
        <body-content>scriptless</body-content>
        <attribute>
        	<name>test</name>
        	<required>true</required>
        	<rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
    <!-- 自定义标签13 -->
    <tag>
        <name>otherWiseTag</name>
        <tag-class>com.my.EL.OtherWiseTag</tag-class> 
        <body-content>scriptless</body-content>
    </tag>   
</taglib>

2.3 使用标签库

在 JSP 页面中确定指定标签需要 2 点:
1、标签库 URI:确定使用哪个标签库。
2、标签名:确定使用哪个标签。
使用步骤:
1、导入标签库:使用 taglib 编译指令导入标签库,就是将标签库和指定前缀关联起来。

<%@ taglib uri="tagliburi" prefix="tagPrefix" %>

2、使用标签:在 JSP 页面中使用自定义标签。

<!-- 有标签体时 -->
<tagPrefix:tagName tagAttribute=”tagValue”  > 
	<tagBody/> 
</tagPrefix:tagName>
<!-- 没有标签体时 -->
<tagPrefix:tagName tagAttribute=”tagValue”  />

JSTL_createLable.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.text.*,java.util.*" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="firstTag" prefix="my" %>
<!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>自定义标签</title>
</head>
<body>
	<h1>自定义标签 </h1><hr/>
	<!-- 原始设置日期格式的方法 -->
	<%
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
		Date now = new Date();
		String nowString = sdf.format(now);
	%>
	现在时间:<%=nowString %><br/>
	<!-- 原始设置日期格式的方法 -->
	我现在时间:<my:nowFormat /><br/>
	
	<hr/><h1>设置标签体是否显示。</h1>
	<my:skipBodyOrEvalBodyInclude>
		<h1>88888888888888</h1>
	</my:skipBodyOrEvalBodyInclude>
	
	<%-- <hr/><h1>设置标签后的内容是否显示</h1>
	<my:skipPageOrEvalPage />
	<h3>本种方法skipPageOrEvalPage,本文字不显示。</h3> --%>
	
	<hr/><h1>设置标签的属性。</h1>
	静态创建
	<my:dbConnectionTag user="root" password="123456" url="jdbc:mysql://localhost:3306/shopping" driver="com.mysql.jdbc.Driver" sql="SELECT `name` FROM items"/>	
	动态创建
	<%
		String user = "root";
		String password = "123456"; 
		String url = "jdbc:mysql://localhost:3306/shopping"; 
		String driver = "com.mysql.jdbc.Driver"; 
		String sql = "SELECT `name` FROM items";
		// 封装到pageContext对象中,以便后续EL表达式调用。
		pageContext.setAttribute("user", user);
		pageContext.setAttribute("password", password);
		pageContext.setAttribute("url", url);
		pageContext.setAttribute("driver", driver);
		pageContext.setAttribute("sql", sql);
		// 
	%>
	<my:dbConnectionTag user="${user}" password="${password}" url="${url}" driver="${driver}" sql="${sql}"/>
	
	<hr/><h1>设置标签。迭代器</h1>
	<%
		String[] person = {"Tom","Jack","Lily"};
		// 封装到pageContext对象中,以便后续EL表达式调用。
		pageContext.setAttribute("person",person);
	%>
	<my:iterationTag items="${person}" var="name">${name}</my:iterationTag>	
	<hr/><h1>修改标签体中的内容。</h1>
	<my:bodyTagSupportTag>hello World!</my:bodyTagSupportTag>
</body>
</html>

三、带属性的标签案例

3.1 开发自定义标签处理类

注意:带属性标签必须为每个属性提供对应的 setter 和 getter 方法。
DBConnectionTag.java:

package com.my.EL;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
// 带属性的标签。
public class DBConnectionTag extends SimpleTagSupport {
	//标签的属性
	private String driver;
	private String url;
	private String password;
	private String user;
	private String sql;
	//执行数据库访问的对象 
	private Connection conn = null;
	private PreparedStatement ps = null;
	private ResultSet rs = null;
	private ResultSetMetaData rsmd = null;
	//标签属性的getter和setter方法
	public String getDriver() {
		return driver;
	}
	public void setDriver(String driver) {
		this.driver = driver;
	}
	
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getUser() {
		return user;
	}
	public void setUser(String user) {
		this.user = user;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getSql() {
		return sql;
	}
	public void setSql(String sql) {
		this.sql = sql;
	}
	// 重写doTag()方法。
	@Override
	public void doTag() throws JspException {
		try {
			//注册驱动
			Class.forName(driver);
			//获取数据库连接
			conn = DriverManager.getConnection(url,user,password);
			//创建PreparedStatement对象
			ps = conn.prepareStatement(sql);
			// 创建ResultSet对象
			rs = ps.executeQuery();
			// 创建ResultSetMetaData对象
			rsmd = rs.getMetaData();
			// 获取列数目
            int columnCount = rsmd.getColumnCount();
            //获取页面输出流
            Writer out = getJspContext().getOut();
            //在页面输出表格
            out.write("<table border='1' bgColor='9999cc' width='400'>");
			if (rs != null) {
				//遍历结果集
				while (rs.next()) {
					out.write("<tr>");
                	//逐列输出查询到的数据
                	for (int i = 1 ; i <= columnCount ; i++ ){
                   		out.write("<td>");
	                    out.write(rs.getString(i));
                    	out.write("</td>");
                	}
	               	out.write("</tr>");
				}
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null) {
					rs.close();
				}
				if (ps != null) {
					ps.close();
				}
				if (conn != null) {
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

3.2 建立 TLD 文件

<attribute>的子元素:
1、name:设置属性名。
2、required:该属性是否为必需。
3、fragment | rtexprvalue:该属性是否支持 JSP 脚本、表达式等动态内容。

<tag>
	<!-- 定义标签名 -->
	<name>dbConnectionTag</name>
	<!-- 指定标签处理类 -->
	<tag-class>com.my.EL.DBConnectionTag</tag-class> 
	<!-- 定义标签体为空 -->
	<body-content>empty</body-content>
	 <!-- 配置标签属性:driver -->
	<attribute>
		<name>driver</name>
		<!-- 设置是否为必须属性 -->
		<required>true</required>
		<!-- 设置属性中属性值是否可以用EL表达式 -->
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<!-- 配置标签属性:url -->
	<attribute>
		<name>url</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<!-- 配置标签属性:user -->
	<attribute>
		<name>user</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<!-- 配置标签属性:password -->
	<attribute>
		<name>password</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<!-- 配置标签属性:sql -->
	<attribute>
		<name>sql</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
</tag>

3.3 使用标签库

静态创建:
<my:dbConnectionTag user="root" password="123456" url="jdbc:mysql://localhost:3306/shopping" driver="com.mysql.jdbc.Driver" sql="SELECT `name` FROM items"/>
动态创建:
<%
	String user = "root";
	String password = "123456"; 
	String url = "jdbc:mysql://localhost:3306/shopping"; 
	String driver = "com.mysql.jdbc.Driver"; 
	String sql = "SELECT `name` FROM items";
	// 封装到pageContext对象中,以便后续EL表达式调用。
	pageContext.setAttribute("user", user);
	pageContext.setAttribute("password", password);
	pageContext.setAttribute("url", url);
	pageContext.setAttribute("driver", driver);
	pageContext.setAttribute("sql", sql);
%>
<my:dbConnectionTag user="${user}" password="${password}" url="${url}" driver="${driver}" sql="${sql}"/>

四、带标签体的标签案例

带标签体的标签,可以在标签内嵌入其他内容(包括静态的 HTML 内容和动态的 JSP 内容),通常用于完成一些逻辑运算,例如判断和循环等。

4.1 开发自定义标签处理类

IterationTag.java:

package com.my.EL;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
// 带标签体的标签
public class IterationTag extends SimpleTagSupport{
	// 标签属性。
	private String collection; // 集合。
	private String item; // 集合的元素。
	public String getCollection() {
		return collection;
	}
	public void setCollection(String collection) {
		this.collection = collection;
	}
	public String getItem() {
		return item;
	}
	public void setItem(String item) {
		this.item = item;
	}
	@Override
	public void doTag() throws JspException,IOException{
		// 创建JspContext实例对象。
		JspContext jspContext = getJspContext();
		// //从page scope中获取属性名为collection的集合
		Collection itemList = (Collection)jspContext.getAttribute(collection);
		//遍历集合
        for (Object s : itemList){
            //将集合的元素设置到page 范围
            getJspContext().setAttribute(item, s );
            //输出标签体
            getJspBody().invoke(null);
        }
	}
}

4.2 建立 TLD 文件

<tag>
    <name>iterator</name>
    <tag-class>com.my.EL.IteratorTag</tag-class>
    <body-content>scriptless</body-content>
    <!-- 配置标签属性:collection -->
    <attribute>
        <name>collection</name> 
        <required>true</required>
        <fragment>true</fragment>
    </attribute>
    <!-- 配置标签属性:item -->
    <attribute>
        <name>item</name> 
        <required>true</required>
        <fragment>true</fragment>
    </attribute>
</tag>

4.3 使用标签库

 <%
	//创建一个List对象
	List<String> a = new ArrayList<String>();
	a.add("hello");
	a.add("world");
	a.add("java");
	//将List对象放入page范围内
	pageContext.setAttribute("a" , a);
%>
<table border="1" bgcolor="aaaadd" width="300">
	<!-- 使用迭代器标签,对a集合进行迭代 -->
	<mytag:iterator collection="a" item="item">
		<tr>
			<td>${pageScope.item}</td>
		<tr>
	</mytag:iterator>
</table>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值