使用自定义标签库与自定义函数

本文介绍如何在Java Web项目中实现自定义JSP标签和函数,包括编写标签类、函数类及对应的.tld文件配置。通过示例展示了自定义if标签与评分函数的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境

集成环境:MyEclipse Enterprise Workbench CI 2018.8.0
服务器:apache-tomcat-8.5.71
Java EE version: JavaEE 6 - Web 3.0
Java version: 1.8(jdk1.8.0_221)
JSTL Version: 1.2.1
系统:Windows 10 家庭中文版
编码:UTF-8


写在前面

    因为只是一个技巧(?),所以就没有打包源码了,在这篇文章里都写清楚。
    在上一篇的时候使用IDEA,因为没有JSTL的依赖包,为了使用c标签我们是手动添加了依赖包并且定位了一个c.tld的文件的。而这个步骤也正好说明了我们自定义标签的话也是需要一个.tld的文件,其余我们感受不到的,应该就是帮我们封装好了。


自定义标签库

什么是tld

t:tag, l:lib, d:description,所以.tld文件简单来说就是一个标签(库)的描述文件。

tld文件怎么写

    参考看t.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 http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
    
  <description>JSTL 1.1 core library</description>
  <display-name>JSTL core</display-name>
  <tlib-version>1.1</tlib-version>
  <short-name>c</short-name>
  <uri>http://java.sun.com/jsp/jstl/core</uri>

    第一段应该是.tld文件编写的规范。
    第二段这五个单词还是都能理解一下:描述,展示名,tlib的版本,短名字(简称)和uri(统一资源标识)。
    描述应该就是这个标签库的一个简要说明。
    展示名就是这个标签库的全称。
    tlib版本我不太清楚是什么的版本。
    简称就是由展示名缩减成一个方便使用的名称。
    uri我不知道放的是什么的链接,那就照葫芦画瓢就好了。
    结合这个部分,我们大概就明白为什么我们使用的时候,在jsp文件的开头要写这么一段:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>了。


    然后往下翻到熟悉的if。

<tag>
    <description>
	Simple conditional tag, which evalutes its body if the
	supplied condition is true and optionally exposes a Boolean
	scripting variable representing the evaluation of this condition
    </description>
    <name>if</name>
    <tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <description>
The test condition that determines whether or
not the body content should be processed.
        </description>
        <name>test</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
	<type>boolean</type>
    </attribute>
    <attribute>
        <description>
Name of the exported scoped variable for the
resulting value of the test condition. The type
of the scoped variable is Boolean.        
        </description>
        <name>var</name>
        <required>false</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
        <description>
Scope for var.
        </description>
        <name>scope</name>
        <required>false</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
  </tag>

    description描述不用说了。
    name是标签名。
    tag-class是标签对应的类(那就意味着我们要写个类,然后你点进去看源码的话,是可以知道我们要继承哪个接口的。)
    body-content是这个标签的标签体(即两个尖括号的中间那个部分)支持填写什么:empty、JSP。
    然后就是attribute属性里,required是指是不是必须要写上的属性(属性必须有,值可以没有),rtexprvalue=runtime expression value运行时表达式的值,我简单理解就是支不支持动态的值,比如${ userName }这样,type是写这个属性接收的值的类型,如果不是基本类型的话,是要写上包名+类名的全称的。


    此时结合c.tld文件中的if标签和if标签对应的IfTag类来看,就还可以知道,attribute定义的属性在类中都要定义与之对应的变量,并且要有set方法。
    我这里就省去看IfTag类了,我们自己自定义标签对应的类里,一般重写三个方法即可,后面在代码的注释里去描述。

编写一个myif标签

    因为我test里的值是要取自定义函数的值的,就是类似于<cs:myif test="${my:score(95)}"></cs:myif>这个效果,所以代码看起来蛮突兀的,其实是在铺垫hh

创建MyIfTag类

package com.csdn.selma003.web.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
 * 我的自定义if标签
 * @author Selma
 */
