JSP的标签库技术可以使得我们可以自己定制自己的标签,如自己定义自己的分页标签,相比之前写过自己用Servlet的标签,的确更方便更好使
其实自定义标签是一个实现了特定接口的Java类,封装了一些常用功能,运行的时候被响应的代码代替,仍然是相关Servlet原理的
概念很多,也比较复杂,我们看一个实例
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib uri="/mytag" prefix="my"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<my:hello/>
</body>
</html>
简单使用了一个标签<my:hello/>
prefix前缀 在这里类似命名空间的意义,可以随意取名,但是用的时候前缀就要对上了比如是my1 那么用的时候就是<my1:hello>
uri是标签的标识通过它来找到对应的文件,怎么找呢?通过web.xml文件
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<jsp-config>
<taglib>
<taglib-uri>/mytag</taglib-uri>
<taglib-location>/WEB-INF/MyTaglib.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
可以看到对应uri=/mytag就可以找到一个MyTaglib.tld文件
TLD术语解释:标签库描述文件,如要在JSP页面中实现JSP标签,必须首先定义实现标签的类,然后在标签库描述文件(TLD)中将写好的类映射成jsp标签,最后在JSP文件中使用定义好的标签,就可以生成动态的JSP内容MyTaglib.tld
<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 web-jsptaglibrary_2_1.xsd"
version="2.1">
<tlib-version>1.0</tlib-version>标签库版本,开发者的声明
<short-name>my</short-name>默认的前缀值
<display-name>My Tag</display-name>文本描述
<description>custom tag</description>简短的名字,可以被一些工具显示
<tag>用于指定自定义标签的内容
<name>hello</name>标签名称
<tag-class>org.tags.HelloTag</tag-class>标签处理类
<body-content>empty</body-content>标签的格式
</tag>
</taglib>
找到这个文件之后呢,我们看到很多嵌套的标签特别要记住的就是tag-class与name,JSP使用的时候就是前缀值:具体标签名字,前者就是具体的标签处理类了
org.tags.HelloTag.java
package org.tags;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
public class HelloTag implements Tag {
private Tag parent;
private PageContext pagecontext;//利用它来获得输出流
@Override
public int doEndTag() throws JspException {
// TODO Auto-generated method stub
JspWriter out=pagecontext.getOut();
try {
out.println("wuhan_beautiful_girl");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return EVAL_PAGE;
}
@Override
public int doStartTag() throws JspException {
// TODO Auto-generated method stub
return SKIP_BODY;
}
@Override
public Tag getParent() {
// TODO Auto-generated method stub
return parent;
}
@Override
public void release() {
// TODO Auto-generated method stub
}
@Override
public void setPageContext(PageContext arg0) {
// TODO Auto-generated method stub
this.pagecontext=arg0;
}
@Override
public void setParent(Tag arg0) {
// TODO Auto-generated method stub
this.parent=arg0;
}
}
解释一下这张图片
1.调用前两个方法,setpagecontext设置页面上下文,这个就是JSP的内置对象
setparent设置父标签,根据学过html的经验大概就是保住它的外部标签吧
2.设置标签的属性
3.调用doStartTag方法,返回EVAL_BODY_INCLUD或者SKIP_BODY
When a Tag returns EVAL_BODY_INCLUDE the result of evaluating the body (if any) is included into the current "out" JspWriter as it happens and then doEndTag() is invoked.
SKIP_BODY则是跳过标签体
4.调用doEndTag
If this method returns EVAL_PAGE, the rest of the page continues to be evaluated. If this method returns SKIP_PAGE, the rest of the page is not evaluated, the request is completed, and the doEndTag() methods of enclosing tags are not invoked. If this request was forwarded or included from another page (or Servlet), only the current page evaluation is stopped.
一般使用的都是前者,后者导致后面的JSP页面不显示了
需要注意的是容器会缓存这个标签处理类实例,有同样的标签,重复使用缓存的而不是在NEW一个
最后才是释放标签处理类实例的时候最后会被调用release()