自定义jsp标签

1.自定义jsp标签概念

在jsp开发时,当jsp内置标签以及JSTL标签库都满足不了需求时,可以根据自己的需求来自定义标签。其实在jsp页面使用标签就等同于调用某个对象的某个方法。

2.标签语音特点及类型

  • <开始标签  属性="属性值">标签体</结束标签>
  • ui标签:input  out ....
  • 空标签:br  hr ......
  • 控制标签:if/foreach...
  • 数据标签:set/out...

3.标签生命周期

路线1:doStarTag-->SKIP_BODY-->doEndTag

路线2:doStartTag-->EVAL_BODY_INCLUDE-->doAfterBody-->EVAL PAGE-->doEndTag

线路3:doStartTag-->EVAL_BODY_INCLUDE-->doAfterBody-->EVAL_BODY_AGAIN-->doAfterBody...(循环)-->满足条件后doEndTag


4.自定义标签步骤

  • 每个标签,必须创建一个标签助手类(继承BodyTagSupport),标签属性必须和助手类的属性对应、且要提供对应get/set方法
  • 创建标签库描述文件(tld),添加自定义标签的配置,而且tld文件必须保存到WEB-INF目录或其子目录
  • 在JSP通过taglib指令导入标签库,并通过指定后缀访问自定义标签

4.1 论证自定义标签生命周期

tld文件

引入方式:<%@taglib prefix="名" uri="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>JSTL 1.1 core library</description>
  <display-name>JSTL core</display-name>
  <tlib-version>1.1</tlib-version>
  <short-name>c</short-name>
 <!--  tld文件路径 -->
  <uri>http://zking.sum</uri>
  <tag>
  <!-- 标签名 -->
    <name>Dome1</name>
   <!--  助手类全路径名 -->
    <tag-class>com.wyy.Dome1</tag-class>
    <body-content>JSP</body-content>
    <attribute>
    	<!-- 标签属性名 -->
        <name>var</name>
       <!--  是否是必写属性 -->
        <required>false</required>
       <!--  是否可以使用EL表达式 -->
        <rtexprvalue>false</rtexprvalue>
    </attribute>
  </tag>
   
   <tag>
  
    <name>Dome2</name>
    <tag-class>com.wyy.Dome2</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>var</name>
        <required>false</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
  </tag>
  
  <tag>

    <name>Dome3</name>
    <tag-class>com.wyy.Dome3</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>var</name>
        <required>false</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
  </tag>
 
 
 <tag>

    <name>set</name>
    <tag-class>com.wyy.Dome4</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>
  
  <tag>

    <name>out</name>
    <tag-class>com.wyy.Dome5</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>var</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>


	<tag>

    <name>if</name>
    <tag-class>com.wyy.Dome6</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>text</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>
  
  <tag>
  <name>forEach</name>
    <tag-class>com.wyy.forEach</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>
</taglib>

助手类
        路线1验证

package com.wyy;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
 * 三种路线
 * 1.doStartag........SKIPBODY......doEndtag
 * @author T440s
 *在jsp页面使用自定义标签,如果打印以下输出则正确
 *
 */
public class Dome1 extends BodyTagSupport {

	@Override
	public int doStartTag() throws JspException {
		// TODO Auto-generated method stub
		System.out.println("Demo1_doStartTag_进来了");
		return SKIP_BODY;
	}
	
	
	
	@Override
	public int doEndTag() throws JspException {
		
		// TODO Auto-generated method stub
		System.out.println("Demo1_doEndTag_进来了");
		return super.doEndTag();
	}
}

        路线2验证

package com.wyy;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
 * 2.doStartag........EVAL_BOOY_INCLUDE.....doAfterbody........EVAL_PAGE....doEndtag
 * @author T440s
 *
 */
public class Dome2 extends BodyTagSupport {

	@Override
	public int doStartTag() throws JspException {
		// TODO Auto-generated method stub
		System.out.println("Demo2_doStartTag_进来了");
		return EVAL_BODY_INCLUDE;
	}
	
