關于JSTL和EL的使用不再特别記錄,需要時單獨檢視。
此處記錄JSP的實用功能--自定義Tag
如果實作自定義Tag不需要處理Body的内容,隻需繼承SimpleTagSupport或者TagSupport類。
以SimpleTagSupport為例。實作一個可以通過角色控制顯示的Button
public class AuthorizationButton extends SimpleTagSupport {
private String role;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public void doTag() throws IOException {
JspContext context = getJspContext();
JspWriter writer = context.getOut();
String displayType = role.equals("admin") ? "block" : "none";
writer.println("<button type='button' class='btn btn-default' style='display:" + displayType + ";'>确認</button>");
}
}
在doTag方法中,根據屬性role的内容,決定輸出的button的display類型。
屬性的定義在标簽注冊時标明。
<?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>Simple Tag Examples</description>
<tlib-version>1.0</tlib-version>
<short-name>myTag</short-name>
<uri>http://example.com/tag</uri>
<tag>
<description>authorization button</description>
<name>authButton</name>
<tag-class>com.sample.servlet.AuthorizationButton</tag-class>
<body-content>empty</body-content>
<attribute>
<name>role</name>
<required>true</required>
</attribute>
</tag>
</taglib>
name 标簽名稱
tag-class 标簽處理的Java類
attribute 定義标簽屬性
uri 資源辨別符
bodycontent
參考文章:http://blog.csdn.net/aaa1117a8w5s6d/article/details/8157212
body-content的值有下面4種:
<xsd:enumeration value="tagdependent"/>
<xsd:enumeration value="JSP"/>
<xsd:enumeration value="empty"/>
<xsd:enumeration value="scriptless"/>
tagdependent:标簽體内容直接被寫入BodyContent,由自定義标簽類來進行處理,而不被JSP容器解釋,
如下:
<test:myList>
select name,age from users
</test:myList>
JSP:接受所有JSP文法,如定制的或内部的tag、scripts、靜态HTML、腳本元素、JSP指令和動作。如:
<my:test>
<%=request.getProtocol()%> // ②
</my:test>
具體可參考後面附源碼。
empty:空标記,即起始标記和結束标記之間沒有内容。
下面幾種寫法都是有效的,
<test:mytag />
<test:mytag uname="Tom" />
<test:mytag></test:mytag>
scriptless:接受文本、EL和JSP動作。
定義之後,就可以在JSP中引用該Tag
文法:<%@taglib uri="http://example.com/tag" prefix="cus"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@taglib uri="http://example.com/tag" prefix="cus"%>
<%@include file="./common/include.jsp"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>CustomizeTag</title>
</head>
<body>
<div class="container">
<div class="row" style="margin-top:10px">
<div class="col-md-1">
<cus:authButton role="admin"></cus:authButton>
<cus:authButton role="visitor"></cus:authButton>
</div>
</div>
</div>
</body>
</html>
當Role為admin時,生成的Button會被顯示
如果需要處理Body的内容,則應該繼承BodyTagSupport
TagSupport與BodyTagSupport的差別參考:(找到的文章都是轉發,原文已找不到出處)
1. TagSupport與BodyTagSupport的差別
TagSupport與BodyTagSupport的差別主要是标簽處理類是否需要與标簽體互動,如果不需要互動就用TagSupport,若需要互動就用BodyTagSupport。
互動就是标簽處理類是否要讀取标簽體的内容和改變标簽體傳回的内容。
用TagSupport實作的标簽,都可以用BodyTagSupport實作,因為BodyTagSupport繼承了TagSupport。
2. doStartTag(),doEndTag(),doAfterBody()
1)doStartTag()方法是遇到标簽開始時會呼叫的方法,其合法的傳回值有EVAL_BODY_INCLUDE和SKIP_BODY。EVAL_BODY_INCLUDE表示将顯示标簽間的文字,SKIP_BODY則不顯示标簽間的文字;
2)doEndTag()方法是在遇到标簽結束時呼叫的方法,其合法的傳回值是EVAL_PAGE和SKIP_PAGE。EVAL_PAGE表示處理完标簽後繼續執行以下的JSP網頁,SKIP_PAGE則不處理接下來的JSP網頁;
3)doAfterBody()方法是在顯示完标簽間的文字後呼叫的,其傳回值有EVAL_BODY_AGAIN和SKIP_BODY,EVAL_BODY_AGAIN會再顯示一次标簽間的文字,SKIP_BODY則繼續執行标簽處理的下一步。
EVAL_BODY_INCLUDE:把Body讀入存在的輸出流中,doStartTag()函數可用
EVAL_PAGE:繼續處理頁面,doEndTag()函數可用
SKIP_BODY:忽略對Body的處理,doStartTag()和doAfterBody()函數可用
SKIP_PAGE:忽略對餘下頁面的處理,doEndTag()函數可用
EVAL_BODY_TAG:已經廢止,由EVAL_BODY_BUFFERED取代
EVAL_BODY_BUFFERED:申請緩沖區,由setBodyContent()函數得到的BodyContent對象來處理tag的 body,如果類實作了BodyTag,那麼doStartTag()可用,否則非法。
調用順序:(圖檔參考:http://blog.csdn.net/zljjava/article/details/17420809)
假設,此處實作一個通過角色控制的Label,隻有角色為admin時才會生成Label并且輸出内容
public class AuthorizationLabel extends BodyTagSupport {
/**
* VersionUID
*/
private static final long serialVersionUID = 1L;
private String role;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public int doStartTag() throws JspException {
// 表示需要處理标簽體
return EVAL_BODY_BUFFERED;
}
@Override
public int doAfterBody() throws JspException {
// 取得标簽體對象
BodyContent body = getBodyContent();
// 取得标簽體的字元串内容
String content = body.getString();
JspWriter writer = bodyContent.getEnclosingWriter();
if (role.equals("admin")) {
try {
writer.println("<label style='font-size:25px;'>" + content + "</label>");
} catch (IOException e) {
e.printStackTrace();
}
}
// 結束對标簽體的處理
return SKIP_BODY;
}
}
在之前的tld檔案中添加這個Label的資訊
<tag>
<description>authorization label</description>
<name>authLabel</name>
<tag-class>com.sample.servlet.AuthorizationLabel</tag-class>
<body-content>tagdependent</body-content>
<attribute>
<name>role</name>
<required>true</required>
</attribute>
</tag>
使用執行個體:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@taglib uri="http://example.com/tag" prefix="cus"%>
<%@include file="./common/include.jsp"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>CustomizeTag</title>
</head>
<body>
<div class="container">
<div class="row" style="margin-top:10px">
<div class="col-md-2" style="text-align:right;">
<cus:authLabel role="admin">Hello world</cus:authLabel>
<cus:authLabel role="visitor">Hello world</cus:authLabel>
</div>
<div class="col-md-1">
<cus:authButton role="admin"></cus:authButton>
<cus:authButton role="visitor"></cus:authButton>
</div>
</div>
</div>
</body>
</html>
隻有第一個label會生成
以上兩個執行個體的執行效果圖:
以上例子僅作為功能Sample,實際項目中不建議這樣通過角色控制控件,個人認為用權限控制更好,例如在Shiro架構下配置指定權限,doTag方法中驗證權限。