JSP是Servlet的擴充,在沒有JSP之前,就已經出現了Servlet技術。Servlet是利用輸出資料流動態產生HTML頁面,包括每一個HTML標籤和每個在HTML頁面中出現的內容。
由於包括大量的HTML標籤、大量的靜態文本及格式等,導致Servlet的開發效率極為低下。所有的表現邏輯,包括布局、色彩及映像等,都必須耦合在Java代碼中,這的確讓人不勝其煩。JSP的出現彌補了這種不足,JSP通過在標準的HTML頁面中插入Java代碼,其靜態部分無須Java程式控制,只有那些需要從資料庫讀取並根據程式動態產生資訊時,才使用Java指令碼控制。
從表面上看,JSP頁面已經不再需要Java類,似乎完全脫離了Java物件導向的特徵。事實上,JSP是Servlet的一種特殊形式,每個JSP頁面就是一個Servlet執行個體——JSP頁面由系統編譯成Servlet,Servlet再負責響應使用者請求。JSP其實也是Servlet的一種簡化,使用JSP時,其實還是使用Servlet,因為Web應用中的每個JSP頁面都會由Servlet容器產生對應的Servlet。對於Tomcat而言,JSP頁面產生的Servlet放在work路徑對應的Web應用下。
看下面一個簡單的JSP頁面:
<!-- 表明此為一個JSP頁面 -->
<%@ page contentType="text/html; charset=gb2312" language="java" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>第一個JSP頁面</TITLE>
</HEAD>
<BODY>
<!-- 下面是Java指令碼 Scriptlet-->
<%for(int i = 0 ; i < 10; i++)
{
out.println(i);
%>
<br>
<%}%>
</BODY>
</HTML>
當啟動Tomcat之後,可以在Tomcat的Catalinalocalhostjsptestorgapachejsp目錄下找到如下檔案(假如Web應用程式名稱為jsptest,上面JSP頁的名為test1.jsp):test1_jsp.java和test1_jsp.class。這兩個檔案都是Tomcat產生的,Tomcat根據JSP頁面產生對應Servlet的Java檔案及class檔案。
下面是test1_jsp.java檔案的原始碼,這是一個特殊的Java類,是一個Servlet類:
//JSP頁面經過Tomcat編譯後預設的包(不同的servlet容器供應商產生的servlet檔案是不同的)
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
//繼承HttpJspBase類,該類其實是個HttpServlet的子類(jasper是tomcat的jsp engine)
public final class test1_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent
{
private static java.util.Vector _jspx_dependants;
public java.util.List getDependants() {
return _jspx_dependants;
}
//用於響應使用者的方法
public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException, ServletException
{ //built-in objects(variavles) are created here.
//獲得頁面輸出資料流
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
//獲得頁面輸出資料流
JspWriter out = null; //not PrintWriter. JspWriter is buffered defautly.
Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
//開始產生響應
try
{
_jspxFactory = JspFactory.getDefaultFactory();
//設定輸出的頁面格式
response.setContentType("text/html; charset=gb2312");
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("rn");
//下面輸出HTML標籤
out.write("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0
Transitional//EN">rn");
out.write("<HTML>rn");
out.write("<HEAD>rn");
out.write("<TITLE>first Jsp</TITLE>rn");
out.write("</HEAD>rn");
out.write("<BODY>rn");
//頁面中的迴圈,在此處迴圈輸出
for(int i = 0 ; i < 10; i++)
{
out.println(i);
out.write("rn");
out.write("<br>rn");
}
out.write("rn");
out.write("</BODY>rn");
out.write("</HTML>rn");
out.write("rn");
}
catch (Throwable t)
{
if (!(t instanceof SkipPageException))
{
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (_jspx_page_context != null) _jspx_page_context.handle
PageException(t);
}
}
finally
{
if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_
page_context);
}
}
}
根據圖2.1的執行效果,再次對比test1.jsp和test1_jsp.java檔案,可得到一個結論:該JSP頁面中的每個字元都由test1_jsp.java檔案的輸出資料流產生。
根據上面的JSP頁面工作原理圖,可以得到如下四個結論:
— JSP檔案必須在JSP伺服器內運行。
— JSP檔案必鬚生成Servlet才能執行。
— 每個JSP頁面的第一個訪問者速度很慢,因為必須等待JSP編譯成Servlet。
— JSP頁面的訪問者無須安裝任何用戶端,甚至不需要可以運行Java的運行環境,因為JSP頁面輸送到用戶端的是標準HTML頁面。
JSP和Servlet會有如下轉換:
- JSP頁面的靜態內容、JSP指令碼都會轉換成Servlet的xxxService()方法,類似於自行建立Servlet時service()方法。
- JSP聲明部分,轉換成Servlet的成員部分。所有JSP聲明部分可以使用private,protected,public,static等修飾符,其他地方則不行。
- JSP的輸出運算式(<%= ..%>部分),輸出運算式會轉換成Servlet的xxxService()方法裡的輸出語句。
- 九個內建對象要麼是xxxService()方法的形參,要麼是該方法的局部變數,所以九個內建對象只能在JSP指令碼和輸出運算式中使用。// 不能在jsp Declaration中使用