	@Override
	public int doAfterBody() throws JspException {
		// TODO Auto-generated method stub
		System.out.println("Demo2_doAfterBody_进来了");
		return EVAL_PAGE;
	}
	
	
	@Override
	public int doEndTag() throws JspException {
		// TODO Auto-generated method stub
		System.out.println("Demo2_doEndTag_进来了");
		return super.doEndTag();
	}
}

         路线3验证 

package com.wyy;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
 *3.doStartag........EVAL_BOOY_INCLUDE.....doAfterbody........EVAL_BOYY_AGAIN.....doAfterbody........EVAL_BOYY_AGAINdoAfterbody........EVAL_BOYY_AGAIN.....doEndtag
 *
 * @author T440s
 *
 */
public class Dome3 extends BodyTagSupport {

	@Override
	public int doStartTag() throws JspException {
		// TODO Auto-generated method stub
		System.out.println("Demo3_doStartTag_进来了");
		return EVAL_BODY_INCLUDE;
	}
	
	@Override
	public int doAfterBody() throws JspException {
		// TODO Auto-generated method stub
		System.out.println("Demo3_doAfterBody_进来了");
		return EVAL_BODY_AGAIN;
	}
	
	
	@Override
	public int doEndTag() throws JspException {
		// TODO Auto-generated method stub
		System.out.println("Demo3_doEndTag_进来了");
		return super.doEndTag();
	}
}

5.案列实践

if标签

助手类:

package com.wyy;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
 * 开发if标签
 * <z:if test="${empty user}">标签体</z:if>
 *     
 * 成员变量:test   必传(使用if标签test属性必传值),支持EL表达式
 * 路线分析:
 * test=true  执行标签体 
 * test=false 不执行标签体
 * @author T440s
 *
 */
public class Dome6 extends BodyTagSupport {
	private boolean text;
	
	public boolean isText() {
		return text;
	}

	public void setText(boolean text) {
		this.text = text;
	}

	@Override
	public int doStartTag() throws JspException {
		// TODO Auto-generated method stub
		//需要一个变量控制返回值,达到标签路线控制
		return text?EVAL_BODY_INCLUDE:SKIP_BODY;
	}
	
	
	
}

在tld文件中进行配置(每个标签都有对应的助手类以及tld配置)

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

set/out 标签

助手类

package com.wyy;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
 * 开发数据标签
 * 第一条路线
 * set标签 没有标签体 需要借助JSPWriter
 * @author T440s
 *
 */
public class Dome4 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 {
		// TODO Auto-generated method stub
        //通过pageContext保存
		pageContext.setAttribute(var, value);
		return SKIP_BODY;
	}
	
	
	
	
	@Override
	public int doEndTag() throws JspException {
		// TODO Auto-generated method stub
		return super.doEndTag();
	}
}

out

package com.wyy;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
 *  
 * 自定义out标签:数据标签
 * 成员变量: value 存放标签对应的值  必传,支持EL表达式	  
 * 注意:无标签体,要在页面上输出内容,需要借助一个类JSPWrite。
 * 路线分析:
 * 执行doStartTag,将内容输出到网页上
 * @author T440s
 *
 */
public class Dome5 extends BodyTagSupport{

	private Object var  ;

	public Object getVar() {
		return var;
	}

	public void setVar(Object var) {
		this.var = var;
	}
	
	@Override
	public int doStartTag() throws JspException {
		// TODO Auto-generated method stub
		JspWriter out = pageContext.getOut();
			try {
				out.print(var);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		return SKIP_BODY;
	}
	
	@Override
	public int doEndTag() throws JspException {
		// TODO Auto-generated method stub
		return super.doEndTag();
	}
}

tld文件配置

<tag>
    <name>set</name>
    <tag-class>com.wyy.Dome4</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>
  
