在mvc模式中,我们可以使用别人提供的标签,例如c标签,就是比较常用的,不过,如果别人提供的标签不适用我们的项目开发了,那么我们也可以自己根据不同需求定义标签,也就是自定义标签。
1.标签语言的特点
例如a标签:<a>bbb</a>
<a>就是开始标签
bbb就是标签体
</a>就是结束标签
还有一些不同的,没有标签体或者结束标签,例如<br><hr>
2.自定义标签的步骤

<body>
<c:if test="true">
天气不错
</c:if>
<f:syso>aaaa</f:syso>
</body>这个<c:if>是标签库提供的,<f:syso>就是我自己定义的
1.tld文件怎么写
按住Ctrl键点击c:if就会跳转至标签库的tld文件,把他的格式抠出来
<tag>
<name>syso</name>
<tag-class>com.csf.my_jsp_f</tag-class>
<body-content>JSP</body-content>
</tag><tag-class>填tag助手类的全类名
自己写的时候只需要保留这几个标签,就可以定义出最简单的页面标签
2.tag助手类
package com.csf;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class my_jsp_f extends BodyTagSupport {
@Override
public int doStartTag() throws JspException {
// return super.doStartTag();//默认返回值,如果是这个,在页面上不会显示标签内容
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
return super.doAfterBody();
}
@Override
public int doEndTag() throws JspException {
return super.doEndTag();
}
}
在类继承了BodyTagSupport类之后,需要重写三个方法,分别对应标签运行到了,开始标签,标签体,结束标签。当然,不同的标签,它们的运行方式不同,所以也就有对应的生命生命周期,这个等下讲。
写完这个,标签就算写完了,就可以在jsp页面使用了。
和标签库一样,需要taglib引入。
<%@ taglib prefix="f" uri="/WEB-INF/f.tld" %>之后就可以使用了,也就是
<f:syso>aaaa</f:syso>
这种写法。
3.标签的生命周期

结构图

<%@page import="com.csf.tag.User"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://jsp.veryedu.cn" prefix="c" %>
<!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>Insert title here</title>
</head>
<body>
<c:dome1>tttttttttttt</c:dome1>
<c:dome2>tttttt</c:dome2>
<%-- <z:dome3>t</z:dome3> --%>
<c:if test="true">输出</c:if>
<c:if test="false">不输出</c:if>
<hr>
<c:set var="name" value="zs"></c:set>
<c:out value="${name }"></c:out>
<hr>
<%
List users=new ArrayList<>();
users.add(new User("u001","zs"));
users.add(new User("u002","zs1"));
users.add(new User("u003","zs2"));
request.setAttribute("users", users);
%>
<%-- <c:forEach items="${users }" var="user">
${user.id }:${user.name }<br>
</c:forEach> --%>
<br>
<!-- 模拟新增场景 -->
<c:select textVal="name" items="${users }" textKey="id"></c:select>
<!-- //当前学生的教员id外键是教员表中的主键id -->
<!-- 默认显示 -->
模拟修改场景
<c:select selectedVal="u002" textVal="name" items="${users }" textKey="id"></c:select>
模拟查询场景 查询所有
<c:select headerTextKey="" headerTextVal="===请选择===" textVal="name" items="${users }" textKey="id"></c:select>
美化后
<c:select cssStyle="font-size; 26px;color: red;" textVal="name" items="${users }" textKey="id"></c:select>
</body>
</html> 
标签写法在下文
4.典型标签
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>c 1.1 core library</description>
<display-name>c core</display-name>
<tlib-version>1.1</tlib-version>
<short-name>c</short-name>
<uri>http://jsp.veryedu.cn</uri>
<tag>
<name>dome1</name>
<tag-class>com.csf.tag.Dome1</tag-class>
<body-content>JSP</body-content>
</tag>
<tag>
<name>dome2</name>
<tag-class>com.csf.tag.Dome2</tag-class>
<body-content>JSP</body-content>
</tag>
<tag>
<name>dome3</name>
<tag-class>com.csf.tag.Dome3</tag-class>
<body-content>JSP</body-content>
</tag>
<tag>
<name>if</name>
<tag-class>com.csf.tag.IfTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<!-- 自定义标签的成员变量名称 -->
<name>test</name>
<!-- 该成员变量是否必传 -->
<required>true</required>
<!-- 是否支持EL表达式 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<tag>
<name>set</name>
<tag-class>com.csf.tag.SetTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<!-- 自定义标签的成员变量名称 -->
<name>var</name>
<!-- 该成员变量是否必传 -->
<required>true</required>
<!-- 是否支持EL表达式 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的成员变量名称 -->
<name>value</name>
<!-- 该成员变量是否必传 -->
<required>true</required>
<!-- 是否支持EL表达式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>out</name>
<tag-class>com.csf.tag.OutTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<!-- 自定义标签的成员变量名称 -->
<name>value</name>
<!-- 该成员变量是否必传 -->
<required>true</required>
<!-- 是否支持EL表达式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>forEach</name>
<tag-class>com.csf.tag.ForEachTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<!-- 自定义标签的成员变量名称 -->
<name>var</name>
<!-- 该成员变量是否必传 -->
<required>true</required>
<!-- 是否支持EL表达式 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的成员变量名称 -->
<name>items</name>
<!-- 该成员变量是否必传 -->
<required>true</required>
<!-- 是否支持EL表达式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>select</name>
<tag-class>com.csf.tag.SelectTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>cssStyle</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>className</name>
<required>false</required>
<rtexprvalue>false</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>
<attribute>
<name>headerTextKey</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>headerTextVal</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>selectedVal</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
(所有标签配置,全在)
1.set/out

