当前位置: 首页 > article >正文

Jsp技术入门指南【十二】自定义标签

Jsp技术入门指南【十二】自定义标签

  • 前言
  • 一、什么是标签
  • 二、标签的类型有哪些?
    • 1. 空标签
    • 2. 带有属性的标签
    • 3. 带主体的标签
  • 三、自定义标签的部件
    • 3.1 自定义标签的四步骤
    • 3.2 标签处理程序
    • 3.3 自定义标签的开发及使用步骤
      • 第一步:创建标签助手类
      • 第二步:创建TLD文件
      • 第三步:在JSP中使用自定义标签
  • 四、JSP标签文件
    • 4.1 Tag File简介
    • 4.2 Tag File的基本结构
    • 4.3 在JSP中使用Tag File


前言

  • 在前面的博客中,我们深入探讨了如何通过JSTL的SQL标签库简化数据库操作,解决了原生JDBC代码冗余、耦合度高的问题,实现了数据库与页面数据的高效交互。这一实践让我们认识到,标签化开发是提升JSP页面简洁性和可维护性的关键手段

然而,随着Web应用复杂度的提升,标准标签库(如JSTL)提供的通用功能已难以满足个性化业务需求
当我们需要封装特定业务逻辑、复用高频操作或实现更灵活的页面控制时,自定义标签便成为必然选择

  • 自定义标签允许开发者将重复的Java代码或复杂逻辑封装为可复用的标签组件,使JSP页面彻底摆脱脚本代码的冗余,真正实现“标签即逻辑”的开发模式。
  • 它不仅延续了标签化开发“关注点分离”的优势,更赋予开发者根据项目需求自由扩展标签功能的能力,是构建高效、整洁Web应用的重要技术手段

接下来,我们将从自定义标签的核心部件(标签处理类、TLD文件)入手,结合实战案例解析其开发流程、类型特性及最佳实践,来逐步讲解自定义标签

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的JSP知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12950980.html?spm=1001.2014.3001.5482


一、什么是标签

  • 在JSP(JavaServer Pages)中,标签是一种特殊的标记,用于封装功能并简化JSP页面的开发。
  • 标签可以替代复杂的Java代码,使页面结构更清晰、更易于维护。
  • 标签类似于HTML标记,但它们执行的是自定义的Java逻辑。

二、标签的类型有哪些?

1. 空标签

空标签是没有主体内容的标签,它们只包含标签名和属性。例如:

<jsp:include page="header.jsp" />

2. 带有属性的标签

这类标签可以接受参数(属性)来控制其行为。例如:

<c:if test="${condition}"><!-- 标签主体 -->
</c:if>

其中testc:if标签的一个属性。

3. 带主体的标签

带主体的标签包含内容(主体),标签处理程序可以处理这些内容。例如:

<mytag:repeat count="5"><p>这是重复内容</p>
</mytag:repeat>

三、自定义标签的部件

3.1 自定义标签的四步骤

自定义标签的开发通常包含四个主要步骤:

  1. 标签处理程序:编写Java类实现标签的逻辑
  2. TLD文件:创建标签库描述符文件
  3. JSP文件:在JSP页面中使用自定义标签
  4. 部署:将标签处理类和TLD文件部署到应用中

我们重点关注前两个步骤:标签处理程序和TLD文件

3.2 标签处理程序

标签处理程序是实现标签逻辑的Java类。它通常继承自TagSupportBodyTagSupport,并重写以下方法:

  • doStartTag():当遇到标签开始时执行
  • doEndTag():当遇到标签结束时执行
  • doAfterBody():处理完标签主体后执行(仅当标签有主体时)

这些方法的返回值控制标签的行为,常见的返回值常量有:

  • SKIP_BODY:跳过标签主体内容
  • EVAL_BODY_INCLUDE:计算并包含标签主体内容
  • EVAL_PAGE:继续处理页面剩余部分
  • SKIP_PAGE:跳过页面剩余部分
  • EVAL_BODY_AGAIN:再次计算标签主体内容(用于迭代)

示例代码
下面是一个简单的标签处理程序示例,它会在页面上显示当前时间:

