目录
一、什么是标签
二、JSP标签库是什么
三、标签语言特点
四、标签类型
五、自定义标签的开发及使用步骤
六、标签生命周期
七、反射工具类的使用
八、代码实操(forEach标签,if标签,out标签,select标签 )
九、总结
一、什么是标签
标记语言,是一种注释文本的语言,以便于计算机可以操作。
很多与“ML”结尾的语言都是标记语言,比如:HTML,XML,XHTML,VML等等。
标记语言与其他语言一样,也需要运行它们的环境,
比如HTML的运行环境时浏览器,XML也要自己的解析和运行的环境。
二、JSP标签库是什么
是一个JSP标签集合,
它封装了JSP应用的通用核心功能,
基于JSP标签我们可以理解为,
是JSP应该通用功能的一种封装方式。
三、标签语言特点
基本结构:
<开始标签 属性="属性值">标签体</结束标签>
空标签:
<br/><hr/>
<开始标签></结束标签>
<开始标签/>
四、标签类型
-
UI标签, 输出页面元素;
-
控制标签, 如if标签,foreach标签等;
-
数据标签,用于向页面输入数据。
五、自定义标签的开发及使用步骤
为什么要在自定义标签:
在一些标签不能满足我们代码所需的一些要求了,这个时候就需要自己去定义了
-
创建一个标签助手类(继承BodyTagSupport),标签属性必须与助手类的属性对应、且要提供对应get/set方法;
-
创建标签库描述文件(tld),添加自定义标签的配置;(注:tld文件必须保存到WEB-INF目录或其子目录jstl标签库)
-
在JSP通过taglib指令导入标签库,并通过指定后缀访问自定义标签。
三种方法在什么时候执行:
- 默认情况,如果jsp上面有标签体,那么三个方法都会执行
-
如果没有标签体,那么doAfterBody方法不会执行
-
即默认设置
-
此时jsp上有标签体,人为将doStartTag的返回值改为SKIP_BODY,那么doAfterBody也不执行 并且jsp页面主体类容显示
-
如果改变doAfterBody的莫认返回值为EVAL_BODY_AGAIN,那么doAfterBody会反复执行
六、标签生命周期
1.doStartTag() 开始标签
2.doAfterBody() 主体部分
3.doEndTag() 结束标签
流程A:SKIP_BODY
3.1 实例化标签助手类->doStartTag()------------->doEndTag()
//主要用开发简单标签
流程B:EVAL_BODY_INCLUDE SKIP_BODY
3.2 实例化标签助手类->doStartTag()------------->doAfterBody---------------->doEndTag()...EVAL_BODY_AGAIN
3.3 .....jrebal 热加载
public class DemoTag extends BodyTagSupport {//继承
private static final long serialVersionUID = 1L;//防止报空指针异常
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
@Override
public int doStartTag() throws JspException {
System.out.println("--------------------doStartTag-------------------------");
//return super.doStartTag();
//return Eval;//跳过主体
return EVAL_BODY_AGAIN;//在打印一遍
}
@Override
public int doEndTag() throws JspException {
System.out.println("---------------doEndTag---------------");
return super.doEndTag();
}
@Override
public int doAfterBody() throws JspException {
System.out.println("-----------doAfterBody-----------------");
return super.doAfterBody();//在打印一遍
}
}
SKIP_BODY:跳过主体
EVAL_BODY_INCLUDE:计算标签主体内容并[输出]
EVAL_PAGE:计算页面的后续部分
SKIP_PAGE:跳过页面的后续部分
EVAL_BODY_AGAIN:再计算主体一次
七、反射工具类的使用
PropertyUtils.getProperty(bean, name);返回Object
BeanUtils.getProperty(bean, name);返回String
八、代码实操(forEach标签,if标签,out标签,select标签 开发示例)
mytag.tld:
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
<!-- 代表标签库的版本号 -->
<tlib-version>1.0</tlib-version>
<!-- 代表jsp的版本 -->
<jsp-version>1.2</jsp-version>
<!-- 你的标签库的简称 -->
<short-name>z</short-name>
<!-- 你标签库的引用uri -->
<uri>/zking</uri>
<tag>
<!-- 标签名 -->
<name>test</name>
<!-- 标签工具类 -->
<tag-class>com.zking.jspTag.tag.TestTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>jsp</body-content>
<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
<attribute>
<!-- 自定义标签的属性名称 -->
<name>name</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<tag>
<!-- 标签名 -->
<name>forEach</name>
<!-- 标签工具类 -->
<tag-class>com.zking.jspTag.tag.ForEachTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>jsp</body-content>
<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
<attribute>
<!-- 自定义标签的属性名称 -->
<name>items</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的属性名称 -->
<name>var</name>
<!-- true表示必填 -->
<required>false</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的属性名称 -->
<name>varStatus</name>
<!-- true表示必填 -->
<required>false</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<tag>
<!-- 标签名 -->
<name>select</name>
<!-- 标签工具类 -->
<tag-class>com.zking.jspTag.tag.SelectTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>empty</body-content>
<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
<attribute>
<!-- 自定义标签的属性名称 -->
<name>items</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的属性名称 -->
<name>name</name>
<!-- true表示必填 -->
<required>false</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的属性名称 -->
<name>valueKey</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的属性名称 -->
<name>textKey</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的属性名称 -->
<name>headText</name>
<!-- true表示必填 -->
<required>false</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的属性名称 -->
<name>selectOptionValue</name>
<!-- true表示必填 -->
<required>false</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- 自定义标签的属性名称 -->
<name>cssStyle</name>
<!-- true表示必填 -->
<required>false</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<tag>
<!-- 标签名 -->
<name>out</name>
<!-- 标签工具类 -->
<tag-class>com.zking.jspTag.tag.OutTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>jsp</body-content>
<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
<attribute>
<!-- 自定义标签的属性名称 -->
<name>value</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<!-- 标签名 -->
<name>if</name>
<!-- 标签工具类 -->
<tag-class>com.zking.jspTag.tag.IfTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>jsp</body-content>
<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
<attribute>
<!-- 自定义标签的属性名称 -->
<name>test</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
Dept.java类:
package com.zking.jspTag.tag;
import java.io.Serializable;
public class Dept implements Serializable {
private Integer did;
private String dname;
public Dept() {
}
public Dept(Integer did, String dname) {
super();
this.did = did;
this.dname = dname;
}
public Integer getDid() {
return did;
}
public void setDid(Integer did) {
this.did = did;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Dept [did=" + did + ", dname=" + dname + "]";
}
}
TestTag.java类:
package com.zking.jspTag.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class TestTag extends BodyTagSupport {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 在结束标签时执行的动作 </z:test>
* 返回值 有两种:
* 1.EVAL_PAGE:计算页面的后续部分
* 2.SKIP_PAGE:跳过页面的后续部分
*/
@Override
public int doEndTag() throws JspException {
System.out.println("在结束标签时执行的动作 doEndTag()....");
return EVAL_PAGE;
}
/**
* 在开始标签时执行的动作 <z:test>
* 返回值 有两种:
* 1.skip_body 跳过主体内容
* 2.EVAL_BODY_INCLUDE 计算主体内容并输出
*
*/
@Override
public int doStartTag() throws JspException {
System.out.println("name="+this.name);
System.out.println("在开始标签时执行的动作 doStartTag()....");
return EVAL_BODY_INCLUDE;
}
}
ForEachTag.java类:
package com.zking.jspTag.tag;
import java.util.Iterator;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class ForEachTag extends BodyTagSupport {
private List<Object> items; // 数据源 List集合
private String var; // 保存遍历元素在作用域中的 key
private String varStatus; // 保存遍历状态对象在作用域中的key
// 内部类 用来保存遍历的状态
public static class Status {
public int index = 0;
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getCount() {
return this.index + 1;
}
public void increment() {
this.index++;
}
}
public List<Object> getItems() {
return items;
}
public void setItems(List<Object> items) {
this.items = items;
}
public String getVar() {
return var;
}
public void setVar(String var) {
this.var = var;
}
public String getVarStatus() {
return varStatus;
}
public void setVarStatus(String varStatus) {
this.varStatus = varStatus;
}
@Override
public int doAfterBody() throws JspException {
Iterator it = (Iterator) pageContext.getAttribute("it");// 取出作用域中的迭代器
if (it.hasNext()) {
Object next = it.next(); // 取出下一个元素
pageContext.setAttribute(this.var, next); // 将取出元素放到作用域中
if (null != this.varStatus && !"".equals(this.varStatus.trim())) {
Status status = (Status) pageContext.getAttribute(this.varStatus);
status.increment();
pageContext.setAttribute(this.varStatus, status);
}
return EVAL_BODY_AGAIN;
}
return super.doAfterBody();
}
@Override
public int doStartTag() throws JspException {
if (null != items && 0 != items.size()) { // 如果集合不为空,并且不是一个长度为0的集合
Iterator<Object> it = items.iterator(); // 得到集合的迭代器
Object next = it.next(); // 取出集合中的第一个元素
pageContext.setAttribute(this.var, next); // 把第一个元素保存到作用域中,key为var中的值
pageContext.setAttribute("it", it); // 将迭代器保存到作用域中
if (null != this.varStatus && !"".equals(this.varStatus.trim())) {
Status status = new Status();
pageContext.setAttribute(this.varStatus, status);
}
return EVAL_BODY_INCLUDE;
}
return super.doStartTag();
}
}
IfTag.java类:
package com.zking.jspTag.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class IfTag extends BodyTagSupport {
private Boolean test;
public Boolean getTest() {
return test;
}
public void setTest(Boolean test) {
this.test = test;
}
@Override
public int doStartTag() throws JspException {
if(test) { //如果为true,执行标签体并且输出
return EVAL_BODY_INCLUDE;
}else { //为false,跳过标签体
return SKIP_BODY;
}
}
}
OutTag.java类:
package com.zking.jspTag.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.println(this.value);
out.println("<select name=\"\">\r\n" +
" <option value=\"1\">财务部</option>\r\n" +
" <option value=\"2\">教学部</option>\r\n" +
" <option value=\"3\">就业部</option>\r\n" +
" <option value=\"4\">教质部</option>\r\n" +
" \r\n" +
"</select>");
} catch (IOException e) {
e.printStackTrace();
}
return super.doStartTag();
}
}
SelectTag.java类:
package com.zking.jspTag.tag;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import javax.management.RuntimeErrorException;
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; //数据源
private String valueKey; //遍历元素中的id属性名
private String textKey; //遍历元素中的文本属性名
private String name;
private String headText;
private String selectOptionValue; //默认选中的value值
private String cssStyle; //样式
public List<Object> getItems() {
return items;
}
public String getSelectOptionValue() {
return selectOptionValue;
}
public String getCssStyle() {
return cssStyle;
}
public void setCssStyle(String cssStyle) {
this.cssStyle = cssStyle;
}
public void setSelectOptionValue(String selectOptionValue) {
this.selectOptionValue = selectOptionValue;
}
public void setItems(List<Object> items) {
this.items = items;
}
public String getHeadText() {
return headText;
}
public void setHeadText(String headText) {
this.headText = headText;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValueKey() {
return valueKey;
}
public void setValueKey(String valueKey) {
this.valueKey = valueKey;
}
public String getTextKey() {
return textKey;
}
public void setTextKey(String textKey) {
this.textKey = textKey;
}
@Override
public int doStartTag() throws JspException {
JspWriter out = pageContext.getOut();
try {
System.out.println(toHtml());
out.println(toHtml());
} catch (Exception e) {
throw new RuntimeException(e);
}
return SKIP_BODY;
}
/**
* 拼接html语句
* <select name="">
<option value="1">财务部</option>
<option value="2">教学部</option>
<option value="3">就业部</option>
<option value="4">教质部</option>
</select>
*
* @return
* @throws Exception
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
public String toHtml() throws Exception {
if(null==items || 0==items.size()) {//如果数据源为空,就直接返回一个空字符串
return "";
}
StringBuffer sb = new StringBuffer();
sb.append("<select ");
sb.append(" name='"+this.name+"' ");
if(null!=this.cssStyle) {
sb.append(" style='"+this.cssStyle+"' ");
}
sb.append(" >");
Object value = null;
Object text = null;
if(null!=this.headText) {
sb.append("<option>"+this.headText+"</option>");
}
for (Object obj : items) { //遍历数据源
//反射获取对象的属性值
value = PropertyUtils.getProperty(obj, this.valueKey);
text = PropertyUtils.getProperty(obj, this.textKey);
if(value.toString().equals(this.selectOptionValue)) { //如果value值和需要默认选中的值一样
sb.append("<option selected value='"+value+"'>"+text+"</option>");
}else {
sb.append("<option value='"+value+"'>"+text+"</option>");
}
}
sb.append("</select>");
return sb.toString();
}
}
index主界面类:
<%@page import="com.zking.jspTag.tag.Dept"%>
<%@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://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="z" uri="/zking" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
List students = new ArrayList<>();
String name = "zs";
request.setAttribute("name", name);
students.add("zs");
students.add("ls");
students.add("ww");
List<Dept> list = new ArrayList<Dept>();
list.add(new Dept(1,"财务部"));
list.add(new Dept(2,"教学部"));
list.add(new Dept(3,"就业部"));
list.add(new Dept(4,"教质部"));
request.setAttribute("students", students);
request.setAttribute("listDept", list);
%>
<!-- 自定义out标签 -->
<h1>
<c:out value="${name}"></c:out> <br/>
<z:out value="${name }"></z:out>
</h1>
<!-- 自定义if标签 -->
<h1>
<c:if test="${name eq 'zs'}">大哥来了</c:if>
<z:if test="${name eq 'zs' }">他走了</z:if>
</h1>
<!-- 自定义forEach标签 -->
<h1>
<c:forEach items="${students}" var="sb" varStatus="s">
${sb},${s.index},${s.count }
</c:forEach> <br/>
<z:forEach items="${students}" var="sb" varStatus="s">
${sb},${s.index},${s.count }
</z:forEach>
</h1>
<!-- 自定义select标签 -->
<select name="" style="width:140px">
<option value="1">财务部</option>
<option value="2">教学部</option>
<option selected value="3">就业部</option>
<option value="4">教质部</option>
</select>
<z:select cssStyle="width:140px" selectOptionValue="3" name="dept" headText="---请选择---" items="${listDept}" valueKey="did" textKey="dname"/>
</body>
</html>
九、总结
JSP自定义标签就分享到这了,希望能对大家有所帮助!