一、带属性的自定义标签的实现
前提须知:
标签库 API
关于SimpleTagSupport类
public class HelloSimpleTag implements SimpleTag
public class SimpleTagSupport implements SimpleTag {
private JspTag parentTag;
private JspContext jspContext;
private JspFragment jspBody;
@Override
public void doTag() throws JspException, IOException {
// NOOP by default
}
@Override
public void setParent( JspTag parent ) {
this.parentTag = parent;
}
@Override
public JspTag getParent() {
return this.parentTag;
}
@Override
public void setJspContext( JspContext pc ) {
this.jspContext = pc;
}
protected JspContext getJspContext() {
return this.jspContext;
}
@Override
public void setJspBody( JspFragment jspBody ) {
this.jspBody = jspBody;
}
protected JspFragment getJspBody() {
return this.jspBody;
}
public static final JspTag findAncestorWithClass(
JspTag from, Class<?> klass)
{
boolean isInterface = false;
if (from == null || klass == null
|| (!JspTag.class.isAssignableFrom(klass)
&& !(isInterface = klass.isInterface()))) {
return null;
}
for (;;) {
JspTag parent = null;
if( from instanceof SimpleTag ) {
parent = ((SimpleTag)from).getParent();
}
else if( from instanceof Tag ) {
parent = ((Tag)from).getParent();
}
if (parent == null) {
return null;
}
if (parent instanceof TagAdapter) {
parent = ((TagAdapter) parent).getAdaptee();
}
if ((isInterface && klass.isInstance(parent))
|| klass.isAssignableFrom(parent.getClass())) {
return parent;
}
from = parent;
}
}
}
在第一种实现中只需要知道
1、setJspContext 方法:该方法把代表 JSP 页面的 pageContext 对象传递给标签处理器对象。
2、doTag 方法:该方法用于完成所有的标签逻辑。该方法可以抛出 javax.servlet.jsp.SkipPageException 异常,用于通知 web 容器不再执行 JSP 页面中位于结束标记后面的内容。
3、只要在tld声明属性名,然后再java代码中实现Set属性名的方法就能够得到该属性值
具体实现如下3个带属性的自定义标签:
kk.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 使用 wjc 指令导入标签库描述文件 -->
<%@taglib prefix="wjc" uri="http://www.baidu.com/mytag/core"%>
<!DOCTYPE html >
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 循环count次输出value值 -->
<wjc:hello value="${param.name }" count="3"/>
<!-- 获取num1和num2的最大值 -->
<wjc:max num1="23" num2="32"/>
<!-- 将WEB-INF下的a.txt输出再浏览器上 -->
<wjc:read src="WEB-INF/a.txt"/>
</body>
</html>
tag.tld(必须放在WEB-INF目录下面)
<?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>Tag 1.1 core library</description>
<display-name>Tag core</display-name>
<!-- 指定标签库的版本号 -->
<tlib-version>1.0</tlib-version>
<!-- 指定标签库的默认前缀名 -->
<short-name>wjc</short-name>
<!-- 指定标签库的唯一uri -->
<uri>http://www.baidu.com/mytag/core</uri>
<!-- 描述自定义的 标签 -->
<tag>
<!-- 标签的名字: 在 JSP 页面上使用标签时的名字 -->
<name>hello</name>
<!-- 标签所在的全类名 -->
<tag-class>cn.itcast.tag.HelloSimpleTag</tag-class>
<!-- 标签体的类型 一共有3种类型 -->
<body-content>empty</body-content>
<!-- 描述当前标签的属性 -->
<attribute>
<!-- 属性名, 需和标签处理器类的 setter 方法定义的属性相同 -->
<name>value</name>
<!-- 该属性是否被必须
就是说在jsp中一定包含value属性
-->
<required>true</required>
<!-- rtexprvalue: runtime expression value
当前属性是否可以接受运行时表达式的动态值
${param.name}
-->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>count</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<tag>
<name>max</name>
<tag-class>cn.itcast.tag.HelloSimpleTag2</tag-class>
<body-content>empty</body-content>
<attribute>
<name>num1</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>num2</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<tag>
<name>read</name>
<tag-class>cn.itcast.tag.HelloSimpleTag3</tag-class>
<body-content>empty</body-content>
<attribute>
<name>src</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
HelloSimpleTag.java
package cn.itcast.tag;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;
public class HelloSimpleTag implements SimpleTag {
private PageContext pageContext;
private String value;
private String count;
public void setValue(String value) {
this.value = value;
}
public void setCount(String count) {
this.count = count;
}
//标签体逻辑实际应该编写到该方法中
@Override
public void doTag() throws JspException, IOException {
// TODO Auto-generated method stub
/*System.out.println("value:"+value+" count:"+count);
HttpServletRequest httpServletRequest = (HttpServletRequest)pageContext.getRequest();
String name = httpServletRequest.getParameter("name");
try {
pageContext.getOut().println("hello "+name);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
JspWriter out = pageContext.getOut();
int k = Integer.valueOf(count);
for(int i = 0; i<k ;i++){
out.println("hello "+value+"<br/>");
}
}
@Override
public void setParent(JspTag parent) {
// TODO Auto-generated method stub
System.out.println("setParent");
}
@Override
public JspTag getParent() {
// TODO Auto-generated method stub
System.out.println("getParent");
return null;
}
//jsp引擎调用,把代表jsp页面的PageContext对象传入
//PageContext可以获取jsp页面的其他八个隐含对象
//所以凡是jsp页面可以做的,标签处理器都可以完成
@Override
public void setJspContext(JspContext pc) {//pc是属于pageContext
// TODO Auto-generated method stub
pageContext = (PageContext)pc;
}
@Override
public void setJspBody(JspFragment jspBody) {
// TODO Auto-generated method stub
System.out.println("setJspBody");
}
}
HelloSimpleTag2.java
package cn.itcast.tag;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class HelloSimpleTag2 extends SimpleTagSupport {
private PageContext pageContext;
private String num1;
private String num2;
public void setNum1(String num1) {
this.num1 = num1;
}
public void setNum2(String num2) {
this.num2 = num2;
}
//标签体逻辑实际应该编写到该方法中
@Override
public void doTag() throws JspException, IOException {
// TODO Auto-generated method stub
/*System.out.println("value:"+value+" count:"+count);
HttpServletRequest httpServletRequest = (HttpServletRequest)pageContext.getRequest();
String name = httpServletRequest.getParameter("name");
try {
pageContext.getOut().println("hello "+name);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
pageContext = (PageContext) getJspContext();
JspWriter out = pageContext.getOut();
int k1 = Integer.valueOf(num1);
int k2 = Integer.valueOf(num2);
out.print((k1>=k2)?k1:k2);
}
}
HelloSimpleTag3.java
package cn.itcast.tag;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class HelloSimpleTag3 extends SimpleTagSupport {
private PageContext pageContext;
private String src;
private BufferedReader reader;
public void setSrc(String src) {
this.src = src;
}
//标签体逻辑实际应该编写到该方法中
@Override
public void doTag() throws JspException, IOException {
pageContext = (PageContext)getJspContext();
InputStream in = pageContext.getServletContext().getResourceAsStream(src);
System.out.println(src);
reader = new BufferedReader(new InputStreamReader(in));
JspWriter out = pageContext.getOut();
String line = null;
while((line = reader.readLine())!=null){
/*line = Pattern.compile("<").matcher(line).replaceAll("<");
line = Pattern.compile(">").matcher(line).replaceAll(">");*/
line = line.replaceAll("<", "<");
line = line.replaceAll(">", ">");
out.println(line+"<br/>");
}
}
}
二、带标签体的自定义标签的实现
前提须知
1)若一个标签有标签体
<wjc:test time="10">hello lhh</wjc:test>
在自定义标签的标签处理器中使用JspFragment对象封装标签体信息。
2)若设置了标签含有标签体,则jsp引擎会调用setJspBody( JspFragment jspBody )方法把JspFragment传递给标签处理器。
再SimpleTagSupport中还定义了一个protected JspFragment getJspBody()方法,用于返回JspFragment对象。
3)JspFragment的invoke(Writer)方法:把标签体内容从Writer中输出,若为null,
则等同于invoke(getJspContext().getOut()),即直接把标签体内容输出到页面上。
有时可以借助StringWriter,可以再标签处理器类中先得到标签体的内容。
//JspFragment的invoke:Writer即为标签体内容输出的字符流,若为Null,则
//输出到getJspContext().getOut():即输出到页面上。
StringWriter sw = new StringWriter();
bodyContext.invoke(sw);
//把标签体的内容变成大写的
System.out.println(sw.toString().toUpperCase());
4)在tld文件中,使用body-content节点描述标签体类型:
<body-content>:指定标签体的类型。可能取值有 3 种:
empty:没有标签体
scriptless:标签体可以包含 el 表达式和 JSP 动作元素,但不能包含 JSP 的脚本元素(<%=request.getAttribute("name")%>)
tagdependent:表示标签体交由标签本身去解析处理。若指定 tagdependent,
在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果传递给标签处理器
<body-content>scriptless</body-content>
具体实现如下()功能:
<%@page import="cn.itcast.bean.UserBean"%>
<%@page import="java.util.List"%>
<%@page import="java.util.ArrayList"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="wjc" uri="http://www.baidu.com/mytag2/core" %>
<!DOCTYPE html >
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<wjc:test time="10">hello lhh</wjc:test>
<%
List<UserBean> list = new ArrayList<UserBean>();
list.add(new UserBean(1,"a","a"));
list.add(new UserBean(2,"b","b"));
list.add(new UserBean(3,"c","c"));
list.add(new UserBean(4,"d","d"));
request.setAttribute("customer", list);
%>
<!-- 其实在标签体中的cust是放在page的属性中 类似于java中的pageContext.setAttribute("cust",customer类对象) -->
<wjc:foreach items="${requestScope.customer }" var="cust">
${pageScope.cust.uid } -- ${cust.uname } <br/>
</wjc:foreach>
</body>
</html>
输出结果
1 -- a
2 -- b
3 -- c
4 -- d
maytag2.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>Tag 1.1 core library</description>
<display-name>Tag core</display-name>
<tlib-version>1.0</tlib-version>
<short-name>wjc</short-name>
<uri>http://www.baidu.com/mytag2/core</uri>
<tag>
<name>foreach</name>
<tag-class>cn.itcast.tag.TestJspFragmentx</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>var</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
TestJspFragmentx.java
package cn.itcast.tag;
import java.io.IOException;
import java.util.Collection;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class TestJspFragmentx extends SimpleTagSupport {
private Collection<?> items;
private String var;
public void setItems(Collection<?> items) {
this.items = items;
}
public String getVar() {
return var;
}
public void setVar(String var) {
this.var = var;
}
@Override
public void doTag() throws JspException, IOException {
// TODO Auto-generated method stub
System.out.println(items);
for(Object ll:items){
getJspContext().setAttribute(var, ll);
//获取标签体
JspFragment bodyContext = getJspBody();
//实现表签体内的功能
bodyContext.invoke(null);
}
}
}
三、开发有父标签的标签
前提须知
1).父标签无法获取子标签的引用,父标签仅把子标签作为标签体来使用
2).子标签可以通过getParent()方法获取父标签的引用(需继承SimpleTagSupport或自实现SimpleTag接口的方法)
若子标签的确有父标签,jsp引擎会把代表父标签的引用通过setParent( JspTag parent )赋给标签处理器。
3).注意:父标签的类型是JspTag类型,该接口是一个空接口,但是来统一Tag和SimpleTag的,实际使用需要进行类型的强制转换
4).在tld配置文件中,无需为父标签有额外的配置。但子标签是以标签体的形式存在的,所以父标签要
<body-content>scriptless</body-content>
具体实现如下功能
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://www.baidu.com/mytag2/core" prefix="wjc"%>
<!DOCTYPE html >
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
request.setAttribute("age", 21);
%>
<wjc:choose>
<wjc:when test="${requestScope.age>24 }">大学毕业</wjc:when>
<wjc:when test="${requestScope.age>20 }">高中毕业</wjc:when>
<wjc:otherwise>高中以下....</wjc:otherwise>
</wjc:choose>
</body>
</html>
>开发3个标签:choose、when、otherwise
>其中when标签有一个boolean类型的属性:test
>choose是when和otherwise的父标签
>when在otherwise之前使用
> 在父标签 choose 中定义一个 "全局" 的 boolean 类型的 flag: 用于判断子标签在满足条件的情况下是否执行.
* 若 when 的 test 为 true, 且 when 的父标签的 flag 也为 true, 则执行 when 的标签体(正常输出标签体的内容),
同时把 flag 设置为 false
* 若 when 的 test 为 true, 且 when 的父标签的 flag 为 false, 则不执行标签体.
* 若 flag 为 true, otherwise 执行标签体.
输出结果
高中毕业
mytag3.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>Tag 1.1 core library</description>
<display-name>Tag core</display-name>
<tlib-version>1.0</tlib-version>
<short-name>wjc</short-name>
<uri>http://www.baidu.com/mytag2/core</uri>
<tag>
<name>choose</name>
<tag-class>cn.itcast.tag.ChooseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
<tag>
<name>when</name>
<tag-class>cn.itcast.tag.WhenTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>otherwise</name>
<tag-class>cn.itcast.tag.OtherWise</tag-class>
<body-content>scriptless</body-content>
</tag>
</taglib>
ChooseTag.java
package cn.itcast.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ChooseTag extends SimpleTagSupport {
boolean flag = true;
@Override
public void doTag() throws JspException, IOException {
// TODO Auto-generated method stub
JspFragment js = getJspBody();
js.invoke(null);
}
}
WhenTag.java
package cn.itcast.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class WhenTag extends SimpleTagSupport {
boolean test;
public void setTest(boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
// TODO Auto-generated method stub
ChooseTag ctag = (ChooseTag)getParent();
boolean flag = ctag.flag;
if(test && flag){
JspFragment js = getJspBody();
js.invoke(null);
ctag.flag = false;
}
}
}
OtherWise.java
package cn.itcast.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class OtherWise extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
// TODO Auto-generated method stub
ChooseTag ctag = (ChooseTag)getParent();
boolean flag = ctag.flag;
if(flag){
JspFragment js = getJspBody();
js.invoke(null);
}
}
}
四、EL 自定义函数的实现
这边其实只要看一下实现就行。前提在前面3个类型标签中已经讲过了。
具体实现
<%@page import="java.util.ArrayList"%>
<%@page import="cn.itcast.bean.UserBean"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%@taglib uri="http://www.baidu.com/mytag2/core" prefix="wjc"%>
<!DOCTYPE html >
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- http://localhost:8080/SimpaleCode/test2.jsp?name=234erdsfg -->
${fn:length(param.name) }<!-- 9 -->
<br/>
<!-- el自定义函数 -->
<!-- 字符串的拼接 -->
${wjc:concat(param.name,param.name1) }
<br/>
<!-- 字符串的截取 -->
${wjc:substr("asdsdf",3,2) }
</body>
</html>
url地址栏为
http://localhost:8080/SimpaleCode/test2.jsp?name=234erdsfg
输出结果
9
234erdsfg
sd
mytag4.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>Tag 1.1 core library</description>
<display-name>Tag core</display-name>
<tlib-version>1.0</tlib-version>
<short-name>wjc</short-name>
<uri>http://www.baidu.com/mytag2/core</uri>
<!-- 描述el的自定函数 -->
<function>
<name>concat</name>
<function-class>cn.itcast.tag.MyFunction</function-class>
<function-signature>java.lang.String concat(java.lang.String ,java.lang.String )</function-signature>
</function>
<!-- 描述el的自定函数 -->
<function>
<name>substr</name>
<function-class>cn.itcast.tag.MyFunction</function-class>
<function-signature>java.lang.String substr(java.lang.String ,java.lang.Integer, java.lang.Integer)</function-signature>
</function>
</taglib>
MyFunction.java
package cn.itcast.tag;
public class MyFunction {
public static String concat(String s1,String s2){
return s1+s2;
}
public static String substr(String s,Integer begin,Integer length){
return s.substring(begin, begin+length);
}
}