set标签
package com.csf.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* 案例3和案例4
* 开发一个数据标签
* 1.第一条以及路线
* 只不过set out标签本身没有标签体,需要在页面上输出内容,需要借助一个类JspWriter
* 2.在没有标签体的情况下是通过JspWriter来输出内容
* @author T440s
*
*/
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 {
// TODO Auto-generated method stub
//将value值保存到var对应的变量中
//jsp传递name给var 假如传递zs给value那么需要把zs赋值给name
//四大作用域:pageContext request session application
pageContext.setAttribute(var, value);
return super.doStartTag();
}
}
out标签
package com.csf.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
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 {
// TODO Auto-generated method stub
JspWriter out = pageContext.getOut();
try {
out.print(value);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return super.doStartTag();
}
}
2.foreach

package com.csf.tag;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* 案例五 foreach
* 熟悉第二第三路线的流程
* 2.doStartTag---->EVAL_BODY_INCLUDE---->doAfterBody----->EVAL_PAGE----->doEndtag
* 3.doStartTag---->EVAL_BODY_INCLUDE (---->doAfterBody----->EVAL_BODY_AGAIN)可能会执行多次 ----->doEndtag
* 将取集合元素的过程看成指针下移取值的过程,如果指针还会指向下一个那么返回值为EVAL_BODY_AGAIN,如果指针没有下一个元素那么返回值为EVAL_PAGE
* 指针是迭代器的东西,所以我们要将迭代器保存并提供到doAfterBody中使用
*
* 实现思路
* 1:最少接受两个参数 var/items
* 2:一定要有标签体的,那么对应需要重写doAfterBody方法
* 3:必定有判断条件决定doAfterBody的返回值是EVAL_PAGE还是EVAL_BODY_AGAIN
* @author T440s
*
*/
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 {
// TODO Auto-generated method stub
//在此处保存迭代器,供doAfterBody中使用
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将集合中的元素值拿到
//it.next()让指针下移
pageContext.setAttribute(var, it.next());
//保存指针下移的状态
pageContext.setAttribute("it", it);
//还有下一个就继续循环
return EVAL_BODY_AGAIN;
}else {
//没有就结束循环
return EVAL_PAGE;
}
}
}
3.if 控制标签
package com.csf.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* 针对第一条第二条路线做一个实际应用
* 作用:开发一个控制标签
*
* c:if test=true 是要输出标签体的 要输出第二条路线
* c:if test=true 是不要输出标签体的 要输出第一条路线
*
* 1.doStartTag---->skipBody---->doEndtag
* 2.doStartTag---->EVAL_BODY_INCLUDE---->doAfterBody----->EVAL_PAGE----->doEndtag
* @author T440s
*
*/
public class IfTag extends BodyTagSupport{
private boolean test;
public boolean isTest() {
return test;
}
public void setTest(boolean test) {
this.test = test;
}
@Override
public int doStartTag() throws JspException {
// TODO Auto-generated method stub
//需要一个变量来控制返回值,从而控制走第一个路线还是第二个路线
return test ? EVAL_BODY_INCLUDE :SKIP_BODY;
}
}
4.select
比较难,因为要根据自己的要求实现

