?????接著上篇文章,我們上篇文章講到了jsp的基本原理以及和servlet的關(guān)系,還介紹了jsp的基本語(yǔ)法部分,本篇文章就繼續(xù)介紹余下的內(nèi)容。
- 編譯指令Page和include
- 基本的動(dòng)作指令
- 內(nèi)置對(duì)象
一、兩個(gè)編譯指令
?????Page指令顧名思義,操作當(dāng)前頁(yè)面的。首先我們要知道使用編譯指令的格式:<%@ page 屬性名="屬性值"%>,關(guān)于page的屬性有哪些,如下圖所示:
?????簡(jiǎn)單說(shuō)明一下,language指定的是本頁(yè)面使用的腳本語(yǔ)言,contentType指定了本頁(yè)面的類(lèi)型,有text/html,img/png等。import可以引入指定的包,默認(rèn)情況下已經(jīng)為我們引入了java.lang.,javax.servlet.jsp.,javax.servlet.http.*。所有在jsp頁(yè)面引入的包,都會(huì)對(duì)應(yīng)到servlet實(shí)例中。session指定當(dāng)前頁(yè)面是否支持會(huì)話(后面詳細(xì)介紹),errorPage指定了當(dāng)前頁(yè)面如果出現(xiàn)異常調(diào)用的頁(yè)面,如果沒(méi)有為當(dāng)前頁(yè)面指定errorPage頁(yè)面,就會(huì)直接拋出異常信息個(gè)瀏覽器(這是我們所不愿意看到的),isErrorPage指定了當(dāng)前頁(yè)面是否是錯(cuò)誤頁(yè)面,如果是,當(dāng)別的頁(yè)面出錯(cuò)的時(shí)候就會(huì)跳轉(zhuǎn)到此頁(yè)面,默認(rèn)為false。這么多的屬性,我們只要稍微有點(diǎn)印象,實(shí)際用的時(shí)候再過(guò)來(lái)參考即可。
?????我們說(shuō)jsp頁(yè)面中是不需要處理任何異常的,甚至是檢查類(lèi)異常都是不需要處理的。我們來(lái)看看為什么。從servlet類(lèi)的源代碼中找原因,因?yàn)檫@是本質(zhì)。
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title></title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write("\t\t");
for(int a=0;a<10;a++){
out.write("\n");
out.write("\t\t\t<p>Walker</p>\n");
out.write("\t\t");
}
out.write("\n");
out.write(" </body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
?????我們就看看這個(gè)用來(lái)響應(yīng)用戶請(qǐng)求的方法,_jspservice(),不知道大家看到?jīng)]有,整個(gè)輸出html頁(yè)面信息的代碼塊都被try....catch了,而看到catch捕捉的異常時(shí)異常機(jī)制的源頭Throwable ,所有的異常都是繼承自它的。而我們看到捕捉到異常之后所進(jìn)行的操作是,如果當(dāng)前對(duì)象不為空,就調(diào)用該對(duì)象的處理方法,處理方法就是判斷當(dāng)前頁(yè)面是否制定的errorPage頁(yè)面,如果沒(méi)有拋異常給瀏覽器,如果有,跳向錯(cuò)誤頁(yè)面。所以無(wú)論你jsp頁(yè)面會(huì)拋出什么異常,在被編譯到servlet實(shí)例中,已經(jīng)做了處理了,這就是為什么jsp頁(yè)面不需要處理異常的原因。
第二個(gè)指令是include指令,這是一個(gè)用來(lái)包含指定頁(yè)面的內(nèi)容的編譯指令,<%@include file="文件路徑"%>,我們來(lái)看一個(gè)例子:
<html>
<head>
<title></title>
</head>
<body>
<h1>這是當(dāng)前頁(yè)面</h1>
<%@include file="convert.jsp"%>
</body>
</html>
<html>
<head>
<title></title>
</head>
<body>
<h1>這是引入頁(yè)面</h1>
</body>
</html>
運(yùn)行結(jié)果的圖片就不貼了,從servlet實(shí)例中可以明顯看出,這一切都做了什么。
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title></title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write("\t\t<h1>這是當(dāng)前頁(yè)面</h1>\n");
out.write("\t\t");
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title></title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write("\t<h1>這是引入頁(yè)面</h1>\n");
out.write(" </body>\n");
out.write("</html>\n");
out.write("\n");
out.write(" </body>\n");
out.write("</html>\n");
?????不知道大家看出來(lái)了沒(méi)有,一個(gè)頁(yè)面里竟然包含了兩個(gè)html標(biāo)簽和title和body標(biāo)簽,可見(jiàn),這個(gè)編譯指令就是在編譯的時(shí)候?qū)⒁氲捻?yè)面中的全部信息直接插入在指定位置上。
二、基本的工作指令
?????第一個(gè)動(dòng)作指令是,forward指令,這個(gè)指令用來(lái)向另外的一個(gè)頁(yè)面進(jìn)行跳轉(zhuǎn)。用法如下:
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<h1>這是當(dāng)前頁(yè)面</h1>
<jsp:forward page="convert.jsp">
/*這是傳入?yún)?shù),暫時(shí)可以不用關(guān)心*/
<jsp:param name="key" value="v" />
</jsp:forward>
</body>
</html>
<html>
<head>
<title>convert.jsp</title>
</head>
<body>
<h1>這是引入頁(yè)面</h1>
</body>
</html>
?????從運(yùn)行結(jié)果上看,至少可以看出兩點(diǎn)。第一,地址欄上的地址依然是index頁(yè)面,也就是說(shuō)頁(yè)面并沒(méi)有跳走,第二,我們看原來(lái)index頁(yè)面的所有信息都被替換成convert頁(yè)面的內(nèi)容。由此我們可以推斷出,所謂的跳轉(zhuǎn)指令,其實(shí)并沒(méi)有完成跳轉(zhuǎn)的操作,只是將目標(biāo)頁(yè)面的所有信息全部替換當(dāng)前頁(yè)面,這和我們之前說(shuō)過(guò)的一個(gè)編譯指令很是類(lèi)似,他是include,我們應(yīng)該可以記得,include編譯指令是將目標(biāo)頁(yè)面中所有內(nèi)容替換到當(dāng)前頁(yè)面的某個(gè)位置,也就是替換了當(dāng)前頁(yè)面中的部分內(nèi)容。而可以將跳轉(zhuǎn)指令forward理解為替換了當(dāng)前頁(yè)面的所有內(nèi)容。
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title>1</title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write("\t\t<h1>這是當(dāng)前頁(yè)面</h1>\n");
out.write("\t\t");
if (true) {
_jspx_page_context.forward("convert.jsp" + "?" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("key", request.getCharacterEncoding())+ "=" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("v", request.getCharacterEncoding()));
return;
}
out.write("\n");
out.write(" </body>\n");
out.write("</html>\n");
?????從servlet源代碼中,我們可以看到,index中前面的代碼正常加載,當(dāng)加載到我們的跳轉(zhuǎn)指令的時(shí)候,它實(shí)際上構(gòu)建以個(gè)URL:convert.jsp?key=v,默默的請(qǐng)求了此頁(yè)面然后將返回的結(jié)果顯示在當(dāng)前的頁(yè)面中,其實(shí)就是去拿來(lái)目標(biāo)頁(yè)面中的內(nèi)容覆蓋當(dāng)前頁(yè)面,對(duì)于index頁(yè)面的一些請(qǐng)求參數(shù),不會(huì)丟失。(關(guān)于請(qǐng)求參數(shù)的接收,下文介紹)
?????第二個(gè)動(dòng)作指令,include指令,用來(lái)動(dòng)態(tài)引入外部文件到當(dāng)前頁(yè)面,和我們的include編譯指令相似,但是也有著顯著的區(qū)別。先看怎么使用:
<html>
<head>
<title>1</title>
</head>
<body>
<h1>這是當(dāng)前頁(yè)面</h1>
<jsp:include page="convert.jsp">
<jsp:param name="a" value="c" />
</jsp:include>
</body>
</html>
<html>
<head>
<title>2</title>
</head>
<body>
<h1>這是引入頁(yè)面</h1>
</body>
</html>
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title>1</title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write("\t\t<h1>這是當(dāng)前頁(yè)面</h1>\n");
out.write("\t\t\n");
out.write("\t\t");
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "convert.jsp" + "?" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("a", request.getCharacterEncoding())+ "=" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("c", request.getCharacterEncoding()), out, false);
out.write("\n");
out.write(" </body>\n");
out.write("</html>\n");
?????我們可以看到,動(dòng)作指令include實(shí)際上不想編譯指令include將目標(biāo)頁(yè)面的所有信息全部插入到指定位置,動(dòng)態(tài)include指令調(diào)用的是一個(gè)include方法,動(dòng)態(tài)的將目標(biāo)頁(yè)面的body部分的內(nèi)容拿過(guò)來(lái),并且還允許傳入?yún)?shù)。可能結(jié)果和編譯指令include一樣,但是內(nèi)部的實(shí)現(xiàn)確是截然不同的,各自有各自的適用場(chǎng)所。
?????第三個(gè)動(dòng)作指令,param,這是我們之前一直在使用的指令,只是一直沒(méi)有說(shuō)明。param指令一般都不會(huì)單獨(dú)使用,通常都是結(jié)合jsp:include,jsp:forward等使用。使用的格式如下:
<jsp:include page="convert.jsp">
<jsp:param name="a" value="c" />
</jsp:include>
?????name指定參數(shù)名,value指定參數(shù)數(shù)值。至于怎么獲取,我們?cè)诮榻Brequest對(duì)象的時(shí)候加以說(shuō)明。request對(duì)象就是一個(gè)專(zhuān)門(mén)用于處理用戶請(qǐng)求的對(duì)象,所以所有的參數(shù)傳遞都是可以使用這個(gè)對(duì)象進(jìn)行接收的。還有一些動(dòng)作指令牽扯到j(luò)avabean知識(shí),暫時(shí)不說(shuō)。
三、JSP內(nèi)置對(duì)象
?????我們打開(kāi)任意的servlet源代碼,可以看到在用于響應(yīng)用戶請(qǐng)求的方法_jspservice();的頭部有一些成員變量的定義和初始化??矗?/p>
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response){
.....
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
.......
}
?????接下來(lái)我們會(huì)詳細(xì)介紹這些對(duì)象的含義及其具體的操作。由于篇幅限制,未完待續(xù)。。