  <tag>
    <name>out</name>
    <tag-class>com.wyy.Dome5</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>var</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>

foreach标签

助手类

package com.wyy;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
 * foreach开发
 * 第二、第三路径
 * 1.最少接受两个参数
 * 2.一定有标签体
 * 3.必定有条件觉得doafterbody返回值是EVAL_PAGE还是 EVAL_BOYY_AGAIN
 * @author T440s
 *
 */
public class forEach  extends BodyTagSupport{
	private String var;
	private List<Object> items=new ArrayList<>();
	
	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 {
			// TODO Auto-generated method stub
				Iterator<Object> it = items.iterator();
				pageContext.setAttribute("it", it);
				return EVAL_BODY_INCLUDE;
		}
	@Override
	public int doAfterBody() throws JspException {
		// TODO Auto-generated method stub
			Iterator<Object> it = (Iterator<Object>) pageContext.getAttribute("it");
			if(it.hasNext()) {//判断集合是否有数据
				//在页面上,需要通过var将集合数据拿出
				pageContext.setAttribute(var, it.next());
				//保存下移状态
				pageContext.setAttribute("it", it);
				//继续循环
				return EVAL_BODY_AGAIN;
			}else {
				//结束循环
				return EVAL_PAGE;
			}
	}
	
	@Override
	public int doEndTag() throws JspException {
		// TODO Auto-generated method stub
		return super.doEndTag();
	}
	
public class student {
		private String name;
		private int age;
		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;
		}
		@Override
		public String toString() {
			return "student [name=" + name + ", age=" + age + "]";
		}
		
		public student() {
			// TODO Auto-generated constructor stub
		}
		public student(String name, int age) {
			super();
			this.name = name;
			this.age = age;
		}
		
	}
}

tld文件配置

 <tag>
  <name>forEach</name>
    <tag-class>com.wyy.forEach</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>

select标签

在项目开发过程中经常会用到select标签,当你的select标签数量达到十个甚至更多时,发现代码量太多,所有我们现在来开发一个自己的select标签

助手类

package com.wyy;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;

/**
 * 查询下拉框
 * 修改回显,在这里有大量的c:foreach/c:if判断
 * 不足之处,代码量过大,以及凡是涉及到下拉框以及复选框,相类似代码量过多
 * <zking:select></zking:select>通过该标签实现上述代码的相同功能
 * 分析属性:
 * 1、需要遍历展示,需要数据源属性items,用于遍历展示 
 * id=option>value;name=option>test
 * 2、对象Key属性textKey,用于对应option>value
 * 3、对象value属性textVal,用于对应option>text
 * 4、对象默认Key属性headerTextKey,用于对应默认option>value
 * 5、对象默认value属性headerTextVal,用于对应默认option>text
 * 6、对象回显属性selectedVal,用于判断数据回显选择 
 * @author T440s
 *
 */
public class select extends BodyTagSupport {

	private List<Object> items=new ArrayList<Object>();//用于遍历展示
	private String textKey;//用于对应option>value
	private String textVal;//用于对应option>text
	private String headerTextKey;//用于对应默认option>value
	private String headerTextVal;//用于对应默认option>text
	private String selectedVal;//用于判断数据回显选择
	
