目錄
前言:
Servlet爲創建基於web的應用程序提供了組件、獨立於開發的平臺,可以不受CGI程序(公共網關接口(Common Gateway Interface,CGI))的性能限制。Servlet有權限訪問所有的javaAPI,包括訪問企業級數據庫的JDBC API。
一、Servlet簡介
Java Servlet是運行在Web服務器或應用服務器上的程序,它是作爲來自Web瀏覽器或其他HTTP客戶端的請求和HTTP服務器上的數據庫或應用程序之間的中間層。
使用Servlet,你可以收集來自網頁表單的用戶輸入,呈現來自數據庫或其他源的記錄,還可以動態創建網頁。
Java Servlet通常情況下與使用CGI實現的程序可以達到異曲同工的效果。但是相比CGI,Servlet有以下優勢:
-
性能明顯更好。
-
Servlet 在 Web 服務器的地址空間內執行。這樣它就沒有必要再創建一個單獨的進程來處理每個客戶端請求。
-
Servlet 是獨立於平臺的,因爲它們是用 Java 編寫的。
-
服務器上的 Java 安全管理器執行了一系列限制,以保護服務器計算機上的資源。因此,Servlet 是可信的。
-
Java 類庫的全部功能對 Servlet 來說都是可用的。它可以通過 sockets 和 RMI 機制與 applets、數據庫或其他軟件進行交互
1、Servlet框架
2、Servlet任務
-
讀取客戶端(瀏覽器)發送的顯式的數據。這包括網頁上的 HTML 表單,或者也可以是來自 applet 或自定義的 HTTP 客戶端程序的表單。
-
讀取客戶端(瀏覽器)發送的隱式的 HTTP 請求數據。這包括 cookies、媒體類型和瀏覽器能理解的壓縮格式等等。
-
處理數據並生成結果。這個過程可能需要訪問數據庫,執行 RMI 或 CORBA 調用,調用 Web 服務,或者直接計算得出對應的響應。
-
發送顯式的數據(即文檔)到客戶端(瀏覽器)。該文檔的格式可以是多種多樣的,包括文本文件(HTML 或 XML)、二進制文件(GIF 圖像)、Excel 等。
-
發送隱式的 HTTP 響應到客戶端(瀏覽器)。這包括告訴瀏覽器或其他客戶端被返回的文檔類型(例如 HTML),設置 cookies 和緩存參數,以及其他類似的任務。
3、Servlet包
Java Servlet是運行在帶有支持Java Servlet規範的解釋器的web服務器上的java類。
Servlet可以使用java.servlet和javax.servlet.http包創建,它是Java企業級的標準組成部分,Java企業版是支持大型開發項目的Java類庫的擴展版本。
這些類實現Java Servlet和JSP規範,下列教程爲Java Servlet2.5和JSP2.1。
Java Servlet就像任何其他的java類一樣已經被創建和編譯。在你安裝Servlet包並把它們添加到你的計算機上的Classpath類路徑中之後,你就可以通過JDK的java編譯器或任何其他編譯器來編譯Servlet。
二、生命週期
Servlet生命週期可被定義爲從創建直到毀滅的整個過程:
-
Servlet 通過調用 init () 方法進行初始化。
-
Servlet 調用 service() 方法來處理客戶端的請求。
-
Servlet 通過調用 destroy() 方法終止(結束)。
-
最後,Servlet 是由 JVM 的垃圾回收器進行垃圾回收的。
1、init()方法
init方法被設計成只調用一次。它在第一次創建Servlet時被調用,在後續每次用戶請求時不再調用,因此,它是用於一次性初始化,就像Appelt的init方法一樣。
Servlet創建用戶第一次調用對應於該Servlet的URL時,你可以指定Servlet在服務器第一次啓動時被加載。
當用戶調用一個Servlet時,就會創建一個Servlet實例,每一個用戶請求都會產生一個新的線程,適當的時候一角給doGet或doPost方法。init()方法簡單地創建或加載一些數據,這些數據被用於Servlet的整個生命週期。
init方法的定義如下:
public void init() throws ServletException {
// 初始化代碼...
}
2、service()方法
service()方法是執行實際任務的主要方法。Servlet容器(即Web服務器)調用service()方法來處理來自客戶端(瀏覽器)的請求,並把格式化的響應寫回給客戶端。
每次服務器接收到一個Servlet請求時,服務器會產生一個新的線程並調用服務。service()方法檢查HTTP請求類型(GET、POST、PUT、DELETE等),並在適當是時候調用doGet、doPost、doPut、doDelete等方法。
public void service(ServletRequest request,
ServletResponse response)
throws ServletException, IOException{
}
service()方法由容器調用,service方法在適當的時候調用odGet、doPost、doPut、doDelete等方法。所以,你不用對service方法做任何動作,只需要根據來自客戶端類型來重寫doGet()或doPost()即可。
doGet()和doPost()方法是每次服務請求中最常用的方法。
3、doGet()方法
GET請求來自於一個URL的正常請求,或者來自於一個未指定METHOD的HTML表單,它由doGet()方法處理。
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet 代碼
}
4、doPost()方法
POST請求來自於一個特別指定了METHOD爲POST的HTML表單,它由doPost()方法處理。
public void doPost(HttpServletResquest requers,HttpServletResponse response)
throws ServletException,IOException{
//Servlet代碼
}
5、destroy()方法
destroy()方法只會被調用一次,在Servlet生命週期結束時被調用。destroy()方法可以讓你的Servlet關閉數據庫連接、停止後臺線程、把Cookie列表或點擊計數器寫入到磁盤,並執行其他類似的清理活動。
在調用destroy()方法之後,servlet對象被標記爲垃圾回收。
public void destroy(){
//終止化代碼
}
6、架構圖:
Servlet生命週期方案:
-
第一個到達服務器的 HTTP 請求被委派到 Servlet 容器。
-
Servlet 容器在調用 service() 方法之前加載 Servlet。
-
然後 Servlet 容器處理由多個線程產生的多個請求,每個線程執行一個單一的 Servlet 實例的 service() 方法。
三、Servlet實例
Servlet是服務HTTP請求並實現javax.servlet.Servlet接口的java類。Web應用程序開發人員通常編寫Servlet來擴展javax.servlet.http.HttpServlet,並實現Servlet接口的抽象類專門用來處理HTTP請求。
1、Hello World實例:
//導入必須的java庫
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
//擴展HttpServlet類
public class HelloWorld extends HttpServlet{
private String message;
public void init()throws ServletException
{
//執行必需的初始化
message = "Hello World";
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException,IOException
{
//設置響應內容類型
response.setContentType("text/html");
//實際的邏輯是在這裏
PrintWriter out = response.getWriter();
out.println("<h1>" + message +"</h1>");
}
public void destroy()
{
//什麼也不做
}
}
2、Servlet部署
我們找到<Tomcat-installation-directory>/webapps/ROOT/WEB-INF/的web.xml文件中創建一下條目,或者找到你的Javaweb項目的web.xml即可。
<web-app>
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>
</web-app>
上面的條目要被創建在web.xml文件中的<web-app>
...</web-app>
標籤內。到這裏,啓動Tomcat服務器輸入 http://localhost:8080/HelloWorld即可。
四、Servlet表單數據
很多情況下,需要傳遞一些信息,從瀏覽器到Web服務器,最終到Web服務器,最終到後臺程序。瀏覽器使用兩種方法可將這些信息傳遞到Web服務器,分別爲GET方法和POST方法。
1、GET方法
GET方法向頁面請求發送已編碼的用戶信息。頁面和已編碼的信息中間用?字符分割,如下:
http://www.test.com/hello?key1=value1&key2=value2
GET方法是默認的從瀏覽器向Web服務器傳遞信息的方法,它會產生一個很長的字符串,出現在瀏覽器的地址欄中。如果你要向服務器傳遞的是密碼或其它的敏感信息,請不要使用GET方法。GET方法有大小限制:請求字符串最多隻能有1024字符。
這些信息使用QUERY_STRING頭傳遞,並可以通過QUERY_STRING環境變量訪問,Servlet使用doGet()方法處理這種類型的請求。
2、POST方法
另一個向後臺程序傳遞信息的比較可靠的方法是POST方法。POST方法打包信息的方式與GET方法基本相同,但是POST方法不是把信息作爲URL中?字符後的文本字符串進行發送,而是把這心信息作爲一個單獨的消息。消息以標準輸出的形式傳到後臺程序,你可以解析和使用這些標準輸出。Servlet使用doPost()方法處理這種類型的請求。
3、使用Servlet讀取表單數據
Servlet處理表單數據,這些數據會根據不同的情況使用不同的方法自動解析:
-
getParameter():您可以調用 request.getParameter() 方法來獲取表單參數的值。
-
getParameterValues():如果參數出現一次以上,則調用該方法,並返回多個值,例如複選框。
-
getParameterNames():如果您想要得到當前請求中的所有參數的完整列表,則調用該方法。
4、使用URL的GET方法實例
下面是一個簡單的URL,將使用GET方法向HelloForm程序傳遞兩個值。http:localhost:8080/TomcatTest/HelloForm?name=菜鳥教程&url=www.runoob.com
下面是處理Web瀏覽器輸入的HelloForm.java Servlet程序。爲我們將使用getParameter()方法,可以很容易地傳遞信息:
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class HelloForm
*/
@WebServlet("/HelloForm")
public class HelloForm extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public HelloForm() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "使用 GET 方法讀取表單數據";
// 處理中文
String name =new String(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8");
String docType = "<!DOCTYPE html> \n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<ul>\n" +
" <li><b>站點名</b>:"
+ name + "\n" +
" <li><b>網址</b>:"
+ request.getParameter("url") + "\n" +
"</ul>\n" +
"</body></html>");
}
// 處理 POST 方法請求的方法
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
然後我們在web.xml文件中創建以下條目:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>HelloForm</servlet-name>
<servlet-class>com.runoob.test.HelloForm</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloForm</servlet-name>
<url-pattern>/TomcatTest/HelloForm</url-pattern>
</servlet-mapping>
</web-app>
然後瀏覽器中輸入http://localhost:8080/TomcatTest/HelloForm?name=菜鳥教程&url=www.runoob.com 即可。
5、使用表單的GET方法實例
下面是一個簡單的實例,使用HTML表單和提交按鈕傳遞兩個值。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<form action="HelloForm" method="GET">
網址名:<input type="text" name="name">
<br />
網址:<input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>
輸入網址之後就可以了。
6、使用表單的POST方法實例
我們對上面的Servlet做小小的修改,以便它可以處理GET和POST方法。下面的HelloForm.java Servlet程序使用GET和POST方法處理由Web瀏覽器給出的輸入(如果中文數據則需要轉碼:String name =new String(request.getParameter("name").getBytes("ISO8859-1"),"UTF-8");)。
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class HelloForm
*/
@WebServlet("/HelloForm")
public class HelloForm extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public HelloForm() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "使用 POST 方法讀取表單數據";
// 處理中文
String name =new String(request.getParameter("name").getBytes("ISO8859-1"),"UTF-8");
String docType = "<!DOCTYPE html> \n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<ul>\n" +
" <li><b>站點名</b>:"
+ name + "\n" +
" <li><b>網址</b>:"
+ request.getParameter("url") + "\n" +
"</ul>\n" +
"</body></html>");
}
// 處理 POST 方法請求的方法
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
編譯部署Servlet,使用帶有POST方法的hello.html進行測試:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<form action="HelloForm" method="POST">
網址名:<input type="text" name="name">
<br />
網址:<input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>
7、將複選框數據傳遞到Servlet程序
下面是一個HTML代碼實例checkbox.html,一個帶有兩個複選框的表單。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<form action="CheckBox" method="POST" target="_blank">
<input type="checkbox" name="runoob" checked="checked" /> 菜鳥教程
<input type="checkbox" name="google" /> Google
<input type="checkbox" name="taobao" checked="checked" /> 淘寶
<input type="submit" value="選擇站點" />
</form>
</body>
</html>
下面是Servlet程序,處理Web瀏覽器給出的複選框輸入。
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class CheckBox
*/
@WebServlet("/CheckBox")
public class CheckBox extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "讀取複選框數據";
String docType = "<!DOCTYPE html> \n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<ul>\n" +
" <li><b>菜鳥按教程標識:</b>: "
+ request.getParameter("runoob") + "\n" +
" <li><b>Google 標識:</b>: "
+ request.getParameter("google") + "\n" +
" <li><b>淘寶標識:</b>: "
+ request.getParameter("taobao") + "\n" +
"</ul>\n" +
"</body></html>");
}
// 處理 POST 方法請求的方法
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
設置對應的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>CheckBox</servlet-name>
<servlet-class>com.runoob.test.CheckBox</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CheckBox</servlet-name>
<url-pattern>/TomcatTest/CheckBox</url-pattern>
</servlet-mapping>
</web-app>
8、讀取所有的表單參數
使用HttpServletRequest的getParameterNames()方法讀取所有可用的表單參數。該方法返回一個枚舉,其中包含未指定順序的參數名。
一旦我們有一個枚舉,我們可以以標準方式循環枚舉,使用hasMoreElements()方法來確定何時停止,使用nextElement()方法來獲取每個參數的名稱。
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ReadParams
*/
@WebServlet("/ReadParams")
public class ReadParams extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ReadParams() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "讀取所有的表單數據";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " +
"transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<table width=\"100%\" border=\"1\" align=\"center\">\n" +
"<tr bgcolor=\"#949494\">\n" +
"<th>參數名稱</th><th>參數值</th>\n"+
"</tr>\n");
Enumeration paramNames = request.getParameterNames();
while(paramNames.hasMoreElements()) {
String paramName = (String)paramNames.nextElement();
out.print("<tr><td>" + paramName + "</td>\n");
String[] paramValues =
request.getParameterValues(paramName);
// 讀取單個值的數據
if (paramValues.length == 1) {
String paramValue = paramValues[0];
if (paramValue.length() == 0)
out.println("<td><i>沒有值</i></td>");
else
out.println("<td>" + paramValue + "</td>");
} else {
// 讀取多個值的數據
out.println("<td><ul>");
for(int i=0; i < paramValues.length; i++) {
out.println("<li>" + paramValues[i]);
}
out.println("</ul></td>");
}
out.print("</tr>");
}
out.println("\n</table>\n</body></html>");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
現在,通過表單嘗試上面的Servlet:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<form action="ReadParams" method="POST" target="_blank">
<input type="checkbox" name="maths" checked="checked" /> 數學
<input type="checkbox" name="physics" /> 物理
<input type="checkbox" name="chemistry" checked="checked" /> 化學
<input type="submit" value="選擇學科" />
</form>
</body>
</html>
當然,我們還要設置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>ReadParams</servlet-name>
<servlet-class>com.runoob.test.ReadParams</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ReadParams</servlet-name>
<url-pattern>/TomcatTest/ReadParams</url-pattern>
</servlet-mapping>
</web-app>
五、客戶端HTTP請求。
當瀏覽器請求網頁時,它會向Web服務器發送特定消息,這些信息不能被直接取用,,因爲這些信息是作爲HTTP請求的頭的一部分進行傳輸的。
頭信息 | 描述 |
---|---|
Accept | 這個頭信息指定瀏覽器或其他客戶端可以處理的 MIME 類型。值 image/png 或 image/jpeg 是最常見的兩種可能值。 |
Accept-Charset | 這個頭信息指定瀏覽器可以用來顯示信息的字符集。例如 ISO-8859-1。 |
Accept-Encoding | 這個頭信息指定瀏覽器知道如何處理的編碼類型。值 gzip 或 compress 是最常見的兩種可能值。 |
Accept-Language | 這個頭信息指定客戶端的首選語言,在這種情況下,Servlet 會產生多種語言的結果。例如,en、en-us、ru 等。 |
Authorization | 這個頭信息用於客戶端在訪問受密碼保護的網頁時識別自己的身份。 |
Connection | 這個頭信息指示客戶端是否可以處理持久 HTTP 連接。持久連接允許客戶端或其他瀏覽器通過單個請求來檢索多個文件。值 Keep-Alive 意味着使用了持續連接。 |
Content-Length | 這個頭信息只適用於 POST 請求,並給出 POST 數據的大小(以字節爲單位)。 |
Cookie | 這個頭信息把之前發送到瀏覽器的 cookies 返回到服務器。 |
Host | 這個頭信息指定原始的 URL 中的主機和端口。 |
If-Modified-Since | 這個頭信息表示只有當頁面在指定的日期後已更改時,客戶端想要的頁面。如果沒有新的結果可以使用,服務器會發送一個 304 代碼,表示 Not Modified 頭信息。 |
If-Unmodified-Since | 這個頭信息是 If-Modified-Since 的對立面,它指定只有當文檔早於指定日期時,操作纔會成功。 |
Referer | 這個頭信息指示所指向的 Web 頁的 URL。例如,如果您在網頁 1,點擊一個鏈接到網頁 2,當瀏覽器請求網頁 2 時,網頁 1 的 URL 就會包含在 Referer 頭信息中。 |
User-Agent | 這個頭信息識別發出請求的瀏覽器或其他客戶端,並可以向不同類型的瀏覽器返回不同的內容。 |
1、讀取HTTP頭的方法
下面的方法可用在Servlet程序中讀取HTTP頭,這些方法通過HttpServletRequest對象可用。
序號 | 方法 & 描述 |
---|---|
1 | Cookie[] getCookies() 返回一個數組,包含客戶端發送該請求的所有的 Cookie 對象。 |
2 | Enumeration getAttributeNames() 返回一個枚舉,包含提供給該請求可用的屬性名稱。 |
3 | Enumeration getHeaderNames() 返回一個枚舉,包含在該請求中包含的所有的頭名。 |
4 | Enumeration getParameterNames() 返回一個 String 對象的枚舉,包含在該請求中包含的參數的名稱。 |
5 | HttpSession getSession() 返回與該請求關聯的當前 session 會話,或者如果請求沒有 session 會話,則創建一個。 |
6 | HttpSession getSession(boolean create) 返回與該請求關聯的當前 HttpSession,或者如果沒有當前會話,且創建是真的,則返回一個新的 session 會話。 |
7 | Locale getLocale() 基於 Accept-Language 頭,返回客戶端接受內容的首選的區域設置。 |
8 | Object getAttribute(String name) 以對象形式返回已命名屬性的值,如果沒有給定名稱的屬性存在,則返回 null。 |
9 | ServletInputStream getInputStream() 使用 ServletInputStream,以二進制數據形式檢索請求的主體。 |
10 | String getAuthType() 返回用於保護 Servlet 的身份驗證方案的名稱,例如,"BASIC" 或 "SSL",如果JSP沒有受到保護則返回 null。 |
11 | String getCharacterEncoding() 返回請求主體中使用的字符編碼的名稱。 |
12 | String getContentType() 返回請求主體的 MIME 類型,如果不知道類型則返回 null。 |
13 | String getContextPath() 返回指示請求上下文的請求 URI 部分。 |
14 | String getHeader(String name) 以字符串形式返回指定的請求頭的值。 |
15 | String getMethod() 返回請求的 HTTP 方法的名稱,例如,GET、POST 或 PUT。 |
16 | String getParameter(String name) 以字符串形式返回請求參數的值,或者如果參數不存在則返回 null。 |
17 | String getPathInfo() 當請求發出時,返回與客戶端發送的 URL 相關的任何額外的路徑信息。 |
18 | String getProtocol() 返回請求協議的名稱和版本。 |
19 | String getQueryString() 返回包含在路徑後的請求 URL 中的查詢字符串。 |
20 | String getRemoteAddr() 返回發送請求的客戶端的互聯網協議(IP)地址。 |
21 | String getRemoteHost() 返回發送請求的客戶端的完全限定名稱。 |
22 | String getRemoteUser() 如果用戶已通過身份驗證,則返回發出請求的登錄用戶,或者如果用戶未通過身份驗證,則返回 null。 |
23 | String getRequestURI() 從協議名稱直到 HTTP 請求的第一行的查詢字符串中,返回該請求的 URL 的一部分。 |
24 | String getRequestedSessionId() 返回由客戶端指定的 session 會話 ID。 |
25 | String getServletPath() 返回調用 JSP 的請求的 URL 的一部分。 |
26 | String[] getParameterValues(String name) 返回一個字符串對象的數組,包含所有給定的請求參數的值,如果參數不存在則返回 null。 |
27 | boolean isSecure() 返回一個布爾值,指示請求是否使用安全通道,如 HTTPS。 |
28 | int getContentLength() 以字節爲單位返回請求主體的長度,並提供輸入流,或者如果長度未知則返回 -1。 |
29 | int getIntHeader(String name) 返回指定的請求頭的值爲一個 int 值。 |
30 | int getServerPort() 返回接收到這個請求的端口號。 |
31 | int getParameterMap() 將參數封裝成 Map 類型。 |
2、HTTP標頭
下面的實例使用HttpServletRequest的getHeaderNames()方法讀取HTTP頭信息。該方法返回一個枚舉,包含與當前的HTTP請求相關的頭信息。
一旦我們有一個枚舉,我們就可以以標準方式循環枚舉,使用hasMoreElements()方法來確定何時停止,使用nextElement()方法獲取每個參數的名稱。
//導入必需的 java 庫
import java.io.IOException;import java.io.IOException;
import java.io.PrintWriter;import java.io.PrintWriter;
import java.util.Enumeration;import java.util.Enumeration;
import javax.servlet.ServletException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponse;
@WebServlet("/DisplayHeader")@WebServlet("/DisplayHeader")
//擴展 HttpServlet 類//擴展 HttpServlet 類
public class DisplayHeader extends HttpServlet {public class DisplayHeader extends HttpServlet {
// 處理 GET 方法請求的方法// 處理 GET 方法請求的方法
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOExceptionpublic void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{{
// 設置響應內容類型// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();PrintWriter out = response.getWriter();
String title = "HTTP Header 請求實例 - 菜鳥教程實例";String title = "HTTP Header 請求實例 - 菜鳥教程實例";
String docType =String docType =
"<!DOCTYPE html> \n";"<!DOCTYPE html> \n";
out.println(docType +out.println(docType +
"<html>\n" +"<html>\n" +
"<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+"<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+
"<body bgcolor=\"#f0f0f0\">\n" +"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +"<h1 align=\"center\">" + title + "</h1>\n" +
"<table width=\"100%\" border=\"1\" align=\"center\">\n" +"<table width=\"100%\" border=\"1\" align=\"center\">\n" +
"<tr bgcolor=\"#949494\">\n" +"<tr bgcolor=\"#949494\">\n" +
"<th>Header 名稱</th><th>Header 值</th>\n"+"<th>Header 名稱</th><th>Header 值</th>\n"+
"</tr>\n");"</tr>\n");
Enumeration headerNames = request.getHeaderNames();Enumeration headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {while(headerNames.hasMoreElements()) {
String paramName = (String)headerNames.nextElement();String paramName = (String)headerNames.nextElement();
out.print("<tr><td>" + paramName + "</td>\n");out.print("<tr><td>" + paramName + "</td>\n");
String paramValue = request.getHeader(paramName);String paramValue = request.getHeader(paramName);
out.println("<td> " + paramValue + "</td></tr>\n");out.println("<td> " + paramValue + "</td></tr>\n");
}}
out.println("</table>\n</body></html>");out.println("</table>\n</body></html>");
}}
// 處理 POST 方法請求的方法// 處理 POST 方法請求的方法
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);(request, response);
}}
}}
之後我們肯定是配置web.xml
<?xml version="1.0" encoding="UTF-8"?> xml version="1.0" encoding="UTF-8"?>
<web-app> <web-app>
<servlet> <servlet>
<!-- 類名 --> <!-- 類名 -->
<servlet-name>DisplayHeader</servlet-name> <servlet-name>DisplayHeader</servlet-name>
<!-- 所在的包 --> <!-- 所在的包 -->
<servlet-class>com.runoob.test.DisplayHeader</servlet-class> <servlet-class>com.runoob.test.DisplayHeader</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>DisplayHeader</servlet-name> <servlet-name>DisplayHeader</servlet-name>
<!-- 訪問的網址 --> <!-- 訪問的網址 -->
<url-pattern>/TomcatTest/DisplayHeader</url-pattern> <url-pattern>/TomcatTest/DisplayHeader</url-pattern>
</servlet-mapping> </servlet-mapping>
</web-app></web-app>
之後直接訪問http://localhost:8080/TomcatTest/DisplayHeader就可以了。
六、Servlet服務器HTTP響應
當一個Web服務器響應一個HTTP請求時,響應通常包括一個狀態行、一些響應報頭、一個空行和文檔。例如:
HTTP/1.1 200 OK
Content-Type: text/html
Header2: ...
...
HeaderN: ...
(Blank Line)
<!doctype ...>
<html>
<head>...</head>
<body>
...
</body>
</html>
狀態行包括HTTP版本(爲HTTP/1.1)、一個狀態碼(本例中爲200)和一個對應狀態碼的短消息(本例中爲OK)。
下標總結了從Web服務器返回到瀏覽器的最有用的HTTP1.1響應報頭,你會在Web編程中頻繁的使用它:
頭信息 | 描述 |
---|---|
Allow | 這個頭信息指定服務器支持的請求方法(GET、POST 等)。 |
Cache-Control | 這個頭信息指定響應文檔在何種情況下可以安全地緩存。可能的值有:public、private 或 no-cache 等。Public 意味着文檔是可緩存,Private 意味着文檔是單個用戶私用文檔,且只能存儲在私有(非共享)緩存中,no-cache 意味着文檔不應被緩存。 |
Connection | 這個頭信息指示瀏覽器是否使用持久 HTTP 連接。值 close 指示瀏覽器不使用持久 HTTP 連接,值 keep-alive 意味着使用持久連接。 |
Content-Disposition | 這個頭信息可以讓您請求瀏覽器要求用戶以給定名稱的文件把響應保存到磁盤。 |
Content-Encoding | 在傳輸過程中,這個頭信息指定頁面的編碼方式。 |
Content-Language | 這個頭信息表示文檔編寫所使用的語言。例如,en、en-us、ru 等。 |
Content-Length | 這個頭信息指示響應中的字節數。只有當瀏覽器使用持久(keep-alive)HTTP 連接時才需要這些信息。 |
Content-Type | 這個頭信息提供了響應文檔的 MIME(Multipurpose Internet Mail Extension)類型。 |
Expires | 這個頭信息指定內容過期的時間,在這之後內容不再被緩存。 |
Last-Modified | 這個頭信息指示文檔的最後修改時間。然後,客戶端可以緩存文件,並在以後的請求中通過 If-Modified-Since 請求頭信息提供一個日期。 |
Location | 這個頭信息應被包含在所有的帶有狀態碼的響應中。在 300s 內,這會通知瀏覽器文檔的地址。瀏覽器會自動重新連接到這個位置,並獲取新的文檔。 |
Refresh | 這個頭信息指定瀏覽器應該如何儘快請求更新的頁面。您可以指定頁面刷新的秒數。 |
Retry-After | 這個頭信息可以與 503(Service Unavailable 服務不可用)響應配合使用,這會告訴客戶端多久就可以重複它的請求。 |
Set-Cookie | 這個頭信息指定一個與頁面關聯的 cookie。 |
1、設置HTTP響應報頭的方法
下面的方法可用於在Servlet程序中設置HTTP響應報頭。這些方法通過HttpServletResponse對象可用。
序號 | 方法 & 描述 |
---|---|
1 | String encodeRedirectURL(String url) 爲 sendRedirect 方法中使用的指定的 URL 進行編碼,或者如果編碼不是必需的,則返回 URL 未改變。 |
2 | String encodeURL(String url) 對包含 session 會話 ID 的指定 URL 進行編碼,或者如果編碼不是必需的,則返回 URL 未改變。 |
3 | boolean containsHeader(String name) 返回一個布爾值,指示是否已經設置已命名的響應報頭。 |
4 | boolean isCommitted() 返回一個布爾值,指示響應是否已經提交。 |
5 | void addCookie(Cookie cookie) 把指定的 cookie 添加到響應。 |
6 | void addDateHeader(String name, long date) 添加一個帶有給定的名稱和日期值的響應報頭。 |
7 | void addHeader(String name, String value) 添加一個帶有給定的名稱和值的響應報頭。 |
8 | void addIntHeader(String name, int value) 添加一個帶有給定的名稱和整數值的響應報頭。 |
9 | void flushBuffer() 強制任何在緩衝區中的內容被寫入到客戶端。 |
10 | void reset() 清除緩衝區中存在的任何數據,包括狀態碼和頭。 |
11 | void resetBuffer() 清除響應中基礎緩衝區的內容,不清除狀態碼和頭。 |
12 | void sendError(int sc) 使用指定的狀態碼發送錯誤響應到客戶端,並清除緩衝區。 |
13 | void sendError(int sc, String msg) 使用指定的狀態發送錯誤響應到客戶端。 |
14 | void sendRedirect(String location) 使用指定的重定向位置 URL 發送臨時重定向響應到客戶端。 |
15 | void setBufferSize(int size) 爲響應主體設置首選的緩衝區大小。 |
16 | void setCharacterEncoding(String charset) 設置被髮送到客戶端的響應的字符編碼(MIME 字符集)例如,UTF-8。 |
17 | void setContentLength(int len) 設置在 HTTP Servlet 響應中的內容主體的長度,該方法設置 HTTP Content-Length 頭。 |
18 | void setContentType(String type) 如果響應還未被提交,設置被髮送到客戶端的響應的內容類型。 |
19 | void setDateHeader(String name, long date) 設置一個帶有給定的名稱和日期值的響應報頭。 |
20 | void setHeader(String name, String value) 設置一個帶有給定的名稱和值的響應報頭。 |
21 | void setIntHeader(String name, int value) 設置一個帶有給定的名稱和整數值的響應報頭。 |
22 | void setLocale(Locale loc) 如果響應還未被提交,設置響應的區域。 |
23 | void setStatus(int sc) 爲該響應設置狀態碼。 |
2、HTTP Header響應實例
我們用setIIntHeader()方法來設置Refresh頭。
//導入必需的 java 庫
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/Refresh")
//擴展 HttpServlet 類
public class Refresh extends HttpServlet {
// 處理 GET 方法請求的方法
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// 設置刷新自動加載時間爲 5 秒
response.setIntHeader("Refresh", 5);
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
//使用默認時區和語言環境獲得一個日曆
Calendar cale = Calendar.getInstance();
//將Calendar類型轉換成Date類型
Date tasktime=cale.getTime();
//設置日期輸出的格式
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//格式化輸出
String nowTime = df.format(tasktime);
PrintWriter out = response.getWriter();
String title = "自動刷新 Header 設置 - 菜鳥教程實例";
String docType =
"<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n"+
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<p>當前時間是:" + nowTime + "</p>\n");
}
// 處理 POST 方法請求的方法
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
然後我們設置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<!-- 類名 -->
<servlet-name>Refresh</servlet-name>
<!-- 所在的包 -->
<servlet-class>com.runoob.test.Refresh</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Refresh</servlet-name>
<!-- 訪問的網址 -->
<url-pattern>/TomcatTest/Refresh</url-pattern>
</servlet-mapping>
</web-app>
七、Servlet HTTP狀態碼
HTTP請求和HTTP響應消息的格式是類似的:
-
初始狀態行 + 回車換行符(回車+換行)
-
零個或多個標題行+回車換行符
-
一個空白行,即回車換行符
-
一個可選的消息主體,比如文件、查詢數據或查詢輸出
例如,服務器的響應頭如下:
HTTP/1.1 200 OK
Content-Type: text/html
Header2: ...
...
HeaderN: ...
(Blank Line)
<!doctype ...>
<html>
<head>...</head>
<body>
...
</body>
</html>
狀態行包括HTTP版本、一個狀態碼和一個對應於狀態碼的短消息。
以下是可能從Web服務器返回的HTTP狀態碼和相關的信息列表:
代碼 | 消息 | 描述 |
---|---|---|
100 | Continue | 只有請求的一部分已經被服務器接收,但只要它沒有被拒絕,客戶端應繼續該請求。 |
101 | Switching Protocols | 服務器切換協議。 |
200 | OK | 請求成功。 |
201 | Created | 該請求是完整的,並創建一個新的資源。 |
202 | Accepted | 該請求被接受處理,但是該處理是不完整的。 |
203 | Non-authoritative Information | |
204 | No Content | |
205 | Reset Content | |
206 | Partial Content | |
300 | Multiple Choices | 鏈接列表。用戶可以選擇一個鏈接,進入到該位置。最多五個地址。 |
301 | Moved Permanently | 所請求的頁面已經轉移到一個新的 URL。 |
302 | Found | 所請求的頁面已經臨時轉移到一個新的 URL。 |
303 | See Other | 所請求的頁面可以在另一個不同的 URL 下被找到。 |
304 | Not Modified | |
305 | Use Proxy | |
306 | Unused | 在以前的版本中使用該代碼。現在已不再使用它,但代碼仍被保留。 |
307 | Temporary Redirect | 所請求的頁面已經臨時轉移到一個新的 URL。 |
400 | Bad Request | 服務器不理解請求。 |
401 | Unauthorized | 所請求的頁面需要用戶名和密碼。 |
402 | Payment Required | 您還不能使用該代碼。 |
403 | Forbidden | 禁止訪問所請求的頁面。 |
404 | Not Found | 服務器無法找到所請求的頁面。. |
405 | Method Not Allowed | 在請求中指定的方法是不允許的。 |
406 | Not Acceptable | 服務器只生成一個不被客戶端接受的響應。 |
407 | Proxy Authentication Required | 在請求送達之前,您必須使用代理服務器的驗證。 |
408 | Request Timeout | 請求需要的時間比服務器能夠等待的時間長,超時。 |
409 | Conflict | 請求因爲衝突無法完成。 |
410 | Gone | 所請求的頁面不再可用。 |
411 | Length Required | "Content-Length" 未定義。服務器無法處理客戶端發送的不帶 Content-Length 的請求信息。 |
412 | Precondition Failed | 請求中給出的先決條件被服務器評估爲 false。 |
413 | Request Entity Too Large | 服務器不接受該請求,因爲請求實體過大。 |
414 | Request-url Too Long | 服務器不接受該請求,因爲 URL 太長。當您轉換一個 "post" 請求爲一個帶有長的查詢信息的 "get" 請求時發生。 |
415 | Unsupported Media Type | 服務器不接受該請求,因爲媒體類型不被支持。 |
417 | Expectation Failed | |
500 | Internal Server Error | 未完成的請求。服務器遇到了一個意外的情況。 |
501 | Not Implemented | 未完成的請求。服務器不支持所需的功能。 |
502 | Bad Gateway | 未完成的請求。服務器從上游服務器收到無效響應。 |
503 | Service Unavailable | 未完成的請求。服務器暫時超載或死機。 |
504 | Gateway Timeout | 網關超時。 |
505 | HTTP Version Not Supported | 服務器不支持"HTTP協議"版本。 |
1、設置HTTP狀態代碼的方法
下面的方法可用於在Servlet程序中設置HTTP狀態碼。這些方法通過HttpServletResponse對象可用。
序號 | 方法 & 描述 |
---|---|
1 | public void setStatus ( int statusCode ) 該方法設置一個任意的狀態碼。setStatus 方法接受一個 int(狀態碼)作爲參數。如果您的響應包含了一個特殊的狀態碼和文檔,請確保在使用 PrintWriter 實際返回任何內容之前調用 setStatus。 |
2 | public void sendRedirect(String url) 該方法生成一個 302 響應,連同一個帶有新文檔 URL 的 Location 頭。 |
3 | public void sendError(int code, String message) 該方法發送一個狀態碼(通常爲 404),連同一個在 HTML 文檔內部自動格式化併發送到客戶端的短消息。 |
2、HTTP狀態碼實例
下面的例子把407錯誤代碼發送到客戶端瀏覽器,瀏覽器會顯示Need authentication!!!消息
// 導入必需的 java 庫
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import javax.servlet.annotation.WebServlet;
@WebServlet("/showError")
// 擴展 HttpServlet 類
public class showError extends HttpServlet {
// 處理 GET 方法請求的方法
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// 設置錯誤代碼和原因
response.sendError(407, "Need authentication!!!" );
}
// 處理 POST 方法請求的方法
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
八、編寫過濾器
Servlet過濾器可用動態地攔截請求和相應,以變換或使用包含在請求或響應中的信息。
可用將一個或多個Servlet過濾器附加到一個Servlet或一組Servlet。Servlet過濾器也可以附加到JavaServerPages(JSP)文件和HTML頁面。調用Servlet前調用所有附加的Servlet過濾器。
Servlet過濾器是可用於Servlet編程的java類,可以實現以下目的:
-
在客戶端的請求訪問後端資源之前,攔截這些請求。
-
在服務器的響應發送回客戶端之前,處理這些響應。
根據規範建議的各種類型的過濾器:
-
身份驗證過濾器(Authentication Filters)。
-
數據壓縮過濾器(Data compression Filters)。
-
加密過濾器(Encryption Filters)。
-
觸發資源訪問事件過濾器。
-
圖像轉換過濾器(Image Conversion Filters)。
-
日誌記錄和審覈過濾器(Logging and Auditing Filters)。
-
MIME-TYPE 鏈過濾器(MIME-TYPE Chain Filters)。
-
標記化過濾器(Tokenizing Filters)。
-
XSL/T 過濾器(XSL/T Filters),轉換 XML 內容。
過濾器通過Web部署描述符(web.xml)中的XML標籤來聲明,然後映射到你的應用程序的部署描述符中的Servlet名稱或URL模式。
當Web容器啓動Web應用程序時,它會成爲你在部署描述符中聲明的每一個過濾器創建一個實例。
Filter的執行順序與在web.xml配置文件中的配置順序一致,一般把Filter配置在所有的Servlet之前。
1、Servlet過濾器方法
過濾器是一個實現了javax.servlet.Filter接口的java類。javax.servlet.Filter接口定義了三個方法:
序號 | 方法 & 描述 |
---|---|
1 | public void doFilter (ServletRequest, ServletResponse, FilterChain) 該方法完成實際的過濾操作,當客戶端請求方法與過濾器設置匹配的URL時,Servlet容器將先調用過濾器的doFilter方法。FilterChain用戶訪問後續過濾器。 |
2 | public void init(FilterConfig filterConfig) web 應用程序啓動時,web 服務器將創建Filter 的實例對象,並調用其init方法,讀取web.xml配置,完成對象的初始化功能,從而爲後續的用戶請求作好攔截的準備工作(filter對象只會創建一次,init方法也只會執行一次)。開發人員通過init方法的參數,可獲得代表當前filter配置信息的FilterConfig對象。 |
3 | public void destroy() Servlet容器在銷燬過濾器實例前調用該方法,在該方法中釋放Servlet過濾器佔用的資源。 |
2、FilterConfig使用
Filter的init方法中提供了一個FilterConfig對象。
如web.xml文件配置如下:
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.runoob.test.LogFilter</filter-class>
<init-param>
<param-name>Site</param-name>
<param-value>菜鳥教程</param-value>
</init-param>
</filter>
在init方法使用FilterConfig對象獲取參數:
public void init(FilterConfig config) throws ServletException {
// 獲取初始化參數
String site = config.getInitParameter("Site");
// 輸出初始化參數
System.out.println("網站名稱: " + site);
}
3、Servlet過濾器實例
以下是Servlet過濾器的實例,將輸出網站名稱和地址。
package com.runoob.test;
//導入必需的 java 庫
import javax.servlet.*;
import java.util.*;
//實現 Filter 類
public class LogFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
// 獲取初始化參數
String site = config.getInitParameter("Site");
// 輸出初始化參數
System.out.println("網站名稱: " + site);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
// 輸出站點名稱
System.out.println("站點網址:http://www.runoob.com");
// 把請求傳回過濾鏈
chain.doFilter(request,response);
}
public void destroy( ){
/* 在 Filter 實例被 Web 容器從服務移除之前調用 */
}
}
這裏使用DisplayHeader.java爲例子:
//導入必需的 java 庫
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/DisplayHeader")
//擴展 HttpServlet 類
public class DisplayHeader extends HttpServlet {
// 處理 GET 方法請求的方法
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "HTTP Header 請求實例 - 菜鳥教程實例";
String docType =
"<!DOCTYPE html> \n";
out.println(docType +
"<html>\n" +
"<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<table width=\"100%\" border=\"1\" align=\"center\">\n" +
"<tr bgcolor=\"#949494\">\n" +
"<th>Header 名稱</th><th>Header 值</th>\n"+
"</tr>\n");
Enumeration headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
String paramName = (String)headerNames.nextElement();
out.print("<tr><td>" + paramName + "</td>\n");
String paramValue = request.getHeader(paramName);
out.println("<td> " + paramValue + "</td></tr>\n");
}
out.println("</table>\n</body></html>");
}
// 處理 POST 方法請求的方法
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
4、Web.xml中的Servlet過濾器映射(Servlet Filter Mapping)
定義過濾器,然後映射到一個URL或Servlet,這與定義Servlet,然後映射到一個URL模式方式大致相同:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.runoob.test.LogFilter</filter-class>
<init-param>
<param-name>Site</param-name>
<param-value>菜鳥教程</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<!-- 類名 -->
<servlet-name>DisplayHeader</servlet-name>
<!-- 所在的包 -->
<servlet-class>com.runoob.test.DisplayHeader</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayHeader</servlet-name>
<!-- 訪問的網址 -->
<url-pattern>/TomcatTest/DisplayHeader</url-pattern>
</servlet-mapping>
</web-app>
上述過濾器適用於所有的Servlet,因爲我們在配置中指定/*。如果你只想在少數的Servlet上應用過濾器,你可以指定一個特定的Servlet路徑。
5、使用多個過濾器
Web應用程序可以根據特定的目的定義若干個不同的過濾器。假設你定義了兩個過濾器AuthenFilter和LogFilter。你需要創建一個如下所述的不同的映射,其餘的處理過程大致相同:
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.runoob.test.LogFilter</filter-class>
<init-param>
<param-name>test-param</param-name>
<param-value>Initialization Paramter</param-value>
</init-param>
</filter>
<filter>
<filter-name>AuthenFilter</filter-name>
<filter-class>com.runoob.test.AuthenFilter</filter-class>
<init-param>
<param-name>test-param</param-name>
<param-value>Initialization Paramter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>AuthenFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
6、過濾器的應用順序
web..xml中的filter-mapping元素的順序決定了Web容器應用過濾器到Servlet的順序。若要反轉過濾器的順序,你只需要在web.xml文件中反轉filter-mapping元素即可。
7、web.xml配置各節點說明
-
<filter>
指定一個過濾器。
-
<filter-name>
用於爲過濾器指定一個名字,該元素的內容不能爲空。 -
<filter-class>
元素用於指定過濾器的完整的限定類名。 -
<init-param>
元素用於爲過濾器指定初始化參數,它的子元素<param-name>
指定參數的名字,<param-value>
指定參數的值。 -
在過濾器中,可以使用
FilterConfig
接口對象來訪問初始化參數。
-
-
<filter-mapping>
元素用於設置一個 Filter 所負責攔截的資源。一個Filter攔截的資源可通過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑
-
<filter-name>
子元素用於設置filter的註冊名稱。該值必須是在<filter>
元素中聲明過的過濾器的名字 -
<url-pattern>
設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式)
-
-
<servlet-name>
指定過濾器所攔截的Servlet名稱。 -
<dispatcher>
指定過濾器所攔截的資源被 Servlet 容器調用的方式,可以是REQUEST
,INCLUDE
,FORWARD
和ERROR
之一,默認REQUEST
。用戶可以設置多個<dispatcher>
子元素用來指定 Filter 對資源的多種調用方式進行攔截。 -
<dispatcher>
子元素可以設置的值及其意義
-
REQUEST
:當用戶直接訪問頁面時,Web容器將會調用過濾器。如果目標資源是通過RequestDispatcher的include()或forward()方法訪問時,那麼該過濾器就不會被調用。 -
INCLUDE
:如果目標資源是通過RequestDispatcher的include()方法訪問時,那麼該過濾器將被調用。除此之外,該過濾器不會被調用。 -
FORWARD
:如果目標資源是通過RequestDispatcher的forward()方法訪問時,那麼該過濾器將被調用,除此之外,該過濾器不會被調用。 -
ERROR
:如果目標資源是通過聲明式異常處理機制調用時,那麼該過濾器將被調用。除此之外,過濾器不會被調用。
-
九、Servlet異常處理
當一個Servlet拋出一個異常時,Web容器在使用了exception-type元素的web.xml中搜索與拋出異常類型相匹配的配置。
你必須在web.xml中使用error-page元素來指定對特定異常或HTTP狀態碼作出相應的Servlet調用。
1、web.xml配置
假設,有一個ErrorHandler的Servlet在任何已定義的異常或錯誤出現時被調用。以下將是在web.xml中創建的項。
<!-- servlet 定義 -->
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>ErrorHandler</servlet-class>
</servlet>
<!-- servlet 映射 -->
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<!-- error-code 相關的錯誤頁面 -->
<error-page>
<error-code>404</error-code>
<location>/ErrorHandler</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/ErrorHandler</location>
</error-page>
<!-- exception-type 相關的錯誤頁面 -->
<error-page>
<exception-type>
javax.servlet.ServletException
</exception-type >
<location>/ErrorHandler</location>
</error-page>
<error-page>
<exception-type>java.io.IOException</exception-type >
<location>/ErrorHandler</location>
</error-page>
如果你想對所有的異常有一個通用的錯誤處理程序,那麼應該定義下面的error-page,而不是爲每個異常定義單獨的error-page元素。
<error-page>
<exception-type>java.lang.Throwable</exception-type >
<location>/ErrorHandler</location>
</error-page>
以下是關於上面web.xml異常處理要注意的點:
-
Servlet ErrorHandler 與其他的 Servlet 的定義方式一樣,且在 web.xml 中進行配置。
-
如果有錯誤狀態代碼出現,不管爲 404(Not Found 未找到)或 403(Forbidden 禁止),則會調用 ErrorHandler 的 Servlet。
-
如果 Web 應用程序拋出 ServletException 或 IOException,那麼 Web 容器會調用 ErrorHandler 的 Servlet。
-
您可以定義不同的錯誤處理程序來處理不同類型的錯誤或異常。上面的實例是非常通用的,希望您能通過實例理解基本的概念。
2、請求屬性-錯誤/異常
以下是錯誤處理的Servlet可以訪問的請求屬性列表,用來分析錯誤/異常的性質。
序號 | 屬性 & 描述 |
---|---|
1 | javax.servlet.error.status_code 該屬性給出狀態碼,狀態碼可被存儲,並在存儲爲 java.lang.Integer 數據類型後可被分析。 |
2 | javax.servlet.error.exception_type 該屬性給出異常類型的信息,異常類型可被存儲,並在存儲爲 java.lang.Class 數據類型後可被分析。 |
3 | javax.servlet.error.message 該屬性給出確切錯誤消息的信息,信息可被存儲,並在存儲爲 java.lang.String 數據類型後可被分析。 |
4 | javax.servlet.error.request_uri 該屬性給出有關 URL 調用 Servlet 的信息,信息可被存儲,並在存儲爲 java.lang.String 數據類型後可被分析。 |
5 | javax.servlet.error.exception 該屬性給出異常產生的信息,信息可被存儲,並在存儲爲 java.lang.Throwable 數據類型後可被分析。 |
6 | javax.servlet.error.servlet_name 該屬性給出 Servlet 的名稱,名稱可被存儲,並在存儲爲 java.lang.String 數據類型後可被分析。 |
3、Servlet錯誤處理程序實例
//導入必需的 java 庫
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
//擴展 HttpServlet 類
public class ErrorHandler extends HttpServlet {
// 處理 GET 方法請求的方法
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Throwable throwable = (Throwable)
request.getAttribute("javax.servlet.error.exception");
Integer statusCode = (Integer)
request.getAttribute("javax.servlet.error.status_code");
String servletName = (String)
request.getAttribute("javax.servlet.error.servlet_name");
if (servletName == null){
servletName = "Unknown";
}
String requestUri = (String)
request.getAttribute("javax.servlet.error.request_uri");
if (requestUri == null){
requestUri = "Unknown";
}
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "菜鳥教程 Error/Exception 信息";
String docType = "<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n");
out.println("<h1>菜鳥教程異常信息實例演示</h1>");
if (throwable == null && statusCode == null){
out.println("<h2>錯誤信息丟失</h2>");
out.println("請返回 <a href=\"" +
response.encodeURL("http://localhost:8080/") +
"\">主頁</a>。");
}else if (statusCode != null) {
out.println("錯誤代碼 : " + statusCode);
}else{
out.println("<h2>錯誤信息</h2>");
out.println("Servlet Name : " + servletName +
"</br></br>");
out.println("異常類型 : " +
throwable.getClass( ).getName( ) +
"</br></br>");
out.println("請求 URI: " + requestUri +
"<br><br>");
out.println("異常信息: " +
throwable.getMessage( ));
}
out.println("</body>");
out.println("</html>");
}
// 處理 POST 方法請求的方法
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
配置web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>com.runoob.test.ErrorHandler</servlet-class>
</servlet>
<!-- servlet mappings -->
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/TomcatTest/ErrorHandler</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/TomcatTest/ErrorHandler</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type >
<location>/ErrorHandler</location>
</error-page>
</web-app>
如果你嘗試輸入錯誤的URL,就會觸發Web容器調用ErrorHandler的Servlet,並顯示適當的消息。
十、Cookie處理
Cookie是存儲在客戶端計算機上的文本文件,並保留了各種跟蹤信息。java servlet顯然支持HTTP Cookie。
識別返回用戶包括三個步驟:
-
服務器腳本向瀏覽器發送一組 Cookie。例如:姓名、年齡或識別號碼等。
-
瀏覽器將這些信息存儲在本地計算機上,以備將來使用。
-
當下一次瀏覽器向 Web 服務器發送任何請求時,瀏覽器會把這些 Cookie 信息發送到服務器,服務器將使用這些信息來識別用戶。
(Servlet Cookie處理需要中文進行編碼與解碼,方法爲:
String str = java.net.URLEncoder.encode("中文","UTF-8"); //編碼
String str = java.net.URLDecoder.decode("編碼後的字符串","UTF-8"); // 解碼
)
1、Cookie剖析
Cookie通常設置在HTTP頭信息中(雖然JavaScript也可以直接在瀏覽器上設置一個Cookie)。設置Cookie的Servlet會發送如下的頭信息:
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT;
path=/; domain=runoob.com
Connection: close
Content-Type: text/html
所以,Set-Cookie頭包含了一個名稱值對、一個GMT日期、一個路徑和一個域。名稱和值會被URL編碼。expires字段是一個指令,告訴瀏覽器在給定的時間和日期之後“忘記”該Cookie。
如果瀏覽器被配置爲存儲Cookie,它將會保留次信息知道到期日期。如果用戶的瀏覽器指向任何匹配該Cookie的路徑和域的界面,它會重新發送Cookie到服務器。瀏覽器的頭信息可能如下:
GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc)
Host: zink.demon.co.uk:1126
Accept: image/gif, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Cookie: name=xyz
Servlet就能通過請求方法request.getCookies()訪問Cookie,該方法將返回一個Cookie對象的數組。
2、Cookie方法
以下是在Servlet中操作Cookie時可使用的有用的方法列表:
序號 | 方法 & 描述 |
---|---|
1 | public void setDomain(String pattern) 該方法設置 cookie 適用的域,例如 runoob.com。 |
2 | public String getDomain() 該方法獲取 cookie 適用的域,例如 runoob.com。 |
3 | public void setMaxAge(int expiry) 該方法設置 cookie 過期的時間(以秒爲單位)。如果不這樣設置,cookie 只會在當前 session 會話中持續有效。 |
4 | public int getMaxAge() 該方法返回 cookie 的最大生存週期(以秒爲單位),默認情況下,-1 表示 cookie 將持續下去,直到瀏覽器關閉。 |
5 | public String getName() 該方法返回 cookie 的名稱。名稱在創建後不能改變。 |
6 | public void setValue(String newValue) 該方法設置與 cookie 關聯的值。 |
7 | public String getValue() 該方法獲取與 cookie 關聯的值。 |
8 | public void setPath(String uri) 該方法設置 cookie 適用的路徑。如果您不指定路徑,與當前頁面相同目錄下的(包括子目錄下的)所有 URL 都會返回 cookie。 |
9 | public String getPath() 該方法獲取 cookie 適用的路徑。 |
10 | public void setSecure(boolean flag) 該方法設置布爾值,表示 cookie 是否應該只在加密的(即 SSL)連接上發送。 |
11 | public void setComment(String purpose) 設置cookie的註釋。該註釋在瀏覽器向用戶呈現 cookie 時非常有用。 |
12 | public String getComment() 獲取 cookie 的註釋,如果 cookie 沒有註釋則返回 null。 |
3、通過Servlet設置Cookie
通過Servlet設置Cookie包括三個步驟:
1)創建一個Cookie對象:你可以調用帶有cookie名稱和cookie值的Cookie構造函數,cookie名稱和cookie值都是字符串。
Cookie cookie = new Cookie("key","value");
無論是名字還是值,都不能包含空格或以下任何字符:[]()=,"/?@:;'
2)設置最大生命週期:你可以使用setMaxAge方法來指定cookie能夠保持有效的時間(以秒爲單位)。下面將設置一個最長有效期爲24小時的cookie。
cookie.setMaxAge(60*60*24);
3)發送Cookie到HTTP響應頭:你可以使用response.addCookie來添加HTTP響應頭中的Cookie,如下:
response.addCookie(cookie);
4、實例
讓我們修改我們的表單數據實例,爲名字和姓氏設置Cookie。
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class HelloServlet
*/
@WebServlet("/HelloForm")
public class HelloForm extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public HelloForm() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// 爲名字和姓氏創建 Cookie
Cookie name = new Cookie("name",
URLEncoder.encode(request.getParameter("name"), "UTF-8")); // 中文轉碼
Cookie url = new Cookie("url",
request.getParameter("url"));
// 爲兩個 Cookie 設置過期日期爲 24 小時後
name.setMaxAge(60*60*24);
url.setMaxAge(60*60*24);
// 在響應頭中添加兩個 Cookie
response.addCookie( name );
response.addCookie( url );
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "設置 Cookie 實例";
String docType = "<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<ul>\n" +
" <li><b>站點名:</b>:"
+ request.getParameter("name") + "\n</li>" +
" <li><b>站點 URL:</b>:"
+ request.getParameter("url") + "\n</li>" +
"</ul>\n" +
"</body></html>");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
然後配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<!-- 類名 -->
<servlet-name>HelloForm</servlet-name>
<!-- 所在的包 -->
<servlet-class>com.runoob.test.HelloForm</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloForm</servlet-name>
<!-- 訪問的網址 -->
<url-pattern>/TomcatTest/HelloForm</url-pattern>
</servlet-mapping>
</web-app>
然後用下面的HTML頁面來調用Servlet。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<form action="/TomcatTest/HelloForm" method="GET">
站點名 :<input type="text" name="name">
<br />
站點 URL:<input type="text" name="url" /><br>
<input type="submit" value="提交" />
</form>
</body>
</html>
5、通過Servlet讀取Cookie
要讀取Cookie,你需要通過調用HttpServletRequest的getCookies()方法創建一個javax.servlet.http.Cookie對象的數組。然後循環遍歷數組,並使用getName()和getValue()方法來訪問每個cookie和關聯的值。
實例:
我們讀取上面實例中設置的Cookie
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ReadCookies
*/
@WebServlet("/ReadCookies")
public class ReadCookies extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ReadCookies() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Cookie cookie = null;
Cookie[] cookies = null;
// 獲取與該域相關的 Cookie 的數組
cookies = request.getCookies();
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "Delete Cookie Example";
String docType = "<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" );
if( cookies != null ){
out.println("<h2>Cookie 名稱和值</h2>");
for (int i = 0; i < cookies.length; i++){
cookie = cookies[i];
if((cookie.getName( )).compareTo("name") == 0 ){
cookie.setMaxAge(0);
response.addCookie(cookie);
out.print("已刪除的 cookie:" +
cookie.getName( ) + "<br/>");
}
out.print("名稱:" + cookie.getName( ) + ",");
out.print("值:" + URLDecoder.decode(cookie.getValue(), "utf-8") +" <br/>");
}
}else{
out.println(
"<h2 class=\"tutheader\">No Cookie founds</h2>");
}
out.println("</body>");
out.println("</html>");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
6、通過Servlet刪除Cookie
刪除Cookie是非常簡單的,如果你想刪除一個cookie,那麼你只需要以下三個步驟:
-
讀取一個現有的 cookie,並把它存儲在 Cookie 對象中。
-
使用 setMaxAge() 方法設置 cookie 的年齡爲零,來刪除現有的 cookie。
-
把這個 cookie 添加到響應頭。
實例:
下面的例子將刪除現有的名爲"url"的cookie,當你下次運行ReadCookies的Servlet時,它會返回url爲null。
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class DeleteCookies
*/
@WebServlet("/DeleteCookies")
public class DeleteCookies extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public DeleteCookies() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Cookie cookie = null;
Cookie[] cookies = null;
// 獲取與該域相關的 Cookie 的數組
cookies = request.getCookies();
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "刪除 Cookie 實例";
String docType = "<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" );
if( cookies != null ){
out.println("<h2>Cookie 名稱和值</h2>");
for (int i = 0; i < cookies.length; i++){
cookie = cookies[i];
if((cookie.getName( )).compareTo("url") == 0 ){
cookie.setMaxAge(0);
response.addCookie(cookie);
out.print("已刪除的 cookie:" +
cookie.getName( ) + "<br/>");
}
out.print("名稱:" + cookie.getName( ) + ",");
out.print("值:" + cookie.getValue( )+" <br/>");
}
}else{
out.println(
"<h2 class=\"tutheader\">No Cookie founds</h2>");
}
out.println("</body>");
out.println("</html>");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
十一、Session跟蹤
HTTP是一種“無狀態”協議,這就意味着每次客戶端檢索網頁時,客戶端打開一個單獨的連接到Web服務器,服務器會自動不保留之前客戶端請求的任何記錄。
但是仍然有以下三種方式來維持Web客戶端和Web服務器之間的session會話:
1、Cookies
一個Web服務器可以分配一個唯一的session會話ID作爲每個Web客戶端的cookie,對於客戶端的後續請求可以使用接收到的cookie來識別。
這可能不是一個有效的方法,因爲很多瀏覽器不支持cookie,所以我們建議不要使用這種方式來維持session會話。
2、隱藏的表單字段
一個Web服務器可以發送一個隱藏的HTML表單字段,以及一個唯一的session會話,如下:
<input type="hidden" name="sessionid" value="12345">
該條目意味着,當表單被提交時,指定的名稱和值會被自動包含在GET和POST數據中。每次當Web瀏覽器發送回請求時,session_id值用於保持不同的Web瀏覽器的跟蹤。
這個可能是一種保持session會發跟蹤的有效方式,但是點擊常規的超文本鏈接不會導致表單提交,因此隱藏的表單字段也不支持常規的session會話跟蹤。
3、URL重寫
你在在每個URL末尾追加一些額外的數據來表示session會話,服務器會把該session會話標識符與已存儲的有關session會話的數據相關聯。
例如:http://w3cshcool.cc/file.html;sessionid=123456,session會話標識符被附加爲sessionid=12345,標識符可被Web服務器識別客戶端。
URL重寫是一種更好的維持session會話的方式,它在瀏覽器不支持cookie時能夠很好的工作,但是它的缺點是會動態生成每個URL來爲頁面分配一個session會話ID,即使是在很簡單的靜態HTML頁面中也會如此。
4、HttpSession對象
Servlet還提供了HttpSession接口,該接口提供了一種跨多個頁面請求或訪問網站時識別用戶以及存儲有關用戶信息的方式。
Servlet容器使用這個接口來創建一個HTTP客戶端和HTTP服務器之間的session會話。會話持續一個指定的時間段,跨多個連接或頁面請求。
你可以通過調用HttpServletRequset的公共方法getSession()來獲取HttpSession對象,例如:
HttpSession session = request.getSession();
你需要在向客戶端發送任何文檔內容之前調用request.getSession()。下面總結了HttpSession對象中可用的幾個重要的方法:
序號 | 方法 & 描述 |
---|---|
1 | public Object getAttribute(String name) 該方法返回在該 session 會話中具有指定名稱的對象,如果沒有指定名稱的對象,則返回 null。 |
2 | public Enumeration getAttributeNames() 該方法返回 String 對象的枚舉,String 對象包含所有綁定到該 session 會話的對象的名稱。 |
3 | public long getCreationTime() 該方法返回該 session 會話被創建的時間,自格林尼治標準時間 1970 年 1 月 1 日午夜算起,以毫秒爲單位。 |
4 | public String getId() 該方法返回一個包含分配給該 session 會話的唯一標識符的字符串。 |
5 | public long getLastAccessedTime() 該方法返回客戶端最後一次發送與該 session 會話相關的請求的時間自格林尼治標準時間 1970 年 1 月 1 日午夜算起,以毫秒爲單位。 |
6 | public int getMaxInactiveInterval() 該方法返回 Servlet 容器在客戶端訪問時保持 session 會話打開的最大時間間隔,以秒爲單位。 |
7 | public void invalidate() 該方法指示該 session 會話無效,並解除綁定到它上面的任何對象。 |
8 | public boolean isNew() 如果客戶端還不知道該 session 會話,或者如果客戶選擇不參入該 session 會話,則該方法返回 true。 |
9 | public void removeAttribute(String name) 該方法將從該 session 會話移除指定名稱的對象。 |
10 | public void setAttribute(String name, Object value) 該方法使用指定的名稱綁定一個對象到該 session 會話。 |
11 | public void setMaxInactiveInterval(int interval) 該方法在 Servlet 容器指示該 session 會話無效之前,指定客戶端請求之間的時間,以秒爲單位。 |
5、session跟蹤實例
本實例說明了如何使用HttpSession對象獲取session會話創建時間和最後訪問時間。如果不存在session會話,我們將通過請求創建一個新的session會話。
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class SessionTrack
*/
@WebServlet("/SessionTrack")
public class SessionTrack extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// 如果不存在 session 會話,則創建一個 session 對象
HttpSession session = request.getSession(true);
// 獲取 session 創建時間
Date createTime = new Date(session.getCreationTime());
// 獲取該網頁的最後一次訪問時間
Date lastAccessTime = new Date(session.getLastAccessedTime());
//設置日期輸出的格式
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String title = "Servlet Session 實例 - 菜鳥教程";
Integer visitCount = new Integer(0);
String visitCountKey = new String("visitCount");
String userIDKey = new String("userID");
String userID = new String("Runoob");
if(session.getAttribute(visitCountKey) == null) {
session.setAttribute(visitCountKey, new Integer(0));
}
// 檢查網頁上是否有新的訪問者
if (session.isNew()){
title = "Servlet Session 實例 - 菜鳥教程";
session.setAttribute(userIDKey, userID);
} else {
visitCount = (Integer)session.getAttribute(visitCountKey);
visitCount = visitCount + 1;
userID = (String)session.getAttribute(userIDKey);
}
session.setAttribute(visitCountKey, visitCount);
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String docType = "<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<h2 align=\"center\">Session 信息</h2>\n" +
"<table border=\"1\" align=\"center\">\n" +
"<tr bgcolor=\"#949494\">\n" +
" <th>Session 信息</th><th>值</th></tr>\n" +
"<tr>\n" +
" <td>id</td>\n" +
" <td>" + session.getId() + "</td></tr>\n" +
"<tr>\n" +
" <td>創建時間</td>\n" +
" <td>" + df.format(createTime) +
" </td></tr>\n" +
"<tr>\n" +
" <td>最後訪問時間</td>\n" +
" <td>" + df.format(lastAccessTime) +
" </td></tr>\n" +
"<tr>\n" +
" <td>用戶 ID</td>\n" +
" <td>" + userID +
" </td></tr>\n" +
"<tr>\n" +
" <td>訪問統計:</td>\n" +
" <td>" + visitCount + "</td></tr>\n" +
"</table>\n" +
"</body></html>");
}
}
在web.xml配置:
?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<!-- 類名 -->
<servlet-name>SessionTrack</servlet-name>
<!-- 所在的包 -->
<servlet-class>com.runoob.test.SessionTrack</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SessionTrack</servlet-name>
<!-- 訪問的網址 -->
<url-pattern>/TomcatTest/SessionTrack</url-pattern>
</servlet-mapping>
</web-app>
6、刪除Session會話數據
-
移除一個特定的屬性:您可以調用 public void removeAttribute(String name) 方法來刪除與特定的鍵相關聯的值。
-
刪除整個 session 會話:您可以調用 public void invalidate() 方法來丟棄整個 session 會話。
-
設置 session 會話過期時間:您可以調用 public void setMaxInactiveInterval(int interval) 方法來單獨設置 session 會話超時。
-
註銷用戶:如果使用的是支持 servlet 2.4 的服務器,您可以調用 logout 來註銷 Web 服務器的客戶端,並把屬於所有用戶的所有 session 會話設置爲無效。
-
web.xml 配置:如果您使用的是 Tomcat,除了上述方法,您還可以在 web.xml 文件中配置 session 會話超時,如下所示:
<session-config>
<session-timeout>15</session-timeout>
</session-config>
上面實例的超時時間是以分鐘爲單位,將覆蓋Tomcat中默認的30分鐘超時時間。
十二、Servlet數據庫訪問
訪問數據庫,演示如何使用Servlet訪問數據庫:
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class DatabaseAccess
*/
@WebServlet("/DatabaseAccess")
public class DatabaseAccess extends HttpServlet {
private static final long serialVersionUID = 1L;
// JDBC 驅動名及數據庫 URL
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB";
// 數據庫的用戶名與密碼,需要根據自己的設置
static final String USER = "root";
static final String PASS = "123456";
/**
* @see HttpServlet#HttpServlet()
*/
public DatabaseAccess() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Connection conn = null;
Statement stmt = null;
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "Servlet Mysql 測試 - 菜鳥教程";
String docType = "<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n");
try{
// 註冊 JDBC 驅動器
Class.forName("com.mysql.jdbc.Driver");
// 打開一個連接
conn = DriverManager.getConnection(DB_URL,USER,PASS);
// 執行 SQL 查詢
stmt = conn.createStatement();
String sql;
sql = "SELECT id, name, url FROM websites";
ResultSet rs = stmt.executeQuery(sql);
// 展開結果集數據庫
while(rs.next()){
// 通過字段檢索
int id = rs.getInt("id");
String name = rs.getString("name");
String url = rs.getString("url");
// 輸出數據
out.println("ID: " + id);
out.println(", 站點名稱: " + name);
out.println(", 站點 URL: " + url);
out.println("<br />");
}
out.println("</body></html>");
// 完成後關閉
rs.close();
stmt.close();
conn.close();
} catch(SQLException se) {
// 處理 JDBC 錯誤
se.printStackTrace();
} catch(Exception e) {
// 處理 Class.forName 錯誤
e.printStackTrace();
}finally{
// 最後是用於關閉資源的塊
try{
if(stmt!=null)
stmt.close();
}catch(SQLException se2){
}
try{
if(conn!=null)
conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
配置web.xml文件:
<servlet>
<servlet-name>DatabaseAccess</servlet-name>
<servlet-class>com.runoob.test.DatabaseAccess</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DatabaseAccess</servlet-name>
<url-pattern>/TomcatTest/DatabaseAccess</url-pattern>
</servlet-mapping>
十三、Servlet文件上傳
Servlet可以與HTML表單標籤一起使用,來允許用戶上傳文件到服務器。上傳的文件可以是文本文件或圖像文件或任何文檔。
使用到的文件有:
-
upload.jsp:文件上傳表單。
-
message.jsp:提交成功後替換頁面。
-
UploadServlet.java:上傳處理Servlet。
-
需要約會的jar文件:commons-fileupload-1.3.2,commons-io-2.5.jar。
1、創建一個文件上傳表單
下面的HTML代碼創建了一個文件上傳表單,需要注意:
-
表單 method 屬性應該設置爲 POST 方法,不能使用 GET 方法。
-
表單 enctype 屬性應該設置爲 multipart/form-data.
-
表單 action 屬性應該設置爲在後端服務器上處理文件上傳的 Servlet 文件。下面的實例使用了 UploadServlet Servlet 來上傳文件。
-
上傳單個文件,您應該使用單個帶有屬性 type="file" 的 <input .../> 標籤。爲了允許多個文件上傳,請包含多個 name 屬性值不同的 input 標籤。輸入標籤具有不同的名稱屬性的值。瀏覽器會爲每個 input 標籤關聯一個瀏覽按鈕。
upload.jsp文件代碼如下:
<%@ 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">
<html><html>
<head><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上傳實例 - 菜鳥教程</title><title>文件上傳實例 - 菜鳥教程</title>
</head></head>
<body><body>
<h1>文件上傳實例 - 菜鳥教程</h1><h1>文件上傳實例 - 菜鳥教程</h1>
<form method="post" action="/TomcatTest/UploadServlet" enctype="multipart/form-data"><form method="post" action="/TomcatTest/UploadServlet" enctype="multipart/form-data">
選擇一個文件:
<input type="file" name="uploadFile" /><input type="file" name="uploadFile" />
<br/><br/><br/><br/>
<input type="submit" value="上傳" /><input type="submit" value="上傳" />
</form></form>
</body></body>
</html></html>
2、編寫後臺Servlet
以下是UploadServlet的源代碼,用於處理文件上傳,在這之前我們先確保依賴包已經引入到項目的WEB-INF/lib目錄下:
-
下面的實例依賴於 FileUpload,所以一定要確保在您的 classpath 中有最新版本的 commons-fileupload.x.x.jar 文件。可以從 http://commons.apache.org/proper/commons-fileupload/ 下載。
-
FileUpload 依賴於 Commons IO,所以一定要確保在您的 classpath 中有最新版本的 commons-io-x.x.jar 文件。可以從 http://commons.apache.org/proper/commons-io/ 下載。
package com.runoob.test; com.runoob.test;
import java.io.File;import java.io.File;
import java.io.IOException;import java.io.IOException;
import java.io.PrintWriter;import java.io.PrintWriter;
import java.util.List;import java.util.List;
import javax.servlet.ServletException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* Servlet implementation class UploadServlet
*/
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 上傳文件存儲目錄
private static final String UPLOAD_DIRECTORY = "upload";
// 上傳配置
private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3; // 3MB
private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB
private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB
/**
* 上傳數據及保存文件
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 檢測是否爲多媒體上傳
if (!ServletFileUpload.isMultipartContent(request)) {
// 如果不是則停止
PrintWriter writer = response.getWriter();
writer.println("Error: 表單必須包含 enctype=multipart/form-data");
writer.flush();
return;
}
// 配置上傳參數
DiskFileItemFactory factory = new DiskFileItemFactory();
// 設置內存臨界值 - 超過後將產生臨時文件並存儲於臨時目錄中
factory.setSizeThreshold(MEMORY_THRESHOLD);
// 設置臨時存儲目錄
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 設置最大文件上傳值
upload.setFileSizeMax(MAX_FILE_SIZE);
// 設置最大請求值 (包含文件和表單數據)
upload.setSizeMax(MAX_REQUEST_SIZE);
// 中文處理
upload.setHeaderEncoding("UTF-8");
// 構造臨時路徑來存儲上傳的文件
// 這個路徑相對當前應用的目錄
String uploadPath = request.getServletContext().getRealPath("./") + File.separator + UPLOAD_DIRECTORY;
// 如果目錄不存在則創建
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdir();
}
try {
// 解析請求的內容提取文件數據
@SuppressWarnings("unchecked")
List<FileItem> formItems = upload.parseRequest(request);
if (formItems != null && formItems.size() > 0) {
// 迭代表單數據
for (FileItem item : formItems) {
// 處理不在表單中的字段
if (!item.isFormField()) {
String fileName = new File(item.getName()).getName();
String filePath = uploadPath + File.separator + fileName;
File storeFile = new File(filePath);
// 在控制檯輸出文件的上傳路徑
System.out.println(filePath);
// 保存文件到硬盤
item.write(storeFile);
request.setAttribute("message",
"文件上傳成功!");
}
}
}
} catch (Exception ex) {
request.setAttribute("message",
"錯誤信息: " + ex.getMessage());
}
// 跳轉到 message.jsp
request.getServletContext().getRequestDispatcher("/message.jsp").forward(
request, response);
}
}
message.jsp文件代碼:
<%@ 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">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上傳結果</title>
</head>
<body>
<center>
<h2>${message}</h2>
</center>
</body>
</html>
編譯運行Servlet,配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<servlet>
<display-name>UploadServlet</display-name>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>com.runoob.test.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/TomcatTest/UploadServlet</url-pattern>
</servlet-mapping>
</web-app>
十四、Servlet處理日期
使用Servlet的最重要的優勢之一是,可以使用核心java中大多數可用方法。例如java提供的java.tuilt包中Date類,封裝了當前的時間和日期。
1、構造函數
Date
或者Date(long millisec)
序號 | 方法 & 描述 |
---|---|
1 | boolean after(Date date) 如果調用的 Date 對象中包含的日期在 date 指定的日期之後,則返回 true,否則返回 false。 |
2 | boolean before(Date date) 如果調用的 Date 對象中包含的日期在 date 指定的日期之前,則返回 true,否則返回 false。 |
3 | Object clone( ) 重複調用 Date 對象。 |
4 | int compareTo(Date date) 把調用對象的值與 date 的值進行比較。如果兩個值是相等的,則返回 0。如果調用對象在 date 之前,則返回一個負值。如果調用對象在 date 之後,則返回一個正值。 |
5 | int compareTo(Object obj) 如果 obj 是 Date 類,則操作等同於 compareTo(Date)。否則,它會拋出一個 ClassCastException。 |
6 | boolean equals(Object date) 如果調用的 Date 對象中包含的時間和日期與 date 指定的相同,則返回 true,否則返回 false。 |
7 | long getTime( ) 返回 1970 年 1 月 1 日以來經過的毫秒數。 |
8 | int hashCode( ) 爲調用對象返回哈希代碼。 |
9 | void setTime(long time) 設置 time 指定的時間和日期,這表示從 1970 年 1 月 1 日午夜以來經過的時間(以毫秒爲單位)。 |
10 | String toString( ) 轉換調用的 Date 對象爲一個字符串,並返回結果。 |
2、獲取當前時間
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class CurrentDate
*/
@WebServlet("/CurrentDate")
public class CurrentDate extends HttpServlet {
private static final long serialVersionUID = 1L;
public CurrentDate() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "顯示當前的日期和時間";
Date date = new Date();
String docType = "<!DOCTYPE html> \n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<h2 align=\"center\">" + date.toString() + "</h2>\n" +
"</body></html>");
}
}
十五、網頁重定向
當文檔移動到新的位置,我們需要向客戶端發送這個新位置時,我們需要使用到網頁重定向。當然,也可能是爲了負載均衡,或者只是爲了簡單的隨機,這些情況都有可能用到網頁重定向。
重定向請求到另一個網頁的最簡單的方式是使用response對象的sendRedirect()方法。下面是該方法的定義:
public void HttpServletResponse.sendRedirect(String location)
throws IOException
該方法把響應連同狀態碼和新網頁的位置發送回瀏覽器,你可以通過把setStatus()和setHeader()方法一起使用來達到同樣的效果:
String site = "http://www.runoob.com" ;
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site);
實例:展示Servlet如何進行網頁重定向到另一個位置:
package com.runoob.test;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class PageRedirect
*/
@WebServlet("/PageRedirect")
public class PageRedirect extends HttpServlet{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
// 要重定向的新位置
String site = new String("http://www.runoob.com");
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site);
}
}
然後配置web.xml,訪問接口看到效果。
十六、Servlet點擊計數器
很多時候,你很有興趣知道網站的某個特定頁面的總點擊量。使用Servlet來計算這些點擊量是非常簡單的。因爲一個Servlet的生命週期是由它運行所在的容器控制的。
一下是實現一個簡單的基於Servlet生命週期的網頁點擊計數器步驟:
-
在 init() 方法中初始化一個全局變量。
-
每次調用 doGet() 或 doPost() 方法時,都增加全局變量。
-
如果需要,您可以使用一個數據庫表來存儲全局變量的值在 destroy() 中。在下次初始化 Servlet 時,該值可在 init() 方法內被讀取。這一步是可選的。
-
如果您只想對一個 session 會話計數一次頁面點擊,那麼請使用 isNew() 方法來檢查該 session 會話是否已點擊過相同頁面。這一步是可選的。
-
您可以通過顯示全局計數器的值,來在網站上展示頁面的總點擊量。這一步是可選的。
實例:實現一個簡單的網頁點擊計數器
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class PageHitCounter
*/
@WebServlet("/PageHitCounter")
public class PageHitCounter extends HttpServlet {
private static final long serialVersionUID = 1L;
private int hitCount;
public void init()
{
// 重置點擊計數器
hitCount = 0;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// 增加 hitCount
hitCount++;
PrintWriter out = response.getWriter();
String title = "總點擊量";
String docType = "<!DOCTYPE html> \n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<h2 align=\"center\">" + hitCount + "</h2>\n" +
"</body></html>");
}
public void destroy()
{
// 這一步是可選的,但是如果需要,您可以把 hitCount 的值寫入到數據庫
}
}
配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>PageHitCounter</servlet-name>
<servlet-class>com.runoob.test.PageHitCounter</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PageHitCounter</servlet-name>
<url-pattern>/TomcatTest/PageHitCounter</url-pattern>
</servlet-mapping>
</web-app>
1、網站點擊計數器
很多時候,你可能有興趣知道整個網站的總點擊量,在Servlet中,這也是非常簡單的,我們使用過濾器做到這一點。
步驟:
-
在過濾器的 init() 方法中初始化一個全局變量。
-
每次調用 doFilter 方法時,都增加全局變量。
-
如果需要,您可以在過濾器的 destroy() 中使用一個數據庫表來存儲全局變量的值。在下次初始化過濾器時,該值可在 init() 方法內被讀取, 這一步是可選的。
在這裏,我們假設 Web 容器將無法重新啓動。如果是重新啓動或 Servlet 被銷燬,點擊計數器將被重置。
// 導入必需的 java 庫
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
public class SiteHitCounter implements Filter{
private int hitCount;
public void init(FilterConfig config)
throws ServletException{
// 重置點擊計數器
hitCount = 0;
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws java.io.IOException, ServletException {
// 把計數器的值增加 1
hitCount++;
// 輸出計數器
System.out.println("網站訪問統計:"+ hitCount );
// 把請求傳回到過濾器鏈
chain.doFilter(request,response);
}
public void destroy()
{
// 這一步是可選的,但是如果需要,您可以把 hitCount 的值寫入到數據庫
}
}
十七、Servlet自動刷新頁面
假設有一個網頁,它是顯示現場比賽成績或股票市場狀況或貨幣兌換率。這些所有類型的頁面,你需要定期刷新網頁。
java Servlet提供了一個機制,使得網頁會在給定的時間間隔自動刷新。
刷新網頁的最簡單的方式是使用響應對象的方法setIntHeader():
public void setIntHeader(String header, int headerValue)
1、自動刷新網頁實例
演示Servlet如何使用setIntHeader()方法設置Refresh頭信息,從而實現自動刷新頁面。
package com.runoob.test;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Refresh
*/
@WebServlet("/Refresh")
public class Refresh extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 設置刷新自動加載的事件間隔爲 5 秒
response.setIntHeader("Refresh", 5);
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
// 獲取當前的時間
Calendar calendar = new GregorianCalendar();
String am_pm;
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
if(calendar.get(Calendar.AM_PM) == 0)
am_pm = "AM";
else
am_pm = "PM";
String CT = hour+":"+ minute +":"+ second +" "+ am_pm;
PrintWriter out = response.getWriter();
String title = "使用 Servlet 自動刷新頁面";
String docType = "<!DOCTYPE html> \n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n"+
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<p>當前時間是:" + CT + "</p>\n");
}
}
十八、發送電子郵件
使用Servlet發送一封電子郵件是很簡單的,但是首先你必須在你的計算機上安裝JavaMail API和Java Activation Framework(JAF)。
-
您可以從 Java 網站下載最新版本的 JavaMail,打開網頁右側有個 Downloads 鏈接,點擊它下載。
-
您可以從 Java 網站下載最新版本的 JAF(版本 1.1.1)
1、發送一封簡單的電子郵件
// 文件名 SendEmail.java
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
public class SendEmail extends HttpServlet{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// 收件人的電子郵件 ID
String to = "[email protected]";
// 發件人的電子郵件 ID
String from = "[email protected]";
// 假設您是從本地主機發送電子郵件
String host = "localhost";
// 獲取系統的屬性
Properties properties = System.getProperties();
// 設置郵件服務器
properties.setProperty("mail.smtp.host", host);
// 獲取默認的 Session 對象
Session session = Session.getDefaultInstance(properties);
// 設置響應內容類型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try{
// 創建一個默認的 MimeMessage 對象
MimeMessage message = new MimeMessage(session);
// 設置 From: header field of the header.
message.setFrom(new InternetAddress(from));
// 設置 To: header field of the header.
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
// 設置 Subject: header field
message.setSubject("This is the Subject Line!");
// 現在設置實際消息
message.setText("This is actual message");
// 發送消息
Transport.send(message);
String title = "發送電子郵件";
String res = "成功發送消息...";
String docType = "<!DOCTYPE html> \n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<p align=\"center\">" + res + "</p>\n" +
"</body></html>");
}catch (MessagingException mex) {
mex.printStackTrace();
}
}
}
詳細的應用當你用到的時候可以自行查閱更加清楚的信息。
十九、Servlet包
涉及到WEB-INF子目錄的Web應用程序結構是所有的Java web應用程序的標準,並由Servlet API規範制定。給定一個頂級目錄名myapp,目錄結構如下:
/myapp
/images
/WEB-INF
/classes
/lib
WEB-INF子目錄中包含應用程序的部署描述符,名爲web.xml。所有的HTML文件都位於頂層目錄myapp下。對於admin用戶,你會發現ROOT目錄是myApp的父目錄(這個是eclipse上的)。
1、創建包中的Servlet
WEB-INF/classes目錄包含了所有的Servlet類和其它類文件。
2、編譯、部署就是之前我們一直在做的工作。
二十、調試
測試/調試Servlte始終是開發過程中的難點。Servlet往往涉及大量的客戶端/服務器交互,可能會發生錯誤但又難以重現。所以這裏有一些建議。
1、Systeem.out.println()
System.out.println() 是作爲一個標記來使用的,用來測試一段特定的代碼是否被執行。我們也可以打印出變量的值。此外:
-
由於 System 對象是核心 Java 對象的一部分,它可以在不需要安裝任何額外類的情況下被用於任何地方。這包括 Servlet、JSP、RMI、EJB's、普通的 Beans 和類,以及獨立的應用程序。
-
與在斷點處停止不同,寫入到 System.out 不會干擾到應用程序的正常執行流程,這使得它在時序是至關重要的時候顯得尤爲有價值。
2、消息日誌
使用適當的日誌記錄方法來記錄所有調試、警告和錯誤信息,推薦使用log4J來記錄所有的消息。
3、當然,也可以調試,使用註解等等。
二十一、國際化
我們先看三個重要術語:
-
國際化(i18n):這意味着一個網站提供了不同版本的翻譯成訪問者的語言或國籍的內容。
-
本地化(l10n):這意味着向網站添加資源,以使其適應特定的地理或文化區域,例如網站翻譯成印地文(Hindi)。
-
區域設置(locale):這是一個特殊的文化或地理區域。它通常指語言符號後跟一個下劃線和一個國家符號。例如 "en_US" 表示針對 US 的英語區域設置。
1、檢查區域設置
序號 | 方法 & 描述 |
---|---|
1 | String getCountry() 該方法以 2 個大寫字母形式的 ISO 3166 格式返回該區域設置的國家/地區代碼。 |
2 | String getDisplayCountry() 該方法返回適合向用戶顯示的區域設置的國家的名稱。 |
3 | String getLanguage() 該方法以小寫字母形式的 ISO 639 格式返回該區域設置的語言代碼。 |
4 | String getDisplayLanguage() 該方法返回適合向用戶顯示的區域設置的語言的名稱。 |
5 | String getISO3Country() 該方法返回該區域設置的國家的三個字母縮寫。 |
6 | String getISO3Language() 該方法返回該區域設置的語言的三個字母的縮寫。 |
JSP教程
JSP與PHP、ASP、ASP.NET等語言類似,運行在服務端的語言。
JSP(全稱Java Server Pages)是由Sun Microsystems公司倡導和許多公司參與共同建造的一種使軟件開發者可以響應客戶端請求,而動態生成HTML、XML或或其它格式文檔的Web網頁的技術標準。
JSP技術是以java語言作爲腳本語言的,JSP網頁爲整個服務器端的java庫單元提供了一個接口來服務於HTTP的應用程序。
JSP文件後綴名爲*.jsp,開發的WEB應用可以跨平臺使用,既可以運行在Linux上也能運行在Windows上。
來第一個JSP程序
<html>
<head>
<title>第一個 JSP 程序</title>
</head>
<body>
<%
out.println("Hello World!");
%>
</body>
</html>
一、JSP簡介
1、什麼是Java Server Pages?
JSP全稱Java Server Pages,是一種動態網頁開發技術。它使用JSP標籤在HTML網頁中插入java代碼。標籤通常以<%開頭,以%>結束。
JSP是一種java servlet,主要用於實現java web應用程序的用戶界面部分。網頁開發者們通過結合HTML代碼、XHTML代碼、XML元素以及嵌入JSP操作和命令來編寫JSP。
JSP通過網頁表單獲取用戶輸入數據、訪問數據庫以及其他數據源,然後動態創建網頁。
JSP標籤有多種功能,比如訪問數據庫、記錄用戶選擇信息、訪問JavaBeans組件等,還可以在不同的網頁中傳遞控制信息和共享信息。
2、爲什麼使用JSP?
JSP程序與CGI程序有着相似的功能,但和CGI程序相比,JSP程序有如下優勢:
-
性能更加優越,因爲JSP可以直接在HTML網頁中動態嵌入元素而不需要單獨引用CGI文件。
-
服務器調用的是已經編譯好的JSP文件,而不像CGI/Perl那樣必須先載入解釋器和目標腳本。
-
JSP 基於Java Servlet API,因此,JSP擁有各種強大的企業級Java API,包括JDBC,JNDI,EJB,JAXP等等。
-
JSP頁面可以與處理業務邏輯的 Servlet 一起使用,這種模式被Java servlet 模板引擎所支持。
最後,JSP是Java EE不可或缺的一部分,是一個完整的企業級應用平臺。這意味着JSP可以用最簡單的方式來實現最複雜的應用。
3、JSP的優勢
-
與ASP相比:JSP有兩大優勢。首先,動態部分用Java編寫,而不是VB或其他MS專用語言,所以更加強大與易用。第二點就是JSP易於移植到非MS平臺上。
-
與純 Servlet 相比:JSP可以很方便的編寫或者修改HTML網頁而不用去面對大量的println語句。
-
與SSI相比:SSI無法使用表單數據、無法進行數據庫鏈接。
-
與JavaScript相比:雖然JavaScript可以在客戶端動態生成HTML,但是很難與服務器交互,因此不能提供複雜的服務,比如訪問數據庫和圖像處理等等。
-
與靜態HTML相比:靜態HTML不包含動態信息。
二、開發環境搭建
這裏的話其實也就是配置好java的開發環境就好,如果你需要在eclipse裏面配置環境,可以搜索相關的教程,如果是IEDA就好很多。
但這裏在列出一下Tomcat的目錄結構回憶一下:
-
bin:二進制執行文件。裏面最常用的文件是startup.bat,如果是 Linux 或 Mac 系統啓動文件爲 startup.sh。
-
conf:配置目錄。裏面最核心的文件是server.xml。可以在裏面改端口號等。默認端口號是8080,也就是說,此端口號不能被其他應用程序佔用。
-
lib:庫文件。tomcat運行時需要的jar包所在的目錄
-
logs:日誌
-
temp:臨時產生的文件,即緩存
-
webapps:web的應用程序。web應用放置到此目錄下瀏覽器可以直接訪問
-
work:編譯以後的class文件。
三、JSP結構
網絡服務器需要一個JSP引擎,也就是一個容器來處理JSP頁面。容器負責截獲對JSP頁面的請求。JSP容器與Web服務器協同合作,爲JSP的正常運行提供必要的運行環境和其它服務,並且能夠正確識別專屬於JSP網頁的特殊元素。
1、JSP處理
Web服務器是如何使用JSP來創建網頁的:
-
就像其他普通的網頁一樣,您的瀏覽器發送一個 HTTP 請求給服務器。
-
Web 服務器識別出這是一個對 JSP 網頁的請求,並且將該請求傳遞給 JSP 引擎。通過使用 URL或者 .jsp 文件來完成。
-
JSP 引擎從磁盤中載入 JSP 文件,然後將它們轉化爲 Servlet。這種轉化只是簡單地將所有模板文本改用 println() 語句,並且將所有的 JSP 元素轉化成 Java 代碼。
-
JSP 引擎將 Servlet 編譯成可執行類,並且將原始請求傳遞給 Servlet 引擎。
-
Web 服務器的某組件將會調用 Servlet 引擎,然後載入並執行 Servlet 類。在執行過程中,Servlet 產生 HTML 格式的輸出並將其內嵌於 HTTP response 中上交給 Web 服務器。
-
Web 服務器以靜態 HTML 網頁的形式將 HTTP response 返回到您的瀏覽器中。
-
最終,Web 瀏覽器處理 HTTP response 中動態產生的HTML網頁,就好像在處理靜態網頁一樣。
一般情況下,JSP引擎會檢查JSP文件對應的Servlet是否已經存在,並且檢查JSP文件的修改日期是否早於Servlet。如果JSP文件的修改日期早於對應的Servlet,那麼容器就可以確定JSP文件沒有被修改過並且Servlet有效。這使得整個流程與其它腳本語言(比如PHP)相比要高效快捷一些。
總的來說,JSP網頁就是用另一種方式來編寫Servlet而不用成爲java編程高手。除了解釋階段外,JSP網頁幾乎可以被當成一個普通的Servlet來對待。
四、JSP生命週期
理解JSP底層功能的關鍵就是去理解它們所遵循的生命週期。
JSP生命週期就是從創建到銷燬的整個過程,類似於servlet生命週期,區別在於JSP生命週期還包括將JSP文件編譯成servlet。
-
編譯階段:
servlet容器編譯servlet源文件,生成servlet類
-
初始化階段:
加載與JSP對應的servlet類,創建其實例,並調用它的初始化方法
-
執行階段:
調用與JSP對應的servlet實例的服務方法
-
銷燬階段:
調用與JSP對應的servlet實例的銷燬方法,然後銷燬servlet實例
1、JSP編譯
當瀏覽器請求JSP頁面時,JSP引擎會首先去檢查是否需要編譯這個文件。如果這個文件沒有被編譯過,或者在上次編譯後被更改過,則編譯這個JSP文件。
編譯的過程包括三個步驟:
-
解析JSP文件。
-
將JSP文件轉爲servlet。
-
編譯servlet。
2、JSP初始化
容器載入JSP文件後,它會在爲請求提供任何服務前調用jspInit()方法。如果你需要執行自定義的JSP初始化任務,複寫jspInit()方法就行:
public void jspInit(){
// 初始化代碼
}
一般來講程序只初始化依次,servlet也是如此。通常情況下你可以在jspInit()方法中初始化數據庫連接、打開文件和創建查詢表。
3、JSP執行
這一階段描述了JSP生命週期中一切與請求相關的交互行爲,知道被銷燬。
當JSP網頁完成初始化後,JSP引擎會調用_jspService()方法。
_jspService()方法需要一個HttpServletRequest對象和一個HttpServletResponse對象作爲它的參數,就像下面這樣:
void _jspService(HttpServletRequest request,
HttpServletResponse response)
{
// 服務端處理代碼
}
_jspService()方法在每個request中被調用一次並且負責產生與之對象的response,並且它還負責產生所有7個HTTP方法的迴應,比如GET、POST、DELETE等等。
4、JSP清理
JSP生命週期的銷燬階段描述了當一個JSP網頁從容器中被移除時發生的一切。
jspDestroy()方法在JSP中等價於servlet中的銷燬方法。當你需要執行任何清理工作時複寫jspDestroy()方法,比如釋放數據庫連接或者關閉文件夾等等。
public void jspDestroy()
{
// 清理代碼
}
5、實例
JSP生命週期代碼實例:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<title>life.jsp</title>
</head>
<body>
<%!
private int initVar=0;
private int serviceVar=0;
private int destroyVar=0;
%>
<%!
public void jspInit(){
initVar++;
System.out.println("jspInit(): JSP被初始化了"+initVar+"次");
}
public void jspDestroy(){
destroyVar++;
System.out.println("jspDestroy(): JSP被銷燬了"+destroyVar+"次");
}
%>
<%
serviceVar++;
System.out.println("_jspService(): JSP共響應了"+serviceVar+"次請求");
String content1="初始化次數 : "+initVar;
String content2="響應客戶請求次數 : "+serviceVar;
String content3="銷燬次數 : "+destroyVar;
%>
<h1>菜鳥教程 JSP 測試實例</h1>
<p><%=content1 %></p>
<p><%=content2 %></p>
<p><%=content3 %></p>
</body>
</html>
五、JSP語法
1、腳本程序
腳本程序可以包含任意量的Java語句、變量、方法或表達式,只要它們在腳本語言中是有效的。
腳本程序的語法格式:
<% 代碼片段 %>
或者,你也可以編寫與其等價的XML語句,就像這樣:
<jsp:scriptlet>
代碼片段
</jsp:scriptlet>
任何文本、HTML標籤、JSP元素必須寫在腳本程序的外面:
<html>
<head><title>Hello World</title></head>
<body>
Hello World!<br/>
<%
out.println("Your IP address is " + request.getRemoteAddr());
%>
</body>
</html>
2、中文編碼問題
如果我們要在頁面正常顯示中文,我們需要在JSP文件頭部添加以下代碼:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
3、JSP聲明
一個聲明語法可以聲明一個或多個變量、方法,供後面的Java代碼使用。在JSP文件中,你必須先聲明這些變量和方法然後才能使用它們。
JSP聲明的語法格式:
<%! declaration;[declaration; ]+...%>
或者你也可以編寫與其等價的XML語句:
<jsp:declaration>
代碼片段
</jsp:declaration>
示例:
<%! int i = 0; %>
<%! int a, b, c; %>
<%! Circle a = new Circle(2.0); %>
4、JSP表達式
一個JSP表達式中包含的腳本語言表達式,先被轉換成String,然後插入到表達式出現的地方。
由於表達式的值會被轉化成String,所以你可以在一個文本行中使用表達式而不用去管它是否是HTML標籤。
表達式元素中可以包含任何符合Java語言規範的表達式,但是不能使用分號來結束表達式。
JSP表達式的語法格式:
<%=表達式 %>
程序示例:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<p>
今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>
</body>
</html>
運行後得到:
今天的日期是:2020-6-3 13:40:07
5、JSP註釋
JSP註釋主要有兩個作用:爲代碼作註釋以及將某段代碼註釋掉。
JSP註釋的語法格式:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<%-- 該部分註釋在網頁中不會被顯示--%>
<p>
今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>
</body>
</html>
語法 | 描述 |
---|---|
<%-- 註釋 --%> | JSP註釋,註釋內容不會被髮送至瀏覽器甚至不會被編譯 |
<!-- 註釋 --> | HTML註釋,通過瀏覽器查看網頁源代碼時可以看見註釋內容 |
<\% | 代表靜態 <%常量 |
%> | 代表靜態 %> 常量 |
' | 在屬性中使用的單引號 |
" | 在屬性中使用的雙引號 |
6、JSP指令
JSP指令用來設置與整個JSP頁面相關的屬性。
JSP指令語法格式:
<%@ directive attribute="value"%>
這裏有三種指令標籤:
指令 | 描述 |
---|---|
<%@ page ... %> | 定義頁面的依賴屬性,比如腳本語言、error頁面、緩存需求等等 |
<%@ include ... %> | 包含其他文件 |
<%@ taglib ... %> | 引入標籤庫的定義,可以是自定義標籤 |
7、JSP行爲
JSP行爲標籤使用XML語法結構來控制servlet引擎。它能動態插入一個文本,重用JavaBean組件,引導用戶去另一個界面,爲Java插件產生相關的HTML等等。
行爲標籤只有一種語法格式,爲:
<jsp:action_name attribute="value" />
行爲標籤基本上是一些預先就定義好的函數,下標羅列了一些可用的JSP行爲標籤:
語法 | 描述 |
---|---|
jsp:include | 用於在當前頁面中包含靜態或動態資源 |
jsp:useBean | 尋找和初始化一個JavaBean組件 |
jsp:setProperty | 設置 JavaBean組件的值 |
jsp:getProperty | 將 JavaBean組件的值插入到 output中 |
jsp:forward | 從一個JSP文件向另一個文件傳遞一個包含用戶請求的request對象 |
jsp:plugin | 用於在生成的HTML頁面中包含Applet和JavaBean對象 |
jsp:element | 動態創建一個XML元素 |
jsp:attribute | 定義動態創建的XML元素的屬性 |
jsp:body | 定義動態創建的XML元素的主體 |
jsp:text | 用於封裝模板數據 |
8、JSP隱含對象
JSP支持九個自動定義的內聯,稱爲隱含對象:
對象 | 描述 |
---|---|
request | HttpServletRequest類的實例 |
response | HttpServletResponse類的實例 |
out | PrintWriter類的實例,用於把結果輸出至網頁上 |
session | HttpSession類的實例 |
application | ServletContext類的實例,與應用上下文有關 |
config | ServletConfig類的實例 |
pageContext | PageContext類的實例,提供對JSP頁面所有對象以及命名空間的訪問 |
page | 類似於Java類中的this關鍵字 |
Exception | Exception類的對象,代表發生錯誤的JSP頁面中對應的異常對象 |
9、控制流語句
JSP提供對java語言的全面支持,所以這裏我們就看看具體是怎麼使用的。
1)判斷語句:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%! int day = 3; %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<h3>IF...ELSE 實例</h3>
<% if (day == 1 | day == 7) { %>
<p>今天是週末</p>
<% } else { %>
<p>今天不是週末</p>
<% } %>
</body>
</html>
2)For循環實例
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%! int fontSize=0; %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<h3>While 循環實例</h3>
<%while ( fontSize <= 3){ %>
<font color="green" size="<%= fontSize %>">
菜鳥教程
</font><br />
<%fontSize++;%>
<%}%>
</body>
</html>
10、運算符和字面量
JSP運算符和java是一致的,字面量也就是:
-
布爾值(boolean):true 和 false;
-
整型(int):與 Java 中的一樣;
-
浮點型(float):與 Java 中的一樣;
-
字符串(string):以單引號或雙引號開始和結束;
-
Null:null。
六、JSP指令
JSP指令用來設置整個JSP頁面相關的屬性,如網頁的編碼方式和腳本語言。
語法格式:
<%@ directive attribute="value" %>
指令可以有很多個屬性,它們以鍵值對的形式存在,並用逗號隔開。
JSP中的三種指令標籤:
指令 | 描述 |
---|---|
<%@ page ... %> | 定義網頁依賴屬性,比如腳本語言、error頁面、緩存需求等等 |
<%@ include ... %> | 包含其他文件 |
<%@ taglib ... %> | 引入標籤庫的定義 |
1、Page指令
Page指令爲容器提供當前頁面的使用說明。一個JSP頁面可以包含很多個page指令。
語法格式:
<%@ page attribute="value" %>
1)屬性
屬性 | 描述 |
---|---|
buffer | 指定out對象使用緩衝區的大小 |
autoFlush | 控制out對象的 緩存區 |
contentType | 指定當前JSP頁面的MIME類型和字符編碼 |
errorPage | 指定當JSP頁面發生異常時需要轉向的錯誤處理頁面 |
isErrorPage | 指定當前頁面是否可以作爲另一個JSP頁面的錯誤處理頁面 |
extends | 指定servlet從哪一個類繼承 |
import | 導入要使用的Java類 |
info | 定義JSP頁面的描述信息 |
isThreadSafe | 指定對JSP頁面的訪問是否爲線程安全 |
language | 定義JSP頁面所用的腳本語言,默認是Java |
session | 指定JSP頁面是否使用session |
isELIgnored | 指定是否執行EL表達式 |
isScriptingEnabled | 確定腳本元素能否被使用 |
2、Include指令
JSP可以通過include指令來包含其他文件。被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是該JSP文件的一部分,會被同時編譯執行。
Include指令的語法格式:
<%@ include file="文件相對 url 地址" %>
3、Taglib指令
JSP API允許用戶自定義標籤,一個自定義標籤庫就是自定義標籤的集合。
Taglib指令引入一個自定義標籤集合的定義,包括庫路徑、自定義標籤。
Taglib指令的語法:
<%@ taglib uri="uri" prefix="prefixOfTag" %>
uri屬性確定標籤庫的位置,prefix屬性指定標籤庫的前綴。
等價的XML語法:
<jsp:directive.taglib uri="uri" prefix="prefixOfTag" />
七、JSP動作元素
與JSP指令元素不同的是,JSP動作元素在請求處理階段起作用。JSP動作元素是用XML語法寫的。
利用JSP動作可以動態地插入文件、重用JavaBean組件、把用戶重定向到另外的頁面、爲Java插件生成HTML代碼。
語法:
<jsp:action_name attribute="value" />
動作元素基本都是預定義的函數,JSP規範定義了一系列的標準動作,它用JSP作爲前綴,可用的標準動作元素如下:
語法 | 描述 |
---|---|
jsp:include | 在頁面被請求的時候引入一個文件。 |
jsp:useBean | 尋找或者實例化一個JavaBean。 |
jsp:setProperty | 設置JavaBean的屬性。 |
jsp:getProperty | 輸出某個JavaBean的屬性。 |
jsp:forward | 把請求轉到一個新的頁面。 |
jsp:plugin | 根據瀏覽器類型爲Java插件生成OBJECT或EMBED標記。 |
jsp:element | 定義動態XML元素 |
jsp:attribute | 設置動態定義的XML元素屬性。 |
jsp:body | 設置動態定義的XML元素內容。 |
jsp:text | 在JSP頁面和文檔中使用寫入文本的模板 |
1、常見的屬性
所有的動作要素都有兩個屬性:id屬性和scope屬性。
-
id屬性:
id屬性是動作元素的唯一標識,可以在JSP頁面中引用。動作元素創建的id值可以通過PageContext來調用。
-
scope屬性:
該屬性用於識別動作元素的生命週期。 id屬性和scope屬性有直接關係,scope屬性定義了相關聯id對象的壽命。 scope屬性有四個可能的值: (a) page, (b)request, (c)session, 和 (d) application。
2、<jsp:include>
動作元素
<jsp:include>
動作元素用來包含靜態和動態的文件。該動作把指定文件插入正在生成的頁面。語法格式如下:
<jsp:include page="相對 URL 地址"flush="true" />
include指令是在JSP文件被轉換成Servlet的時候引入文件,而這裏的jsp:include動作不同,插入文件的時間是在頁面被請求的時候。
屬性:
屬性 | 描述 |
---|---|
page | 包含在頁面中的相對URL地址。 |
flush | 布爾屬性,定義在包含資源前是否刷新緩存區 |
實例:
有date.jsp文件代碼:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<p>
今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>
有main.jsp文件代碼:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<h2>include 動作實例</h2>
<jsp:include page="date.jsp" flush="true" />
</body>
</html>
3、<jsp:useBean>
動作元素
jsp:useBean動作用來加載一個將在JSP頁面中使用的JavaBean。
這個功能非常有用,因爲它使得我們可以發揮Java組件複用的優勢。
jsp:userBean動作最簡單的語法爲:
<jsp:useBean id="name" class="package.class" />
在類載入後,我們就可以通過jsp:setProperty和jsp:getProperty來修改和檢索bean的屬性。
屬性 | 描述 |
---|---|
class | 指定Bean的完整包名。 |
type | 指定將引用該對象變量的類型。 |
beanName | 通過 java.beans.Beans 的 instantiate() 方法指定Bean的名字。 |
4、<jsp:setProperty>
動作元素
jsp:setProperty用來設置已經實例化的Bean對象的屬性,有兩種用法。首先,你可以在jsp:useBean元素的外面(後面)使用jsp:setProperty,如下所示:
<jsp:useBean id="myName" ... />
...
<jsp:setProperty name="myName" property="someProperty" .../>
此時,不管jsp:useBean是找到了一個現有的Bean,還是新建了一個Bean實例,jsp:setProperty都會執行。
第二種用法是把jsp:setProperty放入jap:useBean元素的內部,如下:
<jsp:useBean id="myName" ... >
...
<jsp:setProperty name="myName" property="someProperty" .../>
</jsp:useBean>
此時,jsp:setProperty只有在新建Bean實例時纔會執行,如果是使用現有實例則不執行jsp:setProperty。
jsp:setProperty動作有四個屬性:
屬性 | 描述 |
---|---|
name | name屬性是必需的。它表示要設置屬性的是哪個Bean。 |
property | property屬性是必需的。它表示要設置哪個屬性。有一個特殊用法:如果property的值是"*",表示所有名字和Bean屬性名字匹配的請求參數都將被傳遞給相應的屬性set方法。 |
value | value 屬性是可選的。該屬性用來指定Bean屬性的值。字符串數據會在目標類中通過標準的valueOf方法自動轉換成數字、boolean、Boolean、 byte、Byte、char、Character。例如,boolean和Boolean類型的屬性值(比如"true")通過 Boolean.valueOf轉換,int和Integer類型的屬性值(比如"42")通過Integer.valueOf轉換。 value和param不能同時使用,但可以使用其中任意一個。 |
param | param 是可選的。它指定用哪個請求參數作爲Bean屬性的值。如果當前請求沒有參數,則什麼事情也不做,系統不會把null傳遞給Bean屬性的set方法。因此,你可以讓Bean自己提供默認屬性值,只有當請求參數明確指定了新值時才修改默認屬性值。 |
5、<jsp:getProperty>
動作元素
jsp:getProperty動作提取指定Bean屬性的值,轉換成字符串,然後輸出。語法格式如下:
<jsp:useBean id="myName" ... />
...
<jsp:getProperty name="myName" property="someProperty" .../>
getProperty屬性:
屬性 | 描述 |
---|---|
name | 要檢索的Bean屬性名稱。Bean必須已定義。 |
property | 表示要提取Bean屬性的值 |
6、<jsp:forward>
動作元素
jsp:forward動作把請求轉到另外的頁面。jsp:forward標記只有一個屬性page。語法格式如下:
<jsp:forward page="相對 URL 地址" />
屬性 | 描述 |
---|---|
page | page屬性包含的是一個相對URL。page的值既可以直接給出,也可以在請求的時候動態計算,可以是一個JSP頁面或者一個 Java Servlet. |
7、<jsp:plugin>
動作元素
jsp:plugin動作用來根據瀏覽器的類型,插入通過java插件運行Java Applet所必需的OBJECT或EMBED元素。如果需要的插件不存在,它會下載插件,然後執行Java組件。Java組件可以是一個applet或一個JavaBean。plugin動作有多個對應HTML元素的屬性用於格式化Java組件。param元素可用於向Applet或Bean傳遞參數。
例如:
<jsp:plugin type="applet" codebase="dirname" code="MyApplet.class"
width="60" height="80">
<jsp:param name="fontcolor" value="red" />
<jsp:param name="background" value="black" />
<jsp:fallback>
Unable to initialize Java Plugin
</jsp:fallback>
</jsp:plugin>
8、<jsp:element>
、<jap:attribute>
、<jsp:body>
動作元素
<jsp:element>
、<jap:attribute>
、<jsp:body>
動作元素動態定義XML元素。動態是非常重要的,這就意味着XML元素在編譯時是動態生成的而非靜態。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<jsp:element name="xmlElement">
<jsp:attribute name="xmlElementAttr">
屬性值
</jsp:attribute>
<jsp:body>
XML 元素的主體
</jsp:body>
</jsp:element>
</body>
</html>
9、<jsp:text>
動作元素
<jsp:text>
動作元素允許在JSP頁面和文檔中使用寫入文本的模板,語法格式如下:
<jsp:text>模板數據</jsp:text>
以上文本模板不能包含重複元素,只能包含文本和EL表達式。請注意,在XML文件中,你不能使用表達式如${whatever>0},因爲>符號是非法的。你可以使用${wharever gt 0}表達式或者嵌入一個在CDATA部分的值。
<jsp:text><![CDATA[<br>]]></jsp:text>
如果你需要在XHTML中聲明DOCTYPPE,必須使用到<jsp:text>
動作元素,實例如下:
<jsp:text><![CDATA[<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">]]>
</jsp:text>
<head><title>jsp:text action</title></head>
<body>
<books><book><jsp:text>
Welcome to JSP Programming
</jsp:text></book></books>
</body>
</html>
八、JSP隱式對象
JSP隱式對象是JSP容器爲每個頁面提供的java對象,開發者可以直接使用它們而不用顯示聲明。JSP隱式對象也被稱爲預定義變量。
JSP所支持的九大隱式對象:
對象 | 描述 |
---|---|
request | HttpServletRequest 接口的實例 |
response | HttpServletResponse 接口的實例 |
out | JspWriter類的實例,用於把結果輸出至網頁上 |
session | HttpSession類的實例 |
application | ServletContext類的實例,與應用上下文有關 |
config | ServletConfig類的實例 |
pageContext | PageContext類的實例,提供對JSP頁面所有對象以及命名空間的訪問 |
page | 類似於Java類中的this關鍵字 |
Exception | Exception類的對象,代表發生錯誤的JSP頁面中對應的異常對象 |
九、JSP客戶端請求
當瀏覽器請求一個網頁時,它會向服務器發送一系列不能被直接讀取的信息,因爲這些信息是作爲HTTP信息頭的一部分來傳送的。
信息 | 描述 |
---|---|
Accept | 指定瀏覽器或其他客戶端可以處理的MIME類型。它的值通常爲 image/png 或 image/jpeg |
Accept-Charset | 指定瀏覽器要使用的字符集。比如 ISO-8859-1 |
Accept-Encoding | 指定編碼類型。它的值通常爲 gzip 或compress |
Accept-Language | 指定客戶端首選語言,servlet會優先返回以當前語言構成的結果集,如果servlet支持這種語言的話。比如 en,en-us,ru等等 |
Authorization | 在訪問受密碼保護的網頁時識別不同的用戶 |
Connection | 表明客戶端是否可以處理HTTP持久連接。持久連接允許客戶端或瀏覽器在一個請求中獲取多個文件。Keep-Alive 表示啓用持久連接 |
Content-Length | 僅適用於POST請求,表示 POST 數據的字節數 |
Cookie | 返回先前發送給瀏覽器的cookies至服務器 |
Host | 指出原始URL中的主機名和端口號 |
If-Modified-Since | 表明只有當網頁在指定的日期被修改後客戶端才需要這個網頁。 服務器發送304碼給客戶端,表示沒有更新的資源 |
If-Unmodified-Since | 與If-Modified-Since相反, 只有文檔在指定日期後仍未被修改過,操作纔會成功 |
Referer | 標誌着所引用頁面的URL。比如,如果你在頁面1,然後點了個鏈接至頁面2,那麼頁面1的URL就會包含在瀏覽器請求頁面2的信息頭中 |
User-Agent | 用來區分不同瀏覽器或客戶端發送的請求,並對不同類型的瀏覽器返回不同的內容 |
至於其中的HttpServletRequest類與HTTP信息頭與servlet是一致的。
十、服務器響應
Response響應對象主要將JSP容器處理後的結果傳回到客戶端。可以通過response變量設置HTTP的狀態和向客戶端發送數據,如Cookie、HTTP文件頭信息。
其中響應頭、HttpServletResponse類都是和servlet一樣的,這裏我們看看HTTP響應頭程序示例:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<h2>自動刷新實例</h2>
<%
// 設置每隔5秒自動刷新
response.setIntHeader("Refresh", 5);
// 獲取當前時間
Calendar calendar = new GregorianCalendar();
String am_pm;
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
if(calendar.get(Calendar.AM_PM) == 0)
am_pm = "AM";
else
am_pm = "PM";
String CT = hour+":"+ minute +":"+ second +" "+ am_pm;
out.println("當前時間: " + CT + "\n");
%>
</body>
</html>
HTTP狀態碼、表單處理、過濾器、Cookie處理、Session、文件上傳、日期處理、頁面重定向、點擊量統計、自動刷新、發送郵件等部分和servlet是一致的,只是代碼部分符合的是JSP語法規則而已。
十一、JSP標準標籤庫(JSTL)
JSP標準標籤庫(JSTL)是一個JSP標籤集合,它封裝了JSP應用的核心功能。
JSTL支持通用的、結構化的任務,比如迭代,條件判斷,XML文檔操作,國際化標籤,SQL標籤。除了這些,它還提供了一個框架來使用集成JSTL的自定義標籤。
根據JSTL標籤所提供的功能,可以將其分爲5個類別:
-
核心標籤
-
格式化標籤
-
SQL 標籤
-
XML 標籤
-
JSTL 函數
1、JSTL庫安裝
Apache Tomcat安裝JSTL庫步驟如下:
從Apache的標準標籤庫中下載的二進包(jakarta-taglibs-standard-current.zip)。解壓之後,將jakarta-taglibs-standard-1.1.2/lib下的兩個jar文件:standard.jar和jstl.jar文件拷貝到/WEB-INF/lib下。配置web.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
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-app_2_4.xsd">
<jsp-config>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
<taglib-location>/WEB-INF/fmt.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/fmt-rt</taglib-uri>
<taglib-location>/WEB-INF/fmt-rt.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/c.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/core-rt</taglib-uri>
<taglib-location>/WEB-INF/c-rt.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/sql</taglib-uri>
<taglib-location>/WEB-INF/sql.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/sql-rt</taglib-uri>
<taglib-location>/WEB-INF/sql-rt.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/x</taglib-uri>
<taglib-location>/WEB-INF/x.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/x-rt</taglib-uri>
<taglib-location>/WEB-INF/x-rt.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
使用任何庫,你必須在每個JSP文件中的頭部包含<taglib>
標籤。
2、核心標籤
核心標籤是最常用的JSTL標籤。引用核心標籤庫的語法如下:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
標籤 | 描述 |
---|---|
<c:out> |
用於在JSP中顯示數據,就像<%=...> |
<c:set> |
用於保存數據 |
<c:remove> |
用於刪除數據 |
<c:catch> |
用來處理產生錯誤的異常狀況,並且將錯誤信息存儲起來 |
<c:if> |
與我們一般程序中用的if一樣 |
<c:choose> |
本身值當做<c:when> 和<c:otherwise> 的父標籤 |
<c:when> |
<c:choose> 的字標籤,用來判斷條件是否成立 |
<c:ohterwise> |
<c:choose> 的字標籤,接在<c:when> 標籤判斷爲false時被執行 |
<c:import> |
檢索一個絕對或相對URL,然後將其內容暴露給頁面 |
<c:forEach> |
基礎迭代標籤,接受多種結合類型 |
<c:forTokens> |
根據指定的分隔符來分隔內容並迭代輸出 |
<c:param> |
用來給包含或重定向的頁面傳遞參數 |
<c:redirect> |
重定向至一個新的URL |
<c:url> |
使用可選的查詢參數來創造一個URL |
3、格式化標籤
JSTL格式化標籤用來格式化並輸出文本、日期、時間、數字。引用格式化標籤庫的語法如下:
%@ taglib prefix="fmt"
uri="http://java.sun.com/jsp/jstl/fmt" %>
標籤 | 描述 |
---|---|
<fmt:formatNumber> |
使用指定的格式或精度格式化數字 |
<fmt:parseNumber> |
解析一個代表着數字,貨幣或百分比的字符串 |
<fmt:formatDate> |
使用指定的風格或模式格式化日期和時間 |
<fmt:parseDate> |
解析一個代表着日期或時間的字符串 |
<fmt:bundle> |
綁定資源 |
<fmt:setLocale> |
指定地區 |
<fmt:setBundle> |
綁定資源 |
<fmt:timeZone> |
指定時區 |
<fmt:setTimeZone> |
指定時區 |
<fmt:message> |
顯示資源配置文件信息 |
<fmt:requestEncoding> |
設置request的字符編碼 |
4、SQL標籤。
JSTL SQL標籤庫提桶了與關係型數據庫(Oracle,MySQL,SQL Server等等)進行交互的標籤。引用SQL標籤庫的語法如下:
<%@ taglib prefix="sql"
uri="http://java.sun.com/jsp/jstl/sql" %>
標籤 | 描述 |
---|---|
<sql:setDataSource> |
指定數據源 |
<sql:query> |
運行SQL查詢語句 |
<sql:update> |
運行SQL更新語句 |
<sql:param> |
將SQL語句中的參數設爲指定值 |
<sql:dateParam> |
將SQL語句中的日期參數設爲指定的java.util.Date 對象值 |
<sql:ransaction> |
在共享數據庫連接中提供嵌套的數據庫行爲元素,將所有語句以一個事務的形式來運行 |
5、XML標籤
JSTL XML標籤庫提供了創建和操作XML文檔的標籤。引用XML標籤庫的語法如下:
<%@ taglib prefix="x"
uri="http://java.sun.com/jsp/jstl/xml" %>
x:out | 與<%= ... >,類似,不過只用於XPath表達式 |
---|---|
x:parse | 解析 XML 數據 |
x:set | 設置XPath表達式 |
x:if | 判斷XPath表達式,若爲真,則執行本體中的內容,否則跳過本體 |
x:forEach | 迭代XML文檔中的節點 |
x:choose | x:when和x:otherwise的父標籤 |
x:when | x:choose的子標籤,用來進行條件判斷 |
x:otherwise | x:choose的子標籤,當x:when判斷爲false時被執行 |
x:transform | 將XSL轉換應用在XML文檔中 |
x:param | 與x:transform共同使用,用於設置XSL樣式表 |
6、JSTL函數
JSTL包含一系列標準函數,大部分是通用的字符串處理函數。引用JSTL函數庫的語法如下:
<%@ taglib prefix="fn"
uri="http://java.sun.com/jsp/jstl/functions" %>
函數 | 描述 |
---|---|
fn:contains() | 測試輸入的字符串是否包含指定的子串 |
fn:containsIgnoreCase() | 測試輸入的字符串是否包含指定的子串,大小寫不敏感 |
fn:endsWith() | 測試輸入的字符串是否以指定的後綴結尾 |
fn:escapeXml() | 跳過可以作爲XML標記的字符 |
fn:indexOf() | 返回指定字符串在輸入字符串中出現的位置 |
fn:join() | 將數組中的元素合成一個字符串然後輸出 |
fn:length() | 返回字符串長度 |
fn:replace() | 將輸入字符串中指定的位置替換爲指定的字符串然後返回 |
fn:split() | 將字符串用指定的分隔符分隔然後組成一個子字符串數組並返回 |
fn:startsWith() | 測試輸入字符串是否以指定的前綴開始 |
fn:substring() | 返回字符串的子集 |
fn:substringAfter() | 返回字符串在指定子串之後的子集 |
fn:substringBefore() | 返回字符串在指定子串之前的子集 |
fn:toLowerCase() | 將字符串中的字符轉爲小寫 |
fn:toUpperCase() | 將字符串中的字符轉爲大寫 |
fn:trim() | 移除首尾的空白符 |
十二、JavaBean
JavaBean是特殊的Java類,使用Java語言書寫,並遵守JavaBean API規範。與其它java類相比,JavaBean:
-
提供一個默認的無參構造函數。
-
需要被序列化並且實現了 Serializable 接口。
-
可能有一系列可讀寫屬性。
-
可能有一系列的 getter 或 setter 方法。
1、JavaBean屬性
一個JavaBean對象的屬性應該是可訪問的。這個屬性可以是任意合法的java數據類型,包括自定義java類。
一個JavaBean對象的屬性可以是可讀寫,或只讀,或只寫。JavaBean對象的屬性通過JavaBean實現類中提供的兩個方法來訪問:
方法 | 描述 |
---|---|
getPropertyName() | 舉例來說,如果屬性的名稱爲 myName,那麼這個方法的名字就要寫成 getMyName() 來讀取這個屬性。這個方法也稱爲訪問器。 |
setPropertyName() | 舉例來說,如果屬性的名稱爲 myName,那麼這個方法的名字就要寫成 setMyName()來寫入這個屬性。這個方法也稱爲寫入器。 |
一個只讀的屬性只提供getPropertyName()方法,一個只寫的屬性只提供setPropertyName()方法。
2、JavaBean程序示例:
package com.runoob;
public class StudentsBean implements java.io.Serializable
{
private String firstName = null;
private String lastName = null;
private int age = 0;
public StudentsBean() {
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public int getAge(){
return age;
}
public void setFirstName(String firstName){
this.firstName = firstName;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
public void setAge(int age) {
this.age = age;
}
}
3、訪問JavaBean
<jsp:useBean>
標籤可以在JSP中聲明一個JavaBean,然後使用。聲明後,JavaBean對象就變成了腳本變量,可以通過腳本元素或其它自定義標籤來訪問。語法格式:
<jsp:useBean id="bean 的名字" scope="bean 的作用域" typeSpec/>
其中,根據具體情況,scope的值可以是page,request,session或application。id值可以任意只要不和同一JSP文件的其它id值一樣就行。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<title>useBean 實例</title>
</head>
<body>
<jsp:useBean id="date" class="java.util.Date" />
<p>日期爲:<%= date %>
</body>
</html>
4、訪問JavaBean對象的屬性
在<jsp:useBean>
標籤主題中使用<jsp:getProperty/>
標籤來調用getter方法,使用<jsp:setProperty/>
標籤來調用setter方法,語法格式:
<jsp:useBean id="id" class="bean 編譯的類" scope="bean 作用域">
<jsp:setProperty name="bean 的 id" property="屬性名"
value="value"/>
<jsp:getProperty name="bean 的 id" property="屬性名"/>
...........
</jsp:useBean>
十三、JSP自定義標籤
自定義標籤是用戶定義的JSP語言元素。當JSP頁面包含一個自定義標籤時將被轉化爲servlet,標籤轉化爲對tag handler的對象的操作,即當servlet執行時Web container調用那些操作。
JSP標籤擴展可以讓你創建新的標籤並且可以直接插入到一個JSP頁面。你可以繼承SimpleTagSupport類並重寫doTag()方法來開發一個最簡單的自定義標籤。
1、創建“Hello”標籤
標籤格式爲:
<ex:Hello />
要創建自定義的JSP標籤,首先必須創建處理標籤的java類,所以我們創建一個HelloTag類:
package com.runoob;
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;
public class HelloTag extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
JspWriter out = getJspContext().getOut();
out.println("Hello Custom Tag!");
}
}
最後創建標籤庫:<Tomcat安裝目錄>webapps\ROOT\WEB-INF\custom.tld。
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>Example TLD</short-name>
<tag>
<name>Hello</name>
<tag-class>com.runoob.HelloTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
之後就可以使用了:
<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<html>
<head>
<title>A sample custom tag</title>
</head>
<body>
<ex:Hello/>
</body>
</html>
十四、表達式語言
JSP表達式語言(EL)使得訪問存儲在JavaBean中的數據變得非常簡單。JSP EL既可以用來創建算數表達式,也可以用來創建邏輯表達式。在JSP EL表達式內可以使用整形術、浮點數、字符串、常量true、false、還有null。
1、一個簡單的語法:
典型的,當你需要在JSP標籤中指定一個屬性值時,只需要簡單的使用字符串接口:
<jsp:setProperty name="box" property="perimeter" value="100"/>
JSP EL允許你指定一個表達式來表示屬性值,一個簡單的語法如下:
${expr}
其中,expr指的是表達式。在JSP EL中通用的操作符是.和{}。這兩個操作符允許你通過內嵌的JSP對象訪問各種各樣的JavaBean屬性。
例如:上面的<jsp:setProperty>
標籤可以使用表達式語言改寫成如下形式:
<jsp:setProperty name="box" property="perimeter"
value="${2*box.width+2*box.height}"/>
當JSP編譯器在屬性中見到“${}”格式後,它會產生代碼來計算這個表達式。
你也可以在標籤的末班文本中使用表達式語言,比如<jsp:text>
標籤簡單的將其主體中的文本插入到JSP輸出中:
<jsp:text>
<h1>Hello JSP!</h1>
</jsp:text>
現在,在<jsp:text>
標籤主體使用表達式:
<jsp:text>
Box Perimeter is: ${2*box.width + 2*box.height}
</jsp:text>
想要停止對EL表達式的評估,需要使用page執行將isELlgnored屬性值設爲true:
<%@ page isELIgnored ="true|false" %>
2、EL中的基本操作符
操作符 | 描述 |
---|---|
. | 訪問一個Bean屬性或者一個映射條目 |
[] | 訪問一個數組或者鏈表的元素 |
( ) | 組織一個子表達式以改變優先級 |
+ | 加 |
- | 減或負 |
* | 乘 |
/ or div | 除 |
% or mod | 取模 |
== or eq | 測試是否相等 |
!= or ne | 測試是否不等 |
< or lt | 測試是否小於 |
> or gt | 測試是否大於 |
<= or le | 測試是否小於等於 |
>= or ge | 測試是否大於等於 |
&& or and | 測試邏輯與 |
|| or or | 測試邏輯或 |
! or not | 測試取反 |
empty | 測試是否空值 |
3、JSP EL中的函數
JSP EL允許你在表達式中使用函數,這些函數必須被定義在自定義標籤庫中:
${ns:func(param1, param2, ...)}
ns指的是命名空間(namespace),func指的是函數的名稱,param1指的是第一個參數,param2指的是第二個參數,以此類推。比如,有函數fn:length,在JSTL庫中定義,可以像下面這樣來獲取一個字符串的長度:
${fn:length("Get my length")}
4、JSP EL隱含對象
隱含對象 | 描述 |
---|---|
pageScope | page 作用域 |
requestScope | request 作用域 |
sessionScope | session 作用域 |
applicationScope | application 作用域 |
param | Request 對象的參數,字符串 |
paramValues | Request對象的參數,字符串集合 |
header | HTTP 信息頭,字符串 |
headerValues | HTTP 信息頭,字符串集合 |
initParam | 上下文初始化參數 |
cookie | Cookie值 |
pageContext | 當前頁面的pageContext |
十五、JSP異常處理
1、使用Exception對象
序號 | 方法**&描述** |
---|---|
1 | public String getMessage()返回異常的信息。這個信息在Throwable構造函數中被初始化 |
2 | public ThrowablegetCause()返回引起異常的原因,類型爲Throwable對象 |
3 | public String toString()返回類名 |
4 | public void printStackTrace()將異常棧軌跡輸出至System.err |
5 | public StackTraceElement [] getStackTrace()以棧軌跡元素數組的形式返回異常棧軌跡 |
6 | public ThrowablefillInStackTrace()使用當前棧軌跡填充Throwable對象 |
<%@ page errorPage="ShowError.jsp" %>
<html>
<head>
<title>Error Handling Example</title>
</head>
<body>
<%
// Throw an exception to invoke the error page
int x = 1;
if (x == 1)
{
throw new RuntimeException("Error condition!!!");
}
%>
</body>
</html>
2、在錯誤頁面中使用JSTL標籤
可以利用JSTL標籤來編寫錯誤頁面。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page isErrorPage="true" %>
<html>
<head>
<title>Show Error Page</title>
</head>
<body>
<h1>Opps...</h1>
<table width="100%" border="1">
<tr valign="top">
<td width="40%"><b>Error:</b></td>
<td>${pageContext.exception}</td>
</tr>
<tr valign="top">
<td><b>URI:</b></td>
<td>${pageContext.errorData.requestURI}</td>
</tr>
<tr valign="top">
<td><b>Status code:</b></td>
<td>${pageContext.errorData.statusCode}</td>
</tr>
<tr valign="top">
<td><b>Stack trace:</b></td>
<td>
<c:forEach var="trace"
items="${pageContext.exception.stackTrace}">
<p>${trace}</p>
</c:forEach>
</td>
</tr>
</table>
</body>
</html>
3、使用try...catch塊
<html>
<head>
<title>Try...Catch Example</title>
</head>
<body>
<%
try{
int i = 1;
i = i / 0;
out.println("The answer is " + i);
}
catch (Exception e){
out.println("An exception occurred: " + e.getMessage());
}
%>
</body>
</html>
十六、調試、國際化:與servlet一致。
後記:
本篇博客側重基礎,沒有個人的思考。要先有基礎,才能更好地思考呀~~~沖沖衝