目录
思维导图
一、标签语言的特点
二、自定义标签的开发及步骤
三、标签的生命周期
四、if标签?
五、set与out标签
六、ForEach标签和Select标签
思维导图
一、标签语言的特点
所用jar包
?
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"%>
<%@taglib uri="http://jsp.veryedu.cn" prefix="ysq" %>
<!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>
<!-- 标签的构成 开始标签 标签体 结束标签 -->
<a>我是个a标签呀</a>
<!-- 空标签 没有内容 -->
<br>
<hr>
<!-- UI标签 -->
<table>
<tr></tr>
</table>
<!-- 控制标签 -->
<c:if test="true">输出</c:if>
<c:if test="false"> 不输出</c:if>
<ysq:if test=""></ysq:if>
<!-- 数据标签 -->
<c:set var="name" value="ysq"></c:set>
<c:out value="${name }"></c:out>
</body>
</html>
二、自定义标签的开发及步骤
1、助手类(继承BodyTagSupport)
2、标签库描述文件(tld);(tld文件必须保存到WEB-INF目录或其子目录)
3、JSP通过taglib指令导入标签库
标签库描述文件
<?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>ysq 1.1 core library</description>
<display-name>ysq core</display-name>
<tlib-version>1.1</tlib-version>
<short-name>ysq</short-name>
<uri>http://jsp.veryedu.cn</uri>
<tag>
<name>Demo1</name>
<tag-class>com.ysq.tag.Demo1</tag-class>
<body-content>JSP</body-content>
</tag>
4、JSP通过taglib指令导入标签库
<%@taglib uri="http://jsp.veryedu.cn" prefix="ysq" %>
三、标签的生命周期
1、标签的开发场景
①、doStartTag——SKIP_BODY——doEndTag
②、doStartTag——EVAL_BODY_INCLUDE——doAfterBody——EVAL_PAGE——doEndTag
③、doStartTag——EVAL_BODY_INCLUDE——doAfterBody——EVAL_BODY_AGAIN(N次)——doEndTag
2、返回值
①、SKIP_BODY:跳过主体
②、EVAL_BODY_INCLUDE:计算标签主体内容并[输出]
③、EVAL_BODY_AGAIN:再计算主体一次
④、EVAL_PAGE:计算页面的后续部分
⑤、SKIP_PAGE:跳过页面的后续部分
3、论证这三条路线的执行顺序
代码如下:
package com.ysq.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* 常见的三种路线(根据生命周期图整理出来的)
* 1.doStartTag...skipbody....doEndTag
* 2.doStartTag...EVAL_BODY_INCLUDE....doAfterBody...EVAL_PAGE...doEndTag
* 3.doStartTag...EVAL_BODY_INCLUDE....doAfterBody...EVAL_BODY_AGAIN...doAfterBody...EVAL_BODY_AGAIN...doAfterBody...EVAL_BODY_AGAIN...doEndTag
*
* 第一个例子:论证这三条路线的执行顺序
* 预测结果:在jsp页面中通过ysq:Demo1使用自定义标签,后台打印了(Demon1_doStarTag进来了,Demon1_doEndTag进来了)
* 那么说明了第1条路的正确
* @author zjjt
*
*/
public class Demo1 extends BodyTagSupport{
@Override
public int doStartTag() throws JspException {
// TODO Auto-generated method stub
System.out.println("Demo1_doStarTag进来了");
//return super.doStartTag();
return SKIP_BODY;
}
@Override
public int doEndTag() throws JspException {
System.out.println("Demo1_doEndTag进来了");
return super.doEndTag();
}
}
/**
* 常见的三种路线(根据生命周期图整理出来的)
* 1.doStartTag...skipbody....doEndTag
* 2.doStartTag...EVAL_BODY_INCLUDE....doAfterBody...EVAL_PAGE...doEndTag
* 3.doStartTag...EVAL_BODY_INCLUDE....doAfterBody...EVAL_BODY_AGAIN...doAfterBody...EVAL_BODY_AGAIN...doAfterBody...EVAL_BODY_AGAIN...doEndTag
* 第一个例子:论证这三条路线的执行顺序
* 预测结果:在jsp页面中通过ysq:Demo1使用自定义标签
* 后台打印了(Demon2_doStarTag进来了,"Demon2_doAfterBody进来了",Demon2_doEndTag进来了)
* 那么说明了第2条路的正确
* @author zjjt
*
*/
public class Demo2 extends BodyTagSupport{
@Override
public int doStartTag() throws JspException {
System.out.println("Demo2_doStarTag进来了");
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
System.out.println("Demo2_doAfterBody进来了");
return EVAL_PAGE;
}
@Override
public int doEndTag() throws JspException {
System.out.println("Demo2_doEndTag进来了");
return super.doEndTag();
}
}
/**
* 常见的三种路线(根据生命周期图整理出来的)
* 1.doStartTag...skipbody....doEndTag
* 2.doStartTag...EVAL_BODY_INCLUDE....doAfterBody...EVAL_PAGE...doEndTag
* 3.doStartTag...EVAL_BODY_INCLUDE....doAfterBody...EVAL_BODY_AGAIN...doAfterBody...EVAL_BODY_AGAIN...doAfterBody...EVAL_BODY_AGAIN...doEndTag
* 第一个例子:论证这三条路线的执行顺序
* 预测结果:在jsp页面中通过ysq:Demo1使用自定义标签
* 后台打印了(Demon3_doStarTag进来了,"Demon3_doAfterBody进来了",Demon3_doEndTag进来了)
* 那么说明了第3条路的正确
* @author zjjt
*
*/
public class Demo3 extends BodyTagSupport{
@Override
public int doStartTag() throws JspException {
System.out.println("Demo3_doStarTag进来了");
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
System.out.println("Demo3_doAfterBody进来了");
return EVAL_BODY_AGAIN;
}
@Override
public int doEndTag() throws JspException {
System.out.println("Demo3_doEndTag进来了");
return super.doEndTag();
}
}
标签库描述文件:
<tag>
<name>Demo1</name>
<tag-class>com.ysq.tag.Demo1</tag-class>
<body-content>JSP</body-content>
</tag>
<tag>
<name>Demo2</name>
<tag-class>com.ysq.tag.Demo2</tag-class>
<body-content>JSP</body-content>
</tag>
<tag>
<name>Demo3</name>
<tag-class>com.ysq.tag.Demo3</tag-class>
<body-content>JSP</body-content>
</tag>
测试: <y:Demo1>demo1</y:Demo1> <y:Demo2>demo2</y:Demo2> <%-- <y:Demo3>demo2</y:Demo3> --%>
运行结果:
四、if标签?
代码如下:
package com.ysq.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* 1.doStartTag...skipbody....doEndTag
* 2.doStartTag...EVAL_BODY_INCLUDE....doAfterBody...EVAL_PAGE...doEndTag
*案例2: 这个案例是针对第一条和第二条做一个实际应用
* 开发一个控制标签
* c:if test=true 是需要输出标签体的 要输出就走第二条路线
* c:if test=false 是不需要输出标签体的 不要输出就走第一条路线
* @author zjjt
*
*/
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 {
// 需要一个变量控制返回值,从而控制本标签走第一条线还是第二条线
return test ?EVAL_BODY_INCLUDE: SKIP_BODY;
}
}
标签库描述文件:
<tag>
<name>if</name>
<tag-class>com.ysq.tag.IfTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<!-- 自定义标签的成员变量的名称 -->
<name>test</name>
<!-- 该成员变量是否必传 -->
<required>true</required>
<!-- 是否支持 EL表达式 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
测试:
<y:if test="true">输出</y:if> <y:if test="false">不输出</y:if>
运行结果:
五、set与out标签
1、set
代码如下:
package com.ysq.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* 案例3和案例4 开发一个数据标签
* 1.第一条路线 只不过set,out标签,本身是没有标签体的,需要在页面上输出内容需要借助一个类jspWriter
* 2.在没有标签体的情况下是通过jspWriter来输出内容的
*
* @author zjjt
*
*/
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 {
// 将value值保存到var对应的变量中
// jsp传递name给var,传递zs给value
// 那么需要zs赋值给name
// 四大作用域 pageContext request session Application
// pageContext.setAttribute("name", "zs");
pageContext.setAttribute(var, value);
return super.doStartTag();
}
}
标签库描述文件:
<tag>
<name>set</name>
<tag-class>com.ysq.tag.SetTag</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>
2、out
代码如下:
package com.ysq.tag;
import java.io.IOException;
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 {
JspWriter out=pageContext.getOut();
try {
out.print(value);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.doStartTag();
}
}
标签库描述文件:
<tag>
<name>out</name>
<tag-class>com.ysq.tag.OutTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
测试:
<y:set var="name" value="小白"></y:set> <y:out value="${name}"></y:out>
?运行结果:
六、ForEach标签和Select标签
1、ForEach标签
代码如下:
package com.ysq.tag;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* 2.doStartTag...EVAL_BODY_INCLUDE....doAfterBody...EVAL_PAGE...doEndTag
* 3.doStartTag...EVAL_BODY_INCLUDE....doAfterBody...EVAL_BODY_AGAIN...doAfterBody...
* EVAL_BODY_AGAIN...doAfterBody...EVAL_BODY_AGAIN...doEndTag
* 案例5 foreach
* 熟悉第二第三的开发流程
* 实现思路
* 1.最少要有两个参数 var/items
* 2.一定要有标签体,那么对应需要重新doAfterBody方法
* 3.必定有判断条件决定doAfterBody的返回值是EVAL_PAGE还是EVAL_BODY_AGAIN
* 将去元素集合的过程,看成指针下移的过程,如果指针还能指向下一个,那么返回值为EVAL_BODY_AGAIN
* 如果指针没有下一个元素,那么返回值为EVAL_PAGE
* 指针是迭代器里面的产物,所以需要将迭代器保存并提供到doAfterBody中使用
* @author zjjt
*
*/
public class ForeachTag 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 {
// 在此处保存迭代器,工doAfterBody中使用
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()) {
// 在页面上需要通过var将集合中的对象拿到
// 让指针下移,it.next()代表了指针下移
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();
}
}
标签库描述文件:
<tag>
<name>foreach</name>
<tag-class>com.ysq.tag.ForeachTag</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>
测试中所使用的的User类:
package com.ysq.entity;
public class User {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String id, String name) {
super();
this.id = id;
this.name = name;
}
public User() {
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
测试:
<% ?List u=new ArrayList<>(); u.add(new User("1","小白")); u.add(new User("2","小黑")); u.add(new User("3","小蓝")); request.setAttribute("u", u); %> <y:foreach items="${u }" var="user"> ${user.id }:${user.name }<br> </y:foreach>
运行结果:
2、select标签(美化包括在)
代码如下:
package com.ysq.tag;
import java.util.ArrayList;
import java.util.List;
import java.lang.reflect.Field;
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 zjjt
*
*/
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;
}
}
标签库描述文件:
<tag>
<name>select</name>
<tag-class>com.ysq.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>
测试:
<!-- 模拟新增场景 --> <y:select textVal="name" items="${u }" textKey="id"></y:select> <!-- 默认显示 --> <!-- 模拟修改场景 --> <y:select selectedVal="u002" textVal="name" items="${u }" textKey="id"></y:select> <!-- 模拟查询场景 ?查询所有 --> <y:select headerTextKey="" headerTextVal="===请选择===" textVal="name" items="${u }" textKey="id"></y:select>
<!-- 美化后 --> <y:select cssStyle="font-size; 26px;color: red;" textVal="name" items="${u }" textKey="id"></y:select>
运行结果:
?
|