package com.csf.tag;
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;
import org.apache.commons.beanutils.PropertyUtils;
/**
* 目的:将所学的自定义标签的知识点用于实际项目开发
* 不管是if/set/out/foreach标签那是别人已经具备的功能,直接用别人的就行
* 学习自定义标签理解其底层结构,就是弥补现成C标签没有的功能
*
* 调堂的最终体现形式
* 以前
* 查询下拉框
* <select>
* <option value=''>-==请选择==m</option>
* <option value= '1'>晓哥</option>
* <option checked value='2'>胡哥</option>
* <option value='3'>娜姐</option>
* </ select>
* 修改回显,在这里面有大量的c:foreach. c:if到断
* 不足之处:代码过大。以及凡是涉及到下拉框以及复选框。粗类似的代码过多
* 目前:
* <z:selectc/z: select>
* 目的:通过上述标签能够实现上述代码相同的功能
* 分析属性:
* 1.数据源属懂items,用于遍历展示的 users->List<User>->id=option>value;name=option>text
* 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 SelectTag 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;//美化
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;
}
@Override
public int doStartTag() throws JspException {
// TODO Auto-generated method stub
JspWriter out = pageContext.getOut();
try {
out.print(toHTML());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return super.doStartTag();
}
private String toHTML() throws Exception{
// TODO Auto-generated method stub
StringBuffer sb=new StringBuffer();
sb.append("<select id='"+id+"' class='"+className+"' style='"+cssStyle+"'>");
//拼接默认显示标签
if(headerTextVal!=null&&!"".equals(headerTextVal)) {
sb.append("<option value='"+headerTextKey+"'>"+headerTextVal+"</option>");
}
//循环显示数据源
if(items.size()>0) {
for (Object obj : items) {
//obj对应的user
//希望拿到当前user的id放入option中的value,name放入option中的text
//<option value= '1'>晓哥</option>
//通过反射获取id对应的属性对象
Field textKeyField = obj.getClass().getDeclaredField(textKey);
textKeyField.setAccessible(true);
//获取id对应的值
//textKeyField.get(obj);
//此代码等于上面三行代码
// PropertyUtils.getProperty(obj, textVal);
String value = textKeyField.get(obj).toString();
//修改页面下拉框回显选中
//当下拉框的value值等于selectedVal,那么就要默认下拉框选中
if(value.equals(selectedVal)) {
sb.append("<option selected value= '"+value+"'>"+PropertyUtils.getProperty(obj, textVal)+"</option>");
}else {
sb.append("<option value= '"+value+"'>"+PropertyUtils.getProperty(obj, textVal)+"</option>");
}
}
}
sb.append("</select>");
return sb.toString();
}
// <select>
// <option value=''>-==请选择==m</option>
// <option value= '1'>晓哥</option>
// <option checked value='2'>胡哥</option>
// <option value='3'>娜姐</option>
// </ select>
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;
}
}
ok自定义标签的目的是为了根据不同的需求开发更简单适用的标签,典型中的select标签例子就是。
版权声明:本文为weixin_55966394原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。