在常用的javaweb開發中,jsp一般不會寫入java代碼,但是我們可以用jsp的標籤技術來實現將java代碼替換為標籤在網頁中表示。
標籤技術分為以下幾種:
1.jsp標籤。
2.EL表達式。
3.JSTL標籤庫。
4.自定義標籤技術。
一,jsp標籤
原生標籤,用的不多,主要用以下幾點。
1、標籤
標籤用於把另外一個資源的輸出內容插入進當前JSP頁面的輸出內容之中,這種在JSP頁面執行時的引入方式稱之為動態引入。
語法:
page屬性用於指定被引入資源的相對路徑,它也可以通過執行一個表達式來獲得。
flush屬性指定在插入其他資源的輸出內容時,是否先將當前JSP頁面的已輸出的內容刷新到客戶端。
與include指令的比較:
標籤是動態引入, 標籤涉及到的2個JSP頁面會被翻譯成2個servlet,這2個servlet的內容在執行時進行合併。 而include指令是靜態引入,涉及到的2個JSP頁面會被翻譯成一個servlet,其內容是在源文件級別進行合併。不管是標籤,還是include指令,它們都會把兩個JSP頁面內容合併輸出,所以這兩個頁面不要出現重複的HTML全局架構標籤,否則輸出給客戶端的內容將會是一個格式混亂的HTML文檔。
標籤用於把請求轉發給另外一個資源。
語法:
page屬性用於指定請求轉發到的資源的相對路徑,它也可以通過執行一個表達式來獲得。
標籤
當使用和標籤引入或將請求轉發給其它資源時,可以使用標籤向這個資源傳遞參數。
語法1:
語法2:
標籤的name屬性用於指定參數名,value屬性用於指定參數值。在和標籤中可以使用多個標籤來傳遞多個參數。
二、EL表達式
EL 全名為Expression Language。EL表達式最初出現的目的是為了取代jsp頁面中的jsp腳本表達式,但是隨著el的發展el的功能已經不限於此了。
EL表達式是JSP 2.0(JavaEE1.4)規範中的一門技術 。因此,若想正確解析EL表達式,需使用支持Servlet2.4/JSP2.0技術的WEB服務器。
注意:如果有些Tomcat服務器不能使用EL表達式,可以採取的方法是:
(1)升級成tomcat6
(2)在JSP中加入
EL表達式主要有下面四種功能:獲取數據、執行運算、獲取常用開發對象和調用java方法。
1、獲取數據
使用中括號的地方通常都可以使用點號替代,有兩種情況除外:中括號中是數字或者中括號中包含特殊字符(-.)的情況。
注意:在中括號中如果不用雙引號引起來則是變量,先找變量的值再拿變量的值使用。如果用雙引號則是常量,直接使用常量的值。它只能獲取數據,不要試圖通過EL表達式來設置數據。
(1) 獲取常量
字符串/數字/布爾類型,直接寫在el表達式中,el直接進行輸出。
(2) 獲取域中的變量
如果el中寫的是一個變量的名,則el會調用pageContext的findAttribute方法。在四大作用域中以給定的名字找對應的屬性值,找到後進行輸出,如果四個域中都找不到,什麼都不輸出。
(3) 獲取數組中的數據
(4) 獲取集合中的數據
(5) 獲取Map中的數據
(6) 獲取javabean的屬性
示例如下:
獲取javabean的屬性
Person p = new Person();
p.setName("Lilei");
p.setAge(17);
pageContext.setAttribute("p",p);
%>
${p.name }${p.age } ${p.name }
獲取Map中的數據
Map
map.put("name","張三");
map.put("age","17");
map.put("gender","男");
map.put("addr","中國");
pageContext.setAttribute("map",map);
pageContext.setAttribute("name","age");
%>
${map["name"] }${map["addr"] }
${map.gender }${map.age }
獲取集合中的數據
List
list.add("甄嬛");
list.add("安陵容");
list.add("華妃");
pageContext.setAttribute("list",list);
%>
${list[2] }
獲取數組數據
String [] names = {"容嬤嬤","紫薇","金鎖","小燕子"};
pageContext.setAttribute("names",names);
%>
${names[2]}
獲取域中的變量數據
String name = "李四";
pageContext.setAttribute("name",name);
%>
${name }
獲取常量數據
${"阿薩德發射點發" } ${199 } ${true }
2、執行運算
EL中支持的運算類型:算術運算、邏輯運算、比較運算、三元運算符、empty運算符。
算術運算:如果有非數字參與算數運算,el表達式會試圖將非數字轉換為數字後參與運算。
empty運算符:判斷一個對象是否為null或字符串是否為空字符串或集合內容是否為空或域中是否沒有任何屬性。
示例:
empty 運算符 :
String str = "aaaa";
pageContext.setAttribute("str",str);
List list = new ArrayList();
list.add("");
pageContext.setAttribute("list",list);
%>
${empty str }
${empty list}
${empty pageScope }
三元運算
${10>9? "yes" : "no" }
邏輯運算
&& and
|| or
! not
${not (3>2 and 1<2 or 10>3) }
比較運算
> gt
< lt
>= ge
<= le
!= ne
==eq
${1 eq 1 } ${3 ge 2 } ${5+3 lt 3 }
算術運算
${1+1 }
${1-2 }
${1+"2" }
3、獲取常用開發對象
EL中內置了11個內置對象,這些對象EL內置的,不需要提前定義就可以直接在EL中使用。
pageContext -- 有了它可以很方便的獲取jsp頁面中的9大隱式對象
pageScope -- page域中屬性組成的Map
requestScope -- request域中屬性組成的Map
sessionScope -- session域中屬性組成的Map
applicationScope --application域中屬性組成的Map
param -- 所有請求參數組成的Map
paramValues -- 所有請求參數組成的Map
header -- 所有請求頭組成的Map
headerValues -- 所有請求頭組成的Map
cookie -- 所有cookie信息組成的Map
initParam -- 所有web應用的初始化參數組成Map
示例:
pageContext.setAttribute("name","wang");
request.setAttribute("name","li");
%>
${requestScope.name}
${param.name } ${paramValues.like[2] }${header["Accept-Language"] }
${cookie.JSESSIONID.name }${cookie.JSESSIONID.value }
${initParam.name2 }
4、調用java方法
EL表達式允許用戶開發自定義EL函數,以在JSP頁面中通過EL表達式調用Java類的方法。一般來說,EL自定義函數開發與應用包括以下三個步驟:
編寫一個Java類的靜態方法。
編寫標籤庫描述符(tld)文件,在tld文件中描述自定義函數。
在JSP頁面中導入和使用自定義函數。
編寫完標籤庫描述文件後,需要將它放置到
三、JSTL標籤庫
JavaServer Pages Standard Tag Library是由JCP(Java Community Process)指定的標準,是提供給 Java Web 開發人員的一個標準通用的標籤函數庫,和 EL 配合來取代傳統直接在頁面上嵌入 Java 程序(Scripting)的做法,以提高程序可讀性、維護性和方便性。
JSTL標籤庫主要包括五類:
核心標籤庫 (core) — c
國際化標籤 fmt
數據庫標籤 sql
XML標籤 xml
JSTL函數(EL函數) el
1、核心標籤庫
(1)
標籤用於輸出一段文本內容到pageContext對象當前保存的“out”對象中。
示例:
HTML轉義輸出
${fn:escapeXml(' ') }
輸出默認值
String addr = "西二旗";
//pageContext.setAttribute("addr",addr);
%>
${addr == null?"北京" : addr }
輸出變量
String name = "無雙";
pageContext.setAttribute("name",name);
%>
${name }
輸出常量
${"啦啦啦啦" }
(2)
標籤用於把某一個對象存在指定的域範圍內,或者設置Web域中的java.util.Map類型的屬性對象或JavaBean類型的屬性對象的屬性。
示例:
修改域中的JavaBean的屬性的值
Person p = new Person();
pageContext.setAttribute("p",p);
%>
${p.name }
設置或修改域中的Map的值
Map map = new HashMap();
pageContext.setAttribute("map",map);
%>
${map.cellphone }
設置或修改域中的屬性值
${name }
(3)
標籤用於刪除各種Web域中的屬性。
其語法格式如下:
[scope="{page|request|session|application}"] /> 示例:
pageContext.setAttribute("name","藍精靈");
request.setAttribute("name","小丸子");
session.setAttribute("name","機器貓");
application.setAttribute("name","蠟筆小新");
%>
${name }
(4)
標籤用於捕獲嵌套在標籤體中的內容拋出的異常。
其語法格式如下:
var屬性用於標識
**示例:**
異常 myex.getMessage:
異常 myex.getCause:
異常 myex.getStackTrace:
(5)
標籤可以構造簡單的“if-then”結構的條件表達式,它沒有實現else的功能,如果想要實現else只能重新寫一遍判斷。
示例:
確實是這樣的....
你確定嗎?
(6)
標籤用於指定多個條件選擇的組合邊界,它必須與和標籤一起使用。使用,和三個標籤,可以構造類似 “if-else if-else” 的複雜條件判斷結構。
示例:
對不起,沒有符合您要求的記錄。
符合您要求的記錄共有${count}條.
(7)
標籤用於對一個集合對象中的元素進行循環迭代操作,或者按指定的次數重複迭代執行標籤體中的內容。
示例:
實驗:遍歷10到100的偶數,如果數字所在的位置是3的倍數,顯示成紅色
${i }
${i }
循環執行指定的內容若干次
${i },
遍歷Map中的數據
Map map = new LinkedHashMap();
map.put("name","曹操");
map.put("age","59");
map.put("wife","小喬");
map.put("gender","男");
pageContext.setAttribute("map",map);
%>
${entry.key }:${entry.value }
遍歷集合中的數據
List list = new ArrayList();
list.add("美國");
list.add("中國");
list.add("俄羅斯");
list.add("印度");
list.add("巴西");
pageContext.setAttribute("list",list);
%>
${c }
遍歷數組中的數據
String [] city = {"北京","上海","廣州","鐵嶺","葫蘆島"};
pageContext.setAttribute("city",city);
%>
${c }
(8)
用來瀏覽一字符串中所有的成員,其成員是由定義符號所分隔的。
示例:
${str }
(9)
標籤用於實現請求重定向。
示例:
(10)
示例:
from xxxxx....
xxxx
yyyy
${p }
zzzz
(11)
標籤用於在JSP頁面中構造一個URL地址,其主要目的是實現URL重寫。URL重寫就是將會話標識號以參數形式附加在URL地址後面 。
示例:
String url = response.encodeURL(request.getContextPath()+"/index.jsp");
%>
(12) 標籤
在JSP頁面進行URL的相關操作時,經常要在URL地址後面附加一些參數。標籤可以嵌套在、或標籤內,為這些標籤所使用的URL地址附加參數。
標籤在為一個URL地址附加參數時,將自動對參數值進行URL編碼,例如,如果傳遞的參數值為“中國”,則將其轉換為“%d6%d0%b9%fa”後再附加到URL地址後面,這也就是使用標籤的最大好處。
示例:
1
四、自定義標籤技術
自定義標籤技術分為傳統標籤和簡單標籤兩種。
1、傳統標籤
(1)創建自定義標籤的步驟
使用自定義標籤移除jsp頁面中的java代碼,只需要完成以下兩個步驟:
編寫一個實現Tag接口的Java類(標籤處理器類)。
編寫標籤庫描述符(tld)文件,在tld文件中對標籤處理器類描述成一個標籤。
在JSP頁面中引入tld文件,就可以在jsp頁面中使用自定義標籤了。
(2)Tag接口的執行流程
JSP引擎將遇到自定義標籤時,首先創建標籤處理器類的實例對象,然後按照JSP規範定義的通信規則依次調用它的方法。
1、public void setPageContext(PageContext pc), JSP引擎實例化標籤處理器後,將調用setPageContext方法將JSP頁面的pageContext對象傳遞給標籤處理器,標籤處理器以後可以通過這個pageContext對象與JSP頁面進行通信。
2、public void setParent(Tag t),setPageContext方法執行完後,WEB容器接著調用的setParent方法將當前標籤的父標籤傳遞給當前標籤處理器,如果當前標籤沒有父標籤,則傳遞給setParent方法的參數值為null。
3、public int doStartTag(),調用了setPageContext方法和setParent方法之後,WEB容器執行到自定義標籤的開始標記時,就會調用標籤處理器的doStartTag方法。
4、public int doEndTag(),WEB容器執行完自定義標籤的標籤體後,就會接著去執行自定義標籤的結束標記,此時,WEB容器會去調用標籤處理器的doEndTag方法。
5、public void release(),通常WEB容器執行完自定義標籤後,標籤處理器會駐留在內存中,為其它請求服務器,直至停止web應用時,web容器才會調用release方法。
doStartTag 和 doEndTag方法來分別處理發現開始標籤和發現結束標籤時的代碼。在doStartTag可以通過返回值來控制標籤體是否允許執行,在doEndTag方法裡可以通過返回值控制標籤之後的剩餘頁面是否允許執行。
傳統標籤的這種開發方式,需要我們分析發現開始標籤和發現結束標籤時都需要執行什麼代碼,還需要分析到底要返回什麼樣的標籤體控制程序執行,相對來說相當的繁瑣,因此有了下面的簡單標籤。
示例(利用傳統標籤顯示IP地址):
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
public class ShowIpTag implements Tag {
private PageContext pc = null;
public int doEndTag() throws JspException {
//EVAL_PAGE -- 結束標籤之後的剩餘頁面需要去執行
//SKIP_PAGE -- 結束標籤之後的剩餘頁面不要去執行
return 0;
}
public int doStartTag() throws JspException {
try {
String ip = pc.getRequest().getRemoteAddr();
pc.getOut().write(ip);
} catch (IOException e) {
e.printStackTrace();
}
//Eval_Body_Include -- 開始標籤之後的標籤體需要執行
//Skip_Body -- 開始標籤之後的標籤體不需要執行
return 0;
}
public Tag getParent() {
return null;
}
public void release() {
}
public void setPageContext(PageContext pc) {
this.pc = pc;
}
public void setParent(Tag t) {
}
}
(3)自定義標籤應該具有的功能
控制jsp頁面某一部分內容是否執行。
控制整個jsp頁面是否執行。
控制jsp頁面內容重複執行。
修改jsp頁面內容輸出。 HTML轉義
例一:控制標籤體內容是否執行
doStartTag
EVAL_BODY_INCLUDE 執行標籤內容
SKIP_BODY 跳過標籤內容
Tld配置
例二:控制標籤後的jsp頁面是否執行
doEndTag
EVAL_PAGE 執行標籤後的頁面內容
SKIP_PAGE 跳過標籤後的頁面內容
Tld配置
例三:控制jsp頁面內容重複執行
doStartTag
EVAL_BODY_INCLUDE 執行標籤內容
doAfterBody
EVAL_BODY_AGAIN 重複執行標籤內容
SKIP_BODY 跳過標籤內容
doAfterBody代碼
times--;
if (times > 0) {
return EVAL_BODY_AGAIN;
} else {
return SKIP_BODY;
}
例四:修改標籤體內容輸出
將標籤體內容大寫輸出
MyTag4 extends BodyTagSupport
doStartTag
EVAL_BODY_BUFFERED
doEndTag
String content = getBodyContent().getString();
pageContext.getOut().write(…);
(4)添加標籤屬性
自定義標籤可以定義一個或多個屬性,這樣,在JSP頁面中應用自定義標籤時就可以設置這些屬性的值,通過這些屬性為標籤處理器傳遞參數信息,從而提高標籤的靈活性和複用性。
要想讓一個自定義標籤具有屬性,通常需要完成兩個任務:
在標籤處理器中編寫每個屬性對應的setter方法。
在TLD文件中描術標籤的屬性。
為自定義標籤定義屬性時,每個屬性都必須按照JavaBean的屬性命名方式,在標籤處理器中定義屬性名對應的setter方法,用來接收JSP頁面調用自定義標籤時傳遞進來的屬性值。 例如屬性url,在標籤處理器類中就要定義相應的setUrl(String url)方法。在標籤處理器中定義相應的set方法後,JSP引擎在解析執行開始標籤前,也就是調用doStartTag方法前,會調用set屬性方法,為標籤設置屬性。
通過成員變量 和 setter方法設置屬性 times
Tld配置
… ...
2、簡單標籤
由於傳統標籤使用三個標籤接口來完成不同的功能,顯得過於繁瑣,不利於標籤技術的推廣, SUN公司為降低標籤技術的學習難度,在JSP 2.0中定義了一個更為簡單、便於編寫和調用的SimpleTag接口來實現標籤的功能。實現SimpleTag接口的標籤通常稱為簡單標籤。簡單標籤共定義了5個方法:
setJspContext方法
setParent
getParent方法
setJspBody方法
doTag方法
(1)簡單標籤的方法介紹
setJspContext方法
用於把JSP頁面的pageContext對象傳遞給標籤處理器對象。
setParent方法
用於把父標籤處理器對象傳遞給當前標籤處理器對象。
getParent方法
用於獲得當前標籤的父標籤處理器對象。
setJspBody方法
用於把代表標籤體的JspFragment對象傳遞給標籤處理器對象。
doTag方法
用於完成所有的標籤邏輯,包括輸出、迭代、修改標籤體內容等。在doTag方法中可以拋出。
javax.servlet.jsp.SkipPageException異常,用於通知WEB容器不再執行JSP頁面中位於結束標記後面的內容,這等效於在傳統標籤的doEndTag方法中返回Tag.SKIP_PAGE常量的情況。
(2)SimpleTag接口方法的執行順序
當web容器開始執行標籤時,會調用如下方法完成標籤的初始化:
WEB容器調用標籤處理器對象的setJspContext方法,將代表JSP頁面的pageContext對象傳遞給標籤處理器對象。
WEB容器調用標籤處理器對象的setParent方法,將父標籤處理器對象傳遞給這個標籤處理器對象。注意,只有在標籤存在父標籤的情況下,WEB容器才會調用這個方法。
如果調用標籤時設置了屬性,容器將調用每個屬性對應的setter方法把屬性值傳遞給標籤處理器對象。如果標籤的屬性值是EL表達式或腳本表達式,則WEB容器首先計算表達式的值,然後把值傳遞給標籤處理器對象。
如果簡單標籤有標籤體,容器將調用setJspBody方法把代表標籤體的JspFragment對象傳遞進來。
執行標籤時:
容器調用標籤處理器的doTag()方法,開發人員在方法體內通過操作JspFragment對象,就可以實現是否執行、迭代、修改標籤體的目的。
(3)JspFragment類
javax.servlet.jsp.tagext.JspFragment類是在JSP2.0中定義的,它的實例對象代表JSP頁面中的一段符合JSP語法規範的JSP片段,這段JSP片段中不能包含JSP腳本元素。WEB容器在處理簡單標籤的標籤體時,會把標籤體內容用一個JspFragment對象表示,並調用標籤處理器對象的setJspBody方法把JspFragment對象傳遞給標籤處理器對象。JspFragment類中只定義了兩個方法,如下所示:
getJspContext方法
用於返回代表調用頁面的JspContext對象. —- pageContext
public abstract void invoke(java.io.Writer out) – 輸出標籤體內容
用於執行JspFragment對象所代表的JSP代碼片段。參數out用於指定將JspFragment對象的執行結果寫入到哪個輸出流對象中,如果傳遞給參數out的值為null,則將執行結果寫入到JspContext.getOut()方法返回的輸出流對象中。(簡而言之,可以理解為寫給瀏覽器)。
JspFragment.invoke方法是JspFragment最重要的方法,利用這個方法可以控制是否執行和輸出標籤體的內容、是否迭代執行標籤體的內容或對標籤體的執行結果進行修改後再輸出。例如:
在標籤處理器中如果沒有調用JspFragment.invoke方法,其結果就相當於忽略標籤體內容;
在標籤處理器中重複調用JspFragment.invoke方法,則標籤體內容將會被重複執行;
若想在標籤處理器中修改標籤體內容,只需在調用invoke方法時指定一個可取出結果數據的輸出流對象(例如StringWriter),讓標籤體的執行結果輸出到該輸出流對象中,然後從該輸出流對象中取出數據進行修改後再輸出到目標設備,即可達到修改標籤體的目的。
(4)簡單標籤的四個功能示例
例一:控制標籤體內容是否執行
doTag
JspFragment jspFragment = getJspBody();
jspFragment.invoke(getJspContext().getOut());
jspFragment.invoke(null);
Tld配置
例二:控制標籤後的jsp頁面是否執行
doTag
throw new SkipPageException()
Tld配置
例三:控制jsp頁面內容重複執行
doTag
JspFragment fragment = getJspBody();
for (int i = 0; i < times; i++) {
fragment.invoke(null);
}
Tld配置
例四:修改jsp頁面內容輸出
將標籤體內容大寫輸出
doTag
JspFragment fragment = getJspBody();
StringWriter writer = new StringWriter();
fragment.invoke(writer);
getJspContext().getOut().println(
writer.getBuffer().toString().toUpperCase());
3、 tag接口的繼承結構
閱讀更多 南京菜菜工作室 的文章