package com.example.tags;import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;public class CurrentTimeTag extends BodyTagSupport {private String format = "yyyy-MM-dd HH:mm:ss"; // 默认格式public void setFormat(String format) {this.format = format;}@Overridepublic int doStartTag() throws JspException {try {// 获取当前时间并格式化LocalDateTime now = LocalDateTime.now();String formattedTime = now.format(DateTimeFormatter.ofPattern(format));// 将格式化后的时间输出到页面pageContext.getOut().print(formattedTime);} catch (IOException e) {throw new JspException("Error writing to JSP writer", e);}return SKIP_BODY; // 跳过标签主体,因为我们不需要处理主体内容}
}

3.3 自定义标签的开发及使用步骤

第一步:创建标签助手类

标签助手类是实现标签逻辑的核心。下面是一个更复杂的示例,展示了如何处理标签主体内容:

package com.example.tags;import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.io.IOException;public class RepeatTag extends BodyTagSupport {private int count;public void setCount(int count) {this.count = count;}private int currentIteration = 0;@Overridepublic int doStartTag() throws JspException {currentIteration = 0;if (count > 0) {return EVAL_BODY_INCLUDE; // 计算并包含标签主体内容} else {return SKIP_BODY; // 跳过标签主体}}@Overridepublic int doAfterBody() throws JspException {currentIteration++;if (currentIteration < count) {return EVAL_BODY_AGAIN; // 再次计算标签主体内容} else {return SKIP_BODY; // 完成迭代,跳过剩余主体}}@Overridepublic int doEndTag() throws JspException {// 重置状态,确保标签可以被重用currentIteration = 0;return EVAL_PAGE; // 继续处理页面剩余部分}
}

第二步:创建TLD文件

TLD(Tag Library Descriptor)文件是一个XML文件,用于描述标签库和其中的标签。下面是对应上述标签的TLD文件示例:

<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"version="2.1"><tlib-version>1.0</tlib-version><short-name>custom</short-name><uri>/WEB-INF/tlds/custom.tld</uri><!-- 定义currentTime标签 --><tag><name>currentTime</name><tag-class>com.example.tags.CurrentTimeTag</tag-class><body-content>empty</body-content><attribute><name>format</name><required>false</required><rtexprvalue>true</rtexprvalue></attribute></tag><!-- 定义repeat标签 --><tag><name>repeat</name><tag-class>com.example.tags.RepeatTag</tag-class><body-content>scriptless</body-content><attribute><name>count</name><required>true</required><rtexprvalue>true</rtexprvalue></attribute></tag>
</taglib>

第三步:在JSP中使用自定义标签

下面是如何在JSP页面中使用上述自定义标签的示例:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="/WEB-INF/tlds/custom.tld" prefix="custom" %><!DOCTYPE html>
<html>
<head><title>自定义标签示例</title>
</head>
<body><h3>当前时间:<custom:currentTime format="yyyy-MM-dd" /></h3><h3>重复内容示例:</h3><custom:repeat count="3"><p>这是第 <custom:currentTime format="ss" /> 次重复</p></custom:repeat>
</body>
</html>

四、JSP标签文件

4.1 Tag File简介

Tag File是一种特殊的JSP文件,用于创建自定义标签

  • 与编写Java类不同,Tag File使用JSP语法,可以更方便地实现简单的标签功能。

Tag File必须放在WEB-INF/tags目录下或其子目录中才能被JSP容器识别。例如:

  • WEB-INF/tags/mytag.tag
  • WEB-INF/tags/utils/format.tag

在这里插入图片描述

4.2 Tag File的基本结构

Tag File的基本结构与JSP文件类似,但不需要包含完整的JSP页面元素(如htmlbody标签)。下面是一个简单的Tag File示例:

<%@ attribute name="message" required="true" type="java.lang.String" %>
<%@ attribute name="color" required="false" type="java.lang.String" default="black" %><span style="color: ${color};">${message}</span>

4.3 在JSP中使用Tag File

  • 要在JSP页面中使用Tag File,需要通过taglib指令引用标签库:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib tagdir="/WEB-INF/tags" prefix="mytag" %><!DOCTYPE html>
<html>
<head><title>Tag File示例</title>
</head>
<body><h3>使用Tag File的消息:</h3><mytag:messageTag message="欢迎使用JSP Tag File" color="blue" /><h3>循环示例:</h3><c:forEach var="i" begin="1" end="5"><mytag:messageTag message="这是第 ${i} 条消息" color="green" /></c:forEach>
</body>
</html>
  • Tag File的优点是开发简单,不需要编译Java类,但对于复杂的标签逻辑,仍然建议使用Java类实现的标签处理程序。

以上就是这篇博客的全部内容,下一篇我们将继续探索JSP的更多精彩内容。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的JSP知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12950980.html?spm=1001.2014.3001.5482

非常感谢您的阅读,喜欢的话记得三连哦

在这里插入图片描述

相关文章:

Jsp技术入门指南【十二】自定义标签

Jsp技术入门指南【十二】自定义标签 前言一、什么是标签二、标签的类型有哪些&#xff1f;1. 空标签2. 带有属性的标签3. 带主体的标签 三、自定义标签的部件3.1 自定义标签的四步骤3.2 标签处理程序3.3 自定义标签的开发及使用步骤第一步&#xff1a;创建标签助手类第二步&…...

Java—— 泛型详解

泛型概述 泛型是JDK5中引入的特性&#xff0c;可以在编译阶段约束操作的数据类型&#xff0c;并进行检查。 泛型的格式&#xff1a;<数据类型> 注意&#xff1a;泛型只能支持引用数据类型。 泛型的好处 没有泛型的时候&#xff0c;可以往集合中添加任意类型的数据&#x…...

GPT-4o, GPT 4.5, GPT 4.1, O3, O4-mini等模型的区别与联系

大模型时代浪潮汹涌,作为其中的领军者,OpenAI 其推出的系列模型以强大的能力深刻影响着整个行业,并常常成为业界其他公司对标和比较的基准。因此,深入了解 OpenAI 的大模型,不仅是为了使用它们,更是为了理解当前大模型的能力边界和发展趋势,这对于我们评估和选择其他各类…...

Harness: 全流程 DevOps 解决方案,让持续集成如吃饭般简单

引言 在当今快速发展的软件开发世界中,高效的 DevOps 工具变得越来越重要。Harness 作为一个开源的运维平台,为开发和运维团队提供了从代码托管到 CI/CD 的全流程解决方案,同时实现自动化的开发环境和制品管理。这种集中化的工具可以显著减少运维难度,提高团队效率,真正解…...

Kubernetes生产实战(十二):无工具容器网络连接数暴增指南

当线上容器突然出现TCP连接数暴涨&#xff0c;而容器内又没有安装任何调试工具时&#xff0c;如何快速定位问题&#xff1f;本文将分享一套经过大型互联网公司验证的排查方案&#xff0c;涵盖从快速应急到根因分析的全流程。 一、快速锁定问题容器 查看pod 连接数方式&#x…...

MySQL的Order by与Group by优化详解!

目录 前言核心思想&#xff1a;让索引帮你“排好序”或“分好组”Part 1: ORDER BY 优化详解1.1 什么是 Filesort&#xff1f;为什么它慢&#xff1f;1.2 如何避免 Filesort&#xff1f;—— 利用索引的有序性1.3 EXPLAIN 示例 (ORDER BY) Part 2: GROUP BY 优化详解2.1 什么是…...

Spring MVC中跨域问题处理

在Spring MVC中处理跨域问题可以通过以下几种方式实现&#xff0c;确保前后端能够正常通信&#xff1a; 方法一&#xff1a;使用 CrossOrigin 注解 适用于局部控制跨域配置&#xff0c;直接在Controller或方法上添加注解。 示例代码&#xff1a; RestController CrossOrigin…...

软件测试——用例篇(3)

目录 一、设计测试用例的具体方法 1.1等价类 1.1.1等价类概念介绍 1.1.2等价类分类 1.2边界值 1.2.1边界值分析法 1.2.2边界值分类 1.3正交法 1.3.1正交表 1.3.2正交法设计测试用例步骤 1.4判定表法 1.4.1判定表 1.4.2判定表方法设计测试用例 1.5 场景法 1.6错误…...

在 Win11 下安装 Wireshark 的详细步骤

目录 一、了解 Wireshark1. 作用和功能2. 使用步骤 二、下载安装包三、运行安装包四、使用 Wireshark1. 抓包2. 窗口介绍3. 过滤器&#xff08;显示 / 捕获过滤器&#xff09;4. 保存过滤后的报文1&#xff09;显示过滤器表达式&#xff08;了解&#xff09;2&#xff09;过滤表…...

AI编程: 使用Trae1小时做成的音视频工具,提取音频并识别文本

背景 在上个月&#xff0c;有网页咨询我怎么才能获取视频中的音频并识别成文本&#xff0c;我当时给他的回答是去问一下AI&#xff0c;让AI来给你答案。 他觉得我在敷衍他&#xff0c;大骂了我一顿&#xff0c;大家觉得我的回答对吗&#xff1f; 小编心里委屈&#xff0c;我…...

区块链技术中的Java SE实战:从企业级应用到5大核心问题解析

区块链技术中的Java SE实战&#xff1a;从企业级应用到5大核心问题解析 问题1&#xff1a;如何在Java SE中实现区块链的基本数据结构&#xff1f; 回答1&#xff1a; 区块链的核心数据结构是链式区块&#xff0c;每个区块包含数据、哈希值以及前一个区块的哈希值。以下是一个…...

RTC实时时钟DS1337S/PT7C4337WEX国产替代FRTC1337S

NYFEA徕飞公司的FRTC1337S串行实时时钟是一种低功耗时钟/日历&#xff0c;被设计成可以无缝替代市场上流行的DS1337S和PT7C4337WEX(SOP8)两种型号, 具有两个可编程的时钟闹钟和一个可编程方波输出。 地址和数据通过2线双向总线串行传输。时钟/日历提供秒、分钟、小时、天、日期…...

Vue3.5 企业级管理系统实战(十七):角色管理

本篇主要探讨角色管理功能&#xff0c;其中菜单权限这里先不实现&#xff0c;后续在菜单管理中再进行实现。接口部分依然是使用 Apifox mock 的。 1 角色 api 在 src/api/role.ts 中添加角色相关 api&#xff0c;代码如下&#xff1a; //src/api/role.ts import service fro…...

QTableWidget实现多级表头、表头冻结效果

最终效果&#xff1a; 实现思路&#xff1a;如果只用一个表格的话写起来比较麻烦&#xff0c;可以考虑使用两个QTableWidget组合&#xff0c;把复杂的表头一个用QTableWidget显示&#xff0c;其他内容用另一个QTableWidget。 #include "mainwindow.h" #include &qu…...

A2A大模型协议及Java示例

A2A大模型协议概述 1. 协议作用 A2A协议旨在解决以下问题&#xff1a; 数据交换&#xff1a;不同应用程序之间的数据格式可能不一致&#xff0c;A2A协议通过定义统一的接口和数据格式解决这一问题。模型调用&#xff1a;提供标准化的接口&#xff0c;使得外部应用可以轻松调…...

单脉冲前视成像多目标分辨算法——论文阅读

单脉冲前视成像多目标分辨算法 1. 论文的研究目标及实际意义1.1 研究目标1.2 实际问题与产业意义2. 论文的创新方法及公式解析2.1 核心思路2.2 关键公式与模型2.2.1 单脉冲雷达信号模型2.2.2 匹配滤波输出模型2.2.3 多目标联合观测模型2.2.4 对数似然函数与优化2.2.5 MDL准则目…...

CMake 入门实践

CMake 入门实践 第一章 概念与基础项目1.1 CMake 基础认知1.2 最小 CMake 项目1.3 构建流程验证 第二章 多文件项目管理2.1 项目结构2.2 源码示例2.3 CMake 配置 第三章 库文件管理实战3.1 项目结构3.2 核心配置3.3 接口设计 第四章 构建类型与编译优化4.1 构建类型配置4.2 构建…...

异地多活单元化架构下的微服务体系

治理服务间的跨IDC调用&#xff0c;而数据库层面还是要跨IDC 服务注册中心拆开、 金融要求&#xff0c;距离太远&#xff0c;异地备库&#xff0c;如果延迟没读到数据就可能有资损&#xff0c;IDC3平时不能用&#xff0c;IDC1挂了还是有数据同步问题&#xff0c;IDC3日常维护…...

HarmonyOS NEXT——DevEco Studio的使用(还没写完)

一、IDE环境的搭建 Windows环境 运行环境要求 为保证DevEco Studio正常运行&#xff0c;建议电脑配置满足如下要求&#xff1a; 操作系统&#xff1a;Windows10 64位、Windows11 64位 内存&#xff1a;16GB及以上 硬盘&#xff1a;100GB及以上 分辨率&#xff1a;1280*8…...

《Python星球日记》 第46天:决策树与随机森林

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏:《Python星球日记》,限时特价订阅中ing 目录 一、前言二、决策树算法原理1. 决策树简介2. 决策树的分裂准则(1) 信息熵与信息增益(2) 基尼不纯…...

Windows系统Jenkins企业级实战

目标 在Windows操作系统上使用Jenkins完成代码的自动拉取、编译、打包、发布工作。 实施 1.安装Java开发工具包&#xff08;JDK&#xff09; Jenkins是基于Java的应用程序&#xff0c;因此需要先安装JDK。可以从Oracle官网或OpenJDK下载适合的JDK版本。推荐java17版本&#x…...

C# 方法(ref局部变量和ref返回)

>本章内容: 方法的结构 方法体内部的代码执行 局部变量 局部常量 控制流 方法调用 返回值 返回语句和void方法 局部函数 参数 值参数 引用参数 引用类型作为值参数和引用参数 输出参数 参数数组 参数类型总结 方法重载 命名参数 可选参数 栈帧 递归 ref局部变量和ref返回 …...

C# 引用类型作为值参数与引用参数的区别

在编程中&#xff0c;我们常常需要处理引用类型对象&#xff0c;而将引用类型对象作为参数传递给方法时&#xff0c;有值参数和引用参数这两种方式&#xff0c;它们在方法内部操作时会产生不同的结果。下面就来详细分析这两种情况。 引用类型对象作为值参数传递 当我们把引用…...

滑动窗口,438找出字符串中所有字母的异位词

1.题目 2.解析 这道题我们用滑动窗口来实现&#xff0c;加上哈希表和vector容器的使用来实现这道题目&#xff0c;每次滑动之后我们都对其和答案进行比较&#xff0c;如果全部相等我们返回left&#xff0c;不相等继续滑动即可。 本质就是我们把p中相同数量的字母框起来&#…...

「国产嵌入式仿真平台:高精度虚实融合如何终结Proteus时代?」——从教学实验到低空经济,揭秘新一代AI赋能的产业级教学工具

引言&#xff1a;从Proteus到国产平台的范式革新 在高校嵌入式实验教学中&#xff0c;仿真工具的选择直接影响学生的工程能力培养与创新思维发展。长期以来&#xff0c;Proteus作为经典工具占据主导地位&#xff0c;但其设计理念已难以满足现代复杂系统教学与国产化技术需求。…...

《Python星球日记》 第52天:反向传播与优化器

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、引言二、反向传播算法原理简述1. 什么是反向传播&#xff1f;2. 从数学角度…...

Java常用类概述

Java常用类概述 一、字符串三剑客1. String&#xff08;不可变字符串&#xff09;2. StringBuilder&#xff08;可变&#xff0c;线程不安全&#xff09;3. StringBuffer&#xff08;可变&#xff0c;线程安全&#xff09; 二、日期时间类&#xff08;重点掌握新版API&#xff…...

在现代Web应用中集成 PDF.js (pdfjs-dist 5.2 ESM): 通过 jsdelivr 实现动态加载与批注功能的思考

PDF 文档在现代 Web 应用中越来越常见&#xff0c;无论是作为文档预览、报告展示还是在线编辑的载体。Mozilla 的 PDF.js 是一个功能强大的 JavaScript 库&#xff0c;它使得在浏览器端渲染和显示 PDF 文件成为可能&#xff0c;无需依赖原生插件。 本文将深入探讨如何在你的项…...

C++STL——priority_queue

优先队列 前言优先队列仿函数头文件 前言 本篇主要讲解优先队列及其底层实现。 优先队列 优先队列的本质就是个堆&#xff0c;其与queue一样&#xff0c;都是容器适配器&#xff0c;不过优先队列是默认为vector实现的。priority_queue的接口优先队列默认为大根堆。 仿函数 …...

没有 Mac,如何把 iOS App 成功上架?

开发者的 iOS 上架折腾记&#xff1a;没有 Mac&#xff0c;也能搞定&#xff1f; 最近在帮朋友把一个跨平台 Flutter 项目上架到 App Store&#xff0c;结果被 iOS 上架的那套流程卡得头都大了。其实这也不是第一次碰壁了——每次到“申请证书 打包 上传”的时候&#xff0c…...