	//定义属性美化。拓展/操作标签
	private String cssStyle;//美化
	private String id;//绑定事件...操作标签
	private String className;//美化

	
	@Override
	public int doStartTag() throws JspException {
		JspWriter out = pageContext.getOut();
		try {
			out.print(html());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return super.doStartTag();
	}
	//<select>
		//<option value="">--请选择--</option>
		//<option value="1">hh</option>
	    // <option value="2">jj</option>
		// </select>
	private String html() throws Exception, Exception {
		//获取可变字符串
		StringBuffer sb=new StringBuffer();
		sb.append("<select>");
		//select默认显示
		if(headerTextVal!=null&&!"".equals(headerTextVal)) {
			sb.append("<option vlaue='"+headerTextKey+"'>"+headerTextVal+"</option>");
		}
		//循环显示数据
		if(items.size()>0) {
			for (Object obj : items) {
				//obj就是页面传输过来集合的类型或对象
				//通过反射获取类对象属性 getDeclaredField()获取所有(公共的、私有的)类对象属性
				Field fidname = obj.getClass().getDeclaredField(textKey);
				//打开权限 不了解反射的可以看我主页反射的文章
				fidname.setAccessible(true);
				//获取textKey 对应的属性值
				String value = fidname.get(obj).toString();
				Field fidtext = obj.getClass().getDeclaredField(textVal);
				fidtext.setAccessible(true);
				String text = fidtext.get(obj).toString();
				//追加至<optoin>中 判断默认选中
				if(text.equals(selectedVal)) {
				sb.append("<option selected vlaue='"+value+"'>"+text+"</option>");
				}else {
					sb.append("<option vlaue='"+value+"'>"+text+"</option>");
				}
			}
		}
		sb.append("<option></option>");
		sb.append("</select>");
		return sb.toString();
	}

	public List<Object> getItems() {
		return items;
	}
	public void setItems(List<Object> items) {
		this.items = items;
	}
	public String getTextKey() {
		return textKey;
	}
	public void setTextKey(String textKey) {
		this.textKey = textKey;
	}
	public String getTextVal() {
		return textVal;
	}
	public void setTextVal(String textVal) {
		this.textVal = textVal;
	}
	public String getHeaderTextKey() {
		return headerTextKey;
	}
	public void setHeaderTextKey(String headerTextKey) {
		this.headerTextKey = headerTextKey;
	}
	public String getHeaderTextVal() {
		return headerTextVal;
	}
	public void setHeaderTextVal(String headerTextVal) {
		this.headerTextVal = headerTextVal;
	}
	public String getSelectedVal() {
		return selectedVal;
	}
	public void setSelectedVal(String selectedVal) {
		this.selectedVal = selectedVal;
	}
	public String getCssStyle() {
		return cssStyle;
	}
	public void setCssStyle(String cssStyle) {
		this.cssStyle = cssStyle;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}

	
	
}

tld文件配置

<tag>
  <name>select</name>
  <tag-class>com.wyy.select</tag-class>
  <body-content>JSP</body-content>
  <attribute>
  <!--  自定义标签的成员变量名称-->
  <name>id</name>
  <!-- 该成员变量是否必传-->
  <required>false</required>
  <!--  是否支持EL表达式-->
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  <attribute>
  <!--  自定义标签的成员变量名称-->
  <name>cssStyle</name>
  <!-- 该成员变量是否必传-->
  <required>false</required>
  <!--  是否支持EL表达式-->
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  <attribute>
  <!--  自定义标签的成员变量名称-->
  <name>className</name>
  <!-- 该成员变量是否必传-->
  <required>false</required>
  <!--  是否支持EL表达式-->
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  
  <attribute>
  <!--  自定义标签的成员变量名称-->
  <name>items</name>
  <!-- 该成员变量是否必传-->
  <required>true</required>
  <!--  是否支持EL表达式-->
  <rtexprvalue>true</rtexprvalue>
  </attribute>
  <attribute>
  <!--  自定义标签的成员变量名称-->
  <name>textKey</name>
  <!-- 该成员变量是否必传-->
  <required>true</required>
  <!--  是否支持EL表达式-->
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  <attribute>
  <!--  自定义标签的成员变量名称-->
  <name>textVal</name>
  <!-- 该成员变量是否必传-->
  <required>true</required>
  <!--  是否支持EL表达式-->
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  <attribute>
  <!--  自定义标签的成员变量名称-->
  <name>headerTextKey</name>
  <!-- 该成员变量是否必传-->
  <required>false</required>
  <!--  是否支持EL表达式-->
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  <attribute>
  <!--  自定义标签的成员变量名称-->
  <name>headerTextVal</name>
  <!-- 该成员变量是否必传-->
  <required>false</required>
  <!--  是否支持EL表达式-->
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  <attribute>
  <!--  自定义标签的成员变量名称-->
  <name>selectedVal</name>
  <!-- 该成员变量是否必传-->
  <required>false</required>
  <!--  是否支持EL表达式-->
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  </tag>

测试 index.jsp

<%@page import="com.wyy.student"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@taglib prefix="c" uri="http://zking.sum" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<c:set var="name" value="张三"></c:set>
<hr>
<c:out var="${name}"></c:out>
<hr>
<c:if text="true">输出</c:if>
<c:if text="false">不输出</c:if>
<hr>
<%
List<student> list=new ArrayList<>();
list.add(new student("张三",12));
list.add(new student("ww",16));
list.add(new student("wyf",72));
list.add(new student("kjh",32));
request.setAttribute("list", list);
%>
<c:forEach items="${list }" var="f">
${f.name}   ${f.age}   
</c:forEach>
<hr>
<c:select textKey="age" textVal="name" items="${list}" selectedVal="ww"></c:select>
</body>

</html>

运行结果

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值