public class MyIfTag extends BodyTagSupport {
	/**
	 * 继承BodyTagSupport和继承TagSupport的区别:
	 * <>Body</>
	 * 对于想有Body部分的标签就继承BodyTagSupport
	 * 反之可以直接继承TagSupport
	 */
	private String test;
	public String getTest() {
		return test;
	}
	public void setTest(String test) {
		this.test = test;
	}
	/**
	 * 七个常量(状态):
	 * EVAL_BODY_AGAIN:再次计算身体(c:for就是这个原理
	 * EVAL_BODY_BUFFERED:计算身体缓冲(大概就是允许去读身体部分的内容
	 * EVAL_BODY_INCLUDE:计算包含身体
	 * EVAL_BODY_TAG:计算身体标签(大概就是允许去读身体部分的内容
	 * EVAL_PAGE:计算页面(后续的代码)
	 * SKIP_BODY:跳过身体(大概就是不读身体部分的内容
	 * SKIP_PAGE:跳过页面(后续的代码)(可以粗略理解为return
	 */
	/**
	 * 进入标签头部分就会调用这个方法
	 */
	public int doStartTag() throws JspException {
		System.out.println("进入自定义标签头");
//		return BodyTagSupport.SKIP_BODY;
		return BodyTagSupport.EVAL_BODY_BUFFERED;
//		return BodyTagSupport.EVAL_BODY_TAG;
	}
	/**
	 * 进入Body部分就会调用这个方法
	 */
	public int doAfterBody() throws JspException {
		System.out.println("进入自定义标签体");
		System.out.println("内容是:" + getBodyContent().getString());
		JspWriter out = getBodyContent().getEnclosingWriter();
		try {
			//这里有个弊端,就是你必须body里要写东西,不然进不来这个方法......
			out.print(getTest());
		} catch (IOException e) {
			e.printStackTrace();
		}
		//↓进入body之后再跳过body进入标签尾
		return BodyTagSupport.SKIP_BODY;
	}
	/**
	 * 进入标签尾部分就会调用这个方法
	 */
	public int doEndTag() throws JspException {
		System.out.println("进入自定义标签尾");
		return BodyTagSupport.EVAL_PAGE;
	}
}

创建tld文件

    创建在WEB-INF文件夹下。可以创建File也可以直接选择TLD,选择TLD的话就会自动生成开头的一部分代码。

<?xml version="1.0" encoding="UTF-8"?>

<taglib version="2.1" 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 web-jsptaglibrary_2_1.xsd">
	<tlib-version>1.0</tlib-version>
	<short-name>cs</short-name>
	<uri>https://www.csdn.net/</uri>
	
	<tag>
		<name>myif</name>
		<tag-class>com.csdn.selma003.web.tag.MyIfTag</tag-class>
		<!-- 填empty时,如果body填了值就会报错。 -->
		<!--JSP时,所有JSP支持的这里都能填。 -->
		<body-content>JSP</body-content>
		<attribute>
			<name>test</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
			<type>java.lang.String</type>
		</attribute>
	</tag>
</taglib>

自定义函数

编写一个自定义函数cal

创建MyScoreFunction类

    写在类里的方法一定要是静态方法,其余没什么要求。

package com.csdn.selma003.web.function;

public class MyScoreFunction {
	public static String score(double s) {
		if(s >= 90) {
			return "优秀";
		}else if(s >= 80) {
			return "良好";
		}else if(s >= 70) {
			return "中等";
		}else if(s >= 60){
			return "及格";
		}else {
			return "不及格";
		}
	}
}

创建tld文件

    准确在这里是我继续在我创建的csdn.tld文件里加配置。
    这里直接贴我写的配置,可能不全,但是注释里写了各个的含义。

<function>
		<!-- 方法名 -->
		<name>score</name>
		<!-- 这个函数对应的类 -->
		<function-class>com.csdn.selma003.web.function.MyScoreFunction</function-class>
		<!-- 
			signature:签名
			返回值方法名与参数,参数有多个就加逗号继续写
			注意非基本类型要写清包名+类名
		 -->
		<function-signature>java.lang.String score(double)</function-signature>
	</function>

index.jsp

    因为自定义标签的那个uri没有在全局被注册(我是这么理解的),所以我们在开头的taglib里写当前工程里自定义的tld文件的路径,就不写那个tld文件里定义的uri了。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="cs" uri="WEB-INF/csdn.tld"%>
<% 
	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
	<head>
    	<base href="<%=basePath%>">
    
	    <title>My JSP 'index.jsp' starting page</title>
		<meta http-equiv="pragma" content="no-cache">
		<meta http-equiv="cache-control" content="no-cache">
		<meta http-equiv="expires" content="0">    
		<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
		<meta http-equiv="description" content="This is my page">
		<!--
		<link rel="stylesheet" type="text/css" href="styles.css">
		-->
	</head>
  
	<body>
		This is my JSP page. <br>
		<cs:myif test="${ cs:score(90) }">
		</cs:myif>
	</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈依劼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值