JSP2.2自定義標籤、EL函數

簡介
JSTL是一個JSP標準標籤庫,能夠解決大部分問題,可是若是咱們須要一些更特殊的功能,就須要自定義相似JSTL中標籤的標籤。若是EL表達式沒法知足咱們的需求,咱們也能夠自定義EL函數。
tld後綴的文件爲標籤庫描述符,它是一個XML格式的文件,顧名思義,就是用來描述標籤庫的文件,編寫自定義標籤和EL函數時都須要用到。
 
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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<!--標籤庫描述-->
<description>測試標籤庫</description>
<!--標籤版版本-->
<tlib-version>1.0</tlib-version>
<!--標籤庫名稱-->
<short-name>testTagLibrary</short-name>
<!--定義一個惟一標識當前版本標籤庫的公開的URI,taglib指令的uri屬性必須等於該值。
若是沒有將標籤處理器和tld文件打成jar包,那麼taglib指令的uri屬性的值也能夠本文件的相對路徑,如/WEB-INF/test.tld-->
<uri>http://test/tag-library.com</uri>
 
<tag>
<!--標籤描述-->
<description>經典標籤庫</description>
<!--標籤的名稱,引用標籤時使用-->
<name>classic</name>
<!--標籤處理器的徹底限定類名,不能放到默認包下-->
<tag-class>com.ClassicCustomTag</tag-class>
<!--
指定標籤有效的body類型。
JSP容器使用此值來驗證標籤body類型是否正確,並經過頁面組合工具幫助頁面做者提供有效的標籤body。
tagdependent:標籤的body由標籤處理器解析,能夠是另一種語言,如SQL。
JSP:標籤body能夠包含jsp的語法,如jsp腳本元素,使用簡單標籤處理器不能設置爲該值。
empty:標籤body必須爲空。
scriptless:標籤body能夠是靜態HTML元素,EL表達式,jsp動做元素,但不容許出現jsp腳本元素
-->
<body-content>JSP</body-content>
<!--標籤的屬性-->
<attribute>
<!--屬性描述-->
<description>權限</description>
<!--屬性的名稱-->
<name>permission</name>
<!--true/yes表示必須,false/no表示可選-->
<required>true</required>
<!--true/yes表示屬性值支持jsp腳本元素和EL表達式,false/no表示不支持-->
<rtexprvalue>true</rtexprvalue>
<!--屬性值的類型,若是rtexprvalue爲false/no,則該值永遠爲java.lang.String-->
<type>java.lang.String</type>
</attribute>
</tag>
 
<!--用於提供標籤庫中要暴露給EL的每一個函數的信息-->
<function>
<!--函數的惟一名稱-->
<name>customPrint</name>
<!--函數的徹底限定類名,不能放到默認包下,該類包含實現該函數的靜態方法-->
<function-class>com.CustomElFunction</function-class>
<!--實現該函數的靜態方法的簽名,能夠使用基本數據類型以及void。
如java.lang.String nickName(java.lang.String,int)-->
<function-signature>java.lang.String print(java.lang.String)</function-signature>
</function>
</taglib>
 
自定義標籤
建立自定義標籤分爲兩個步驟,編寫標籤處理器和註冊標籤。標籤處理器在JSP2.0以後新增了一種實現方式。註冊標籤就是在tld文件中描述標籤,而且把tld文件放到WEB-INF目錄下。若是把標籤處理器和tld文件打成jar包,那麼tld文件應該放在jar包的META-INF目錄下。
 
JSP2.0以前
JSP2.0以前的標籤處理器要實現Tag、IterationTag、BodyTag等接口,稱爲典型標籤處理器。
 
