本节知识总结
目录
前言
首先介绍一下我们学习本节的目标:
①明确c标签怎么来的;
②如何开发一个自己的标签
③根据实际业务场景开发对应标签
下面我们就来完成这些目标<( ̄︶ ̄)↗[GO!]🧐
一、jsp标签语言的特点
1.组成
①开始标签
②标签体
③结束标签
组成形式:<开始标签 属性="属性值">标签体</结束标签>
2.分类
可分为以下四种:
①空标签: br、hr...
②ui标签:input、table...
③控制标签:if、foreach...
④数据标签:set标签、out标签...
代码如下(示例):
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" 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>
<z:if test=""></z:if>
<z:forEach items=""></z:forEach>
<!-- 标签的构造:开始标签,标签体,结束标签 -->
<a>标签的特点</a>
<!-- 空标签 -->
<br>
<hr>
<!-- UI标签 -->
<table>
<tr></tr>
</table>
<input>
<!-- 控制标签 -->
<c:if test="true"></c:if>
<c:if test="false"></c:if>
<!-- 数据标签 -->
<c:set var="name" value="zs"></c:set>
<c:out value="${name }"></c:out>
</body>
</html>
二、jsp自定义标签步骤
1.tag助手继承BodyTagSupport
重写doStartTag()
重写doAfterBodyTag
重写doEndTag
代码如下(示例):
package com.xhy.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;public class Demo1 extends BodyTagSupport{
@Override
public int doStartTag() throws JspException {
System.out.println("进来了");
// TODO Auto-generated method stub// return super.doStartTag();不显示
return EVAL_BODY_INCLUDE;显示
}
@Override
public int doAfterBody() throws JspException {
// TODO Auto-generated method stub
return super.doAfterBody();
}
@Override
public int doEndTag() throws JspException {
// TODO Auto-generated method stub
return super.doEndTag();
}
}
2.新建tld标签库描述文件
在你的web应用目录下,找到WEB-INF文件夹,在里面新建一个tld类型的文件(注:一定要是tld文件)
这里可以参考jstl里的tld文件进行编写!!
导入jstl包和standard包:https://mvnrepository.com/ 去里面搜索jra包吧学会自己下载哦🐷
代码如下(示例):
<?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>zking 1.1 core library</description>
<display-name>zking core</display-name>
<tlib-version>1.1</tlib-version><!-- 代表标签库的版本号 -->
<short-name>zking</short-name><!-- 你的标签库的简称 -->
<uri>http://jsp.veryedu.cn</uri><!-- 你标签库的引用uri -->
<tag>
<name>demo1</name><!-- 你定义的标签的名称 -->
<tag-class>com.zking.tag.Demo1</tag-class><!-- 对应的标签处理程序:包名+类名,全包名 -->
<body-content>JSP</body-content><!-- 标签体内容的格式 -->
</tag>
</taglib>
3.使用自定义标签
你要在使用你定义的标签的jsp页面导入你的标签库就像导入类包一样(也称为:调用自己所写的标签)使用标签
代码如下(示例):
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://jsp.veryedu.cn" prefix="z"%>
<!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>
<z:demo1>随便来点</z:demo1>
</body>
</html>
三、jsp标签生命周期
首先介绍他的开发场景:
①doStartTag——SKIP_BODY——doEndTag
②doStartTag——EVAL_BODY_INCLUDE——doAfterBody——EVAL_PAGE——doEndTag
③doStartTag——EVAL_BODY_INCLUDE——doAfterBody——EVAL_BODY_AGAIN(N次)——doEndTag
然后是返回值:
SKIP_BODY:跳过主体
EVAL_BODY_INCLUDE:计算标签主体内容并输出
EVAL_BODY_AGAIN:再计算主体一次
EVAL_PAGE:计算页面的后续部分
SKIP_PAGE:跳过页面的后续部分
测试:
代码如下(示例):
package com.xhy.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* 三种路线
*①doStartTag——SKIP_BODY——doEndTag
* ②doStartTag——EVAL_BODY_INCLUDE——doAfterBody——EVAL_PAGE——doEndTag
* ③doStartTag——EVAL_BODY_INCLUDE——doAfterBody——EVAL_BODY_AGAIN(N次)——doEndTag
*/
public class Test01 extends BodyTagSupport{
//第一个例子:根据代码论证这三条路线的执行顺序(涉及三个类:Test01.java,Test02.java,Test03.java)
@Override
public int doStartTag() throws JspException {
System.out.println("Test01_doStartTag");
//return super.doStartTag();
return SKIP_BODY;
}
@Override
public int doEndTag() throws JspException {
System.out.println("Test01_doEndTag");
// TODO Auto-generated method stub
return super.doEndTag();
}
}
public class Test02 extends BodyTagSupport{
//第一个例子:根据代码论证这三条路线的执行顺序(涉及三个类:Test01.java,Test02.java,Test03.java)
@Override
public int doStartTag() throws JspException {
System.out.println("Test02_doStartTag");
//return super.doStartTag();
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
System.out.println("Test02_doAfterBody");
// TODO Auto-generated method stub
return EVAL_PAGE;
}
@Override
public int doEndTag() throws JspException {
System.out.println("Test02_doEndTag");
// TODO Auto-generated method stub
return super.doEndTag();
}
}
public class Test03 extends BodyTagSupport{
//第一个例子:根据代码论证这三条路线的执行顺序(涉及三个类:Test01.java,Test02.java,Test03.java)
@Override
public int doStartTag() throws JspException {
System.out.println("Test03_doStartTag");
//return super.doStartTag();
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
System.out.println("Test03_doAfterBody");
// TODO Auto-generated method stub
return EVAL_BODY_AGAIN;
}
@Override
public int doEndTag() throws JspException {
System.out.println("Test03_doEndTag");
// TODO Auto-generated method stub
return super.doEndTag();
}
}
四、建立常见的jsp标签
1.z:if标签:
1.tag助手继承BodyTagSupport
return this.test ?EVAL_BODY_INCLUDE:SKIP_BODY;
package com.xhy.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;public class If extends BodyTagSupport{
private boolean test;public boolean isTest() {
return test;
}public void setTest(boolean test) {
this.test = test;
}
@Override
public int doStartTag() throws JspException {
return this.test ? EVAL_BODY_INCLUDE:SKIP_BODY;
}
@Override
public int doEndTag() throws JspException {
// TODO Auto-generated method stub
return super.doEndTag();
}
}
2.创建tld文件,开发if标签
<tag>
<name>if</name>
<tag-class>com.xhy.tag.If</tag-class>
<body-content>JSP</body-content>
<attribute>
<!-- 自定义标签的成员变量名称-->
<name>test</name>
<!-- 该成员变量是否必传-->
<required>true</required>
<!-- 是否支持EL表达式-->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
3.使用
<z:if test="true">输出</z:if>
<zking:if test="false">不输出</zking:if>
2.z:set与z:out标签:
pageContext:setAttribute(var,value)
JspWrite out=pageContext.getOut();
out.print(value);
①set
1.tag助手继承BodyTagSupport
package com.xhy.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;public class Set 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 String toString() {
return "SetTag [var=" + var + ", value=" + value + "]";
}
public Set() {
// TODO Auto-generated constructor stub
}@Override
public int doStartTag() throws JspException {
pageContext.setAttribute(var, value);
return super.doStartTag();
}
}
2. 创建tld文件,开发set标签
<tag>
<name>set</name>
<tag-class>com.xhy.tag.Set</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>
3.使用:
<z:set var="name" value="xhy"></z:set>
②out
1.tag助手继承BodyTagSupport
package com.xhy.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;public class Out extends BodyTagSupport{
private Object value;
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
@Override
public int doStartTag() throws JspException {
JspWriter out = pageContext.getOut();
try {
out.print(value);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.doStartTag();
}@Override
public int doEndTag() throws JspException {
// TODO Auto-generated method stub
return super.doEndTag();
}
}
2. 创建tld文件,开发Out标签
<tag>
<name>out</name>
<tag-class>com.xhy.tag.Out</tag-class>
<body-content>JSP</body-content>
<attribute>
<!-- 自定义标签的成员变量名称-->
<name>value</name>
<!-- 该成员变量是否必传-->
<required>true</required>
<!-- 是否支持EL表达式-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
3.使用
<z:out value="${name} "></z:out>
3.z:foreach标签:
分析:
1.属性值有:var items
2.start:Iterator<Object> it=items.iterator();
pageContext.setAttribute("it", it);3.after:Iterator<Object> it = (Iterator<Object>) pageContext.getAttribute("it");
if(it.hasNext()) {
pageContext.setAttribute(var, it.next());
pageContext.setAttribute("it", it);
return EVAL_BODY_AGAIN;
}else {
return EVAL_PAGE;
}
1.tag助手继承BodyTagSupport
package com.xhy.tag;
import java.util.Iterator;
import java.util.List;import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;public class foreach extends BodyTagSupport{
private String var;
private List<Object> items;
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 {
Iterator<Object> it=items.iterator();
pageContext.setAttribute("it", it);
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
Iterator<Object> it = (Iterator<Object>) pageContext.getAttribute("it");
if(it.hasNext()) {
pageContext.setAttribute(var, it.next());
pageContext.setAttribute("it", it);
return EVAL_BODY_AGAIN;
}else {
return EVAL_PAGE;
}
}
}
2. 创建tld文件,开发foreach标签
<tag>
<!-- 标签名 -->
<name>foreach</name>
<!-- 标签工具类 -->
<tag-class>com.xhy.tag.foreach</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>jsp</body-content>
<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
<attribute>
<!-- 自定义标签的属性名称 -->
<name>var</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的属性名称 -->
<name>items</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
3.测试
<%
List user=new ArrayList<>();
user.add(new User(1,"a"));
user.add(new User(2,"b"));
user.add(new User(3,"c"));
request.setAttribute("user", user);
%><z:foreach items="${ user }" var="i">
${ i.id }:${ i.name }
</z:foreach>
4.z:select标签:
将所学的自定义标签的知识点,用于实际项目开发
不管if/set/out/foreach...,那都是C标签已经具备的功能,直接用别人的就好
学习自定义标签理解其底层的目的,就是弥补现成C标签没有的功能
查询下拉框
修改回显,在这里有大量的c:foreach/c:if判断
不足之处,代码量过大,以及凡是涉及到下拉框以及复选框,相类似代码量过多
目前:
<z:select></z:select>通过该标签实现上述代码的相同功能
分析属性:
1、需要遍历展示,需要数据源属性items,用于遍历展示 users->List<User>->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,用于判断数据回显选择
1.tag助手继承BodyTagSupport
package com.xhy.tag;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
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;
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;//美化
//没有标签体,有需要往页面输出内容 JspWriter
@Override
public int doStartTag() throws JspException {
JspWriter out = pageContext.getOut();
try {
out.print(doHTML());
} catch (Exception e) {
e.printStackTrace();
}
return super.doStartTag();
}
//<select>
//<option value="">--请选择--</option>
//<option value="1">晓哥</option>
// <option value="2">胡哥</option>
// </select>
private String doHTML() throws Exception, Exception {
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
//通过反射获取到id对应的属性对象
Field textKeyField = obj.getClass().getDeclaredField(textKey);
textKeyField.setAccessible(true);//打开权限
//textKeyField.get(obj);//获取id对应的值
//以下方法等价于上面三行代码
//PropertyUtils.getProperty(obj, textVal);
String value = textKeyField.get(obj).toString();
//System.out.println(value+"--------");
sb.append("<option value='"+value+"'>"+PropertyUtils.getProperty(obj, textVal)+"</option>");
//修改页面下拉框回显选中
//当下拉框的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();
}
// get/set方法
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;
}
}
2. 创建tld文件,开发select标签
<tag>
<name>select</name>
<tag-class>com.xhy.tag.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>
3.测试
<%
List user=new ArrayList<>();
user.add(new User(1,"a"));
user.add(new User(2,"b"));
user.add(new User(3,"c"));
request.setAttribute("user", user);
%><!-- 模拟的是新增场景 -->
<zking:select cssStyle="color:blue" textVal="name" items="${users}" textKey="id"></zking:select>
<!-- 模拟修改场景 -->
<zking:select selectedVal="u" textVal="name" items="${users}" textKey="id"></zking:select>
<!-- 模拟查询 所有 -->
<zking:select headerTextKey="" headerTextVal="--请选择--" textVal="name" items="${users}" textKey="id"></zking:select>
总结
自己开发jsp标签使代码更灵活了,熟悉了tld文件
今天的内容就到这了!我们下期再见!希望以上内容能对你有帮助,当然有什么错误之处还望大佬指正!谢谢😘