TagSupport
標籤處理器繼承TagSupport類,而後重寫doStartTag、doAfterBody、doEndTag方法既可。
若是標籤有屬性,那麼須要在標籤處理器中定義該屬性。
doStartTag方法是Tag接口定義的,在處理開始標籤時調用,返回Tag.EVAL_BODY_INCLUDE表示執行標籤body,返回Tag.SKIP_BODY表示不執行標籤body。
doEndTag方法是Tag接口定義的,在處理結束標籤時調用,返回Tag.EVAL_PAGE表示執行頁面的剩餘部分,返回Tag.SKIP_PAGE表示不執行頁面的剩餘部分。
doAfterBody是IterationTag接口定義的,在處理完標籤body後調用,返回IterationTag.EVAL_BODY_AGAIN表示再次執行標籤body,返回Tag.SKIP_BODY表示再也不執行標籤body。
執行順序爲,doStartTag->body->doAfterBody->doEndTag。
下面爲一個簡單的例子。
 
ClassicCustomTag.java
package com;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
 
public class ClassicCustomTag extends TagSupport {
 
private String permission;
 
public String getPermission() {
return permission;
}
 
public void setPermission(String permission) {
this.permission = permission;
}
 
@Override
public int doStartTag() throws JspException {
if ("query".equals(permission) || "add".equals(permission)
|| "delete".equals(permission) || "edit".equals(permission)) {
return SKIP_BODY;
} else {
return EVAL_BODY_INCLUDE;
}
}
 
@Override
public int doAfterBody() throws JspException {
return super.doAfterBody();
}
 
@Override
public int doEndTag() throws JspException {
return super.doEndTag();
}
}
 
test.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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<description>測試標籤庫</description>
<tlib-version>1.0</tlib-version>
<short-name>testTagLibrary</short-name>
<uri>http://test/tag-library.com</uri>
 
<tag>
<description>經典標籤庫</description>
<name>classic</name>
<tag-class>com.ClassicCustomTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<description>權限</description>
<name>permission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
</tag>
</taglib>
 
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://test/tag-library.com" prefix="test" %>
<html>
<head>
<title>index</title>
</head>
<body>
<div>
<button onclick="alert(this.innerHTML);" <test:classic permission="query">disabled title="沒有權限" </test:classic>>查詢
</button>
</div>
<div>
<button onclick="alert(this.innerHTML);" <test:classic permission="edit">disabled title="沒有權限" </test:classic>>編輯
</button>
</div>
 
<div>
<button onclick="alert(this.innerHTML);" <test:classic permission="export">disabled title="沒有權限" </test:classic>>導出
</button>
</div>
</body>
</html>
 
BodyTagSupport
若是標籤處理類須要和標籤body交互如讀取、重寫標籤body,那麼須要繼承BodyTagSupport類,BodyTagSupport繼承了TagSupport,所以能夠實現TagSupport的所有功能,所以能夠重寫doStartTag、doAfterBody、doEndTag,還能夠重寫getBodyContent、doInitBody。
此時doStartTag應該返回BodyTag.EVAL_BODY_BUFFERED,表示申請緩衝區,由setBodyContent方法獲得的BodyContent對象來處理標籤的body,不然getBodyContent返回null。body.getEnclosingWriter能夠返回一個JspWriter對象,用於將響應發送到客戶端。
doInitBody方法表示準備執行標籤body時調用。
執行順序爲,doStartTag->doInitBody->body->doAfterBody->doEndTag。
下面爲一個簡單的例子。
 
ClassicCustomBodyTag.java
package com;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
 
public class ClassicCustomBodyTag extends BodyTagSupport {
 
private String permission;
 
public String getPermission() {
return permission;
}
 
public void setPermission(String permission) {
this.permission = permission;
}
 
@Override
public int doStartTag() throws JspException {
if ("query".equals(permission) || "add".equals(permission)
|| "delete".equals(permission) || "edit".equals(permission)) {
return EVAL_BODY_BUFFERED;
} else {
return SKIP_BODY;
}
}
 
@Override
public void doInitBody() throws JspException {
 
}
 
@Override
public int doAfterBody() throws JspException {
try {
BodyContent body = getBodyContent();
System.out.println("body:" + body.getString());
if ("query".equals(permission)) {
body.getEnclosingWriter().print("查詢");
} else if ("add".equals(permission)) {
body.getEnclosingWriter().print("新增");
} else if ("delete".equals(permission)) {
body.getEnclosingWriter().print("刪除");
} else {
body.getEnclosingWriter().print("無");
}
} catch (Exception e) {
e.printStackTrace();
}
return super.doAfterBody();
}
 
@Override
public int doEndTag() throws JspException {
return super.doEndTag();
}
}
 
test.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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<description>測試標籤庫</description>
<tlib-version>1.0</tlib-version>
<short-name>testTagLibrary</short-name>
<uri>http://test/tag-library.com</uri>
 
<tag>
<description>經典標籤庫</description>
<name>classic</name>
<tag-class>com.ClassicCustomBodyTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<description>權限</description>
<name>permission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
</tag>
</taglib>
 
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://test/tag-library.com" prefix="test" %>
<html>
<head>
<title>index</title>
</head>
<body>
<div>
<button onclick="alert(this.innerHTML);"><test:classic permission="query">***</test:classic>
</button>
</div>
<div>
<button onclick="alert(this.innerHTML);"><test:classic permission="edit">***</test:classic>
</button>
</div>
</body>
</html>
 
JSP2.0以後
JSP2.0以後新增了SimpleTag接口,實現該接口的標籤處理器稱爲簡單標籤處理器。
簡單標籤處理器必須有無參構造函數。JSP容器調用setJspContext方法傳遞JspContext對象,從JspContext對象中能夠獲取JspWriter,用於將響應發送到客戶端。若是標籤有body,JSP容器調用setJspBody方法傳遞JspFragment對象,若是沒有body,就不會調用這個方法。最後JSP容器在標籤執行時調用doTag方法,而且只調用一次。
JspFragment有兩個方法,一個是獲取JspContext對象,一個是執行標籤body而且輸出到指定的Writer。
 
SimpleTagSupport
該類實現了SimpleTag接口,能夠方便開發。
下面是一個簡單的例子。
 
SimpleCustomTag.java
package com;
 
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
 
public class SimpleCustomTag extends SimpleTagSupport {
 
private String permission;
 
public String getPermission() {
return permission;
}
 
public void setPermission(String permission) {
this.permission = permission;
}
 
@Override
public void doTag() throws JspException, IOException {
try {
JspContext jspContext = getJspContext();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
OutputStreamWriter outputStreamWriter=new OutputStreamWriter(byteArrayOutputStream);
getJspBody().invoke(outputStreamWriter);
outputStreamWriter.close();
System.out.println("body:" + byteArrayOutputStream.toString());
if ("query".equals(permission)) {
jspContext.getOut().print("查詢");
} else if ("add".equals(permission)) {
jspContext.getOut().print("新增");
} else if ("delete".equals(permission)) {
jspContext.getOut().print("刪除");
} else {
jspContext.getOut().print("無");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
 
test.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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<description>測試標籤庫</description>
<tlib-version>1.0</tlib-version>
<short-name>testTagLibrary</short-name>
<uri>http://test/tag-library.com</uri>
 
<tag>
<description>簡單標籤庫</description>
<name>simple</name>
<tag-class>com.SimpleCustomTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<description>權限</description>
<name>permission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
</tag>
</taglib>
 
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://test/tag-library.com" prefix="test" %>
<html>
<head>
<title>index</title>
</head>
<body>
<div>
<button onclick="alert(this.innerHTML);"><test:simple permission="query">***</test:simple>
</button>
</div>
<div>
<button onclick="alert(this.innerHTML);"><test:simple permission="edit">***</test:simple>
</button>
</div>
</body>
</html>
 
自定義EL函數
函數必須是靜態方法。
下面爲一個簡單的例子。
 
CustomElFunction.java
package com;
 
public class CustomElFunction {
 
public static String print(String message) {
return "自定義打印:" + message;
}
}
 
test.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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<description>測試標籤庫</description>
<tlib-version>1.0</tlib-version>
<short-name>testTagLibrary</short-name>
<uri>http://test/tag-library.com</uri>
 
<function>
<name>customPrint</name>
<function-class>com.CustomElFunction</function-class>
<function-signature>java.lang.String print(java.lang.String)</function-signature>
</function>
</taglib>
 
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://test/tag-library.com" prefix="test" %>
<html>
<head>
<title>${test:customPrint("index.jsp")}</title>
</head>
<body>
</body>
</html>
相關文章
相關標籤/搜索