3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Java Servlet和JSP教程

發布時間:2024/4/17 javascript 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java Servlet和JSP教程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?http://www.bccn.net/article/web/jsp/jc/200409/72.html

簡介

?????這是一個比較完整的Servlet、JSP教程,包含大量的實用資料和示例,仙人掌工作室傾情推薦。全文共十三章,主要包括:Servlet和JSP特點,安裝和配置開發、運行環境,表單數據處理,HTTP請求頭、應答狀態處理,訪問CGI變量,會話狀態,JSP腳本元素、指令、動作,等等。具體請見《目錄》。

目錄
作 者 : 仙人掌工作室???????????????????????????????


   目    錄? (后面的紅色數字代表頁數,點擊可直接進入相應的章節)
一、Servlet和JSP概述??? [2]
1.1 JavaServlet及其特點
1.2 JSP及其特點
二、設置開發、運行環境??? [3]?
2.1 安裝Servlet和JSP開發工具
2.2 安裝支持Servlet的Web服務器
三、第一個Servlet???? [4]
3.1 Servlet基本結構?????
3.2 輸出純文本的簡單Servlet
3.2.1 HelloWorld.java
3.2.2 Servlet的編譯和安裝
3.2.3 運行Servlet
3.3 輸出HTML的Servlet
3.4 幾個HTML工具函數
四、處理表單數據?????[6]
4.1 表單數據概述
4.2 實例:讀取三個表單變量
4.3 實例:輸出所有的表單數據
五、讀取HTTP請求頭??? [8]
5.1 HTTP請求頭概述
5.2 在Servlet中讀取請求頭
5.3 實例:輸出所有的請求頭
六、訪問CGI變量????[9]
6.1 CGI變量概述
6.2 標準CGI變量的Servlet等價表示
6.3 實例:讀取CGI變量
七、HTTP應答狀態???? [10]
7.1 狀態代碼概述
7.2 設置狀態代碼
7.3 HTTP1.1狀態代碼及其含義
7.4 實例:訪問多個搜索引擎
八、設置HTTP應答頭?? ?[13]?
8.1 HTTP應答頭概述
8.2 常見應答頭及其含義
8.3 實例:內容改變時自動刷新頁面
九、處理Cookie???? [15]
9.1 Cookie概述
9.2 Servlet的Cookie API
9.2.1 創建Cookie
9.2.2 讀取和設置Cookie屬性
9.2.3 在應答頭中設置Cookie
9.2.4 讀取保存到客戶端的Cookie
9.3 幾個Cookie工具函數
9.3.1 獲取指定名字的Cookie值
9.3.2 自動保存的Cookie
9.4 實例:定制的搜索引擎界面??

十、會話狀態??????[17]?
10.1 會話狀態概述
10.2 會話狀態跟蹤API
10.2.1 查看當前請求的會話對象
10.2.2 查看和會話有關的信息
10.2.3 在會話對象中保存數據
10.3 實例:顯示會話信息
十一、JSP及語法概要?????[19]?
11.1 概述
11.2 JSP語法概要表
11.3 關于模板文本(靜態HTML)
十二、腳本元素、指令和預定義變量???[21]
12.1 JSP腳本元素
12.1.1 JSP表達式
12.1.2 JSP Scriptlet
12.1.3 JSP聲明
12.2 JSP指令
12.2.1 page指令
12.2.2 include指令
12.3 實例:腳本元素和指令的應用
12.4 JSP預定義變量
十三、JSP動作??? [25]
13.1 jsp:include動作
13.2 jsp:useBean動作
13.3 關于jsp:useBean的進一步說明
13.4 jsp:setProperty動作
13.5 jsp:getProperty動作
13.6 jsp:forward動作
13.7 jsp:plugin動作
附錄:JSP注釋和字符引用約定
注:原文出處:Servlets and JavaServer Pages

一、Servlet和JSP概述

1.1 Java Servlet及其特點

   Servlet是Java技術對CGI編程的回答。Servlet程序在服務器端運行,動態地生成Web頁面。與傳統的CGI和許多其他類似CGI的技術相比,Java Servlet具有更高的效率,更容易使用,功能更強大,具有更好的可移植性,更節省投資(更重要的是, Servlet程序員收入要比Perl程序員高:-):

高效。

在傳統的CGI中,每個請求都要啟動一個新的進程,如果CGI程序本身的執行時間較短,啟動進程所需要的開銷很可能反而超過實際執行時間。而在Servlet中,每個請求由一個輕量級的Java線程處理(而不是重量級的操作系統進程)。
在傳統CGI中,如果有N個并發的對同一CGI程序的請求,則該CGI程序的代碼在內存中重復裝載了N次;而對于Servlet,處理請求的是N個線程,只需要一份Servlet類代碼。在性能優化方面,Servlet也比CGI有著更多的選擇,比如緩沖以前的計算結果,保持數據庫連接的活動,等等。


方便。

Servlet提供了大量的實用工具例程,例如自動地解析和解碼HTML表單數據、讀取和設置HTTP頭、處理Cookie、跟蹤會話狀態等。


功能強大。

在Servlet中,許多使用傳統CGI程序很難完成的任務都可以輕松地完成。例如,Servlet能夠直接和Web服務器交互,而普通的CGI程序不能。Servlet還能夠在各個程序之間共享數據,使得數據庫連接池之類的功能很容易實現。


可移植性好。

Servlet用Java編寫,Servlet API具有完善的標準。因此,為I-Planet Enterprise Server寫的Servlet無需任何實質上的改動即可移植到Apache、Microsoft IIS或者WebStar。幾乎所有的主流服務器都直接或通過插件支持Servlet。


節省投資。

不僅有許多廉價甚至免費的Web服務器可供個人或小規模網站使用,而且對于現有的服務器,如果它不支持Servlet的話,要加上這部分功能也往往是免費的(或只需要極少的投資)。
  

1.2 JSP及其特點

   JavaServer Pages(JSP)是一種實現普通靜態HTML和動態HTML混合編碼的技術,有關JSP基礎概念的說明請參見《JSP技術簡介 》。

   許多由CGI程序生成的頁面大部分仍舊是靜態HTML,動態內容只在頁面中有限的幾個部分出現。但是包括Servlet在內的大多數CGI技術及其變種,總是通過程序生成整個頁面。JSP使得我們可以分別創建這兩個部分。例如,下面就是一個簡單的JSP頁面:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD><TITLE>歡迎訪問網上商店</TITLE></HEAD>
<BODY>
<H1>歡迎</H1>
<SMALL>歡迎,
<!-- 首次訪問的用戶名字為"New User" -->
<% out.println(Utils.getUserNameFromCookie(request)); %>
要設置帳號信息,請點擊
<A HREF="Account-Settings.html">這里</A></SMALL>
<P>
頁面的其余內容。.
</BODY></HTML>



   下面是JSP和其他類似或相關技術的一個簡單比較:

JSP和Active Server Pages(ASP)相比

Microsoft的ASP是一種和JSP類似的技術。JSP和ASP相比具有兩方面的優點。首先,動態部分用Java編寫,而不是VB Script或其他Microsoft語言,不僅功能更強大而且更易于使用。第二,JSP應用可以移植到其他操作系統和非Microsoft的Web服務器上。


JSP和純Servlet相比

JSP并沒有增加任何本質上不能用Servlet實現的功能。但是,在JSP中編寫靜態HTML更加方便,不必再用 println語句來輸出每一行HTML代碼。更重要的是,借助內容和外觀的分離,頁面制作中不同性質的任務可以方便地分開:比如,由頁面設計專家進行HTML設計,同時留出供Servlet程序員插入動態內容的空間。


JSP和服務器端包含(Server-Side Include,SSI)相比

SSI是一種受到廣泛支持的在靜態HTML中引入外部代碼的技術。JSP在這方面的支持更為完善,因為它可以用Servlet而不是獨立的程序來生成動態內容。另外,SSI實際上只用于簡單的包含,而不是面向那些能夠處理表單數據、訪問數據庫的“真正的”程序。


JSP和javascript相比

javascript能夠在客戶端動態地生成HTML。雖然javascript很有用,但它只能處理以客戶端環境為基礎的動態信息。除了Cookie之外,HTTP狀態和表單提交數據對javascript來說都是不可用的。另外,由于是在客戶端運行,javascript不能訪問服務器端資源,比如數據庫、目錄信息等等。

?

二、設置開發、運行環境

2.1 安裝Servlet和JSP開發工具

   要學習Servlet和JSP開發,首先你必須準備一個符合Java Servlet 2.1/2.2和JavaServer Pages1.0/1.1規范的開發環境。Sun提供免費的JavaServer Web Development Kit(JSWDK),可以從http://java.sun.com/products/servlet/下載。

   安裝好JSWDK之后,你還要告訴javac,在編譯文件的時候到哪里去尋找Servlet和JSP類。JSWDK安裝指南對此有詳細說明,但主要就是把servlet.jar和jsp.jar加入CLASSPATH。CLASSPATH是一個指示Java如何尋找類文件的環境變量,如果不設置CLASSPATH,Java在當前目錄和標準系統庫中尋找類;如果你自己設置了CLASSPATH,不要忘記包含當前目錄(即在CLASSPATH中包含“.”)。

   另外,為了避免和其他開發者安裝到同一Web服務器上的Servlet產生命名沖突,最好把自己的Servlet放入包里面。此時,把包層次結構中的頂級目錄也加入CLASSPATH會帶來不少方便。請參見下文具體說明。?

2.2 安裝支持Servlet的Web服務器


   除了開發工具之外,你還要安裝一個支持Java Servlet的Web服務器,或者在現有的Web服務器上安裝Servlet軟件包。如果你使用的是最新的Web服務器或應用服務器,很可能它已經有了所有必需的軟件。請查看Web服務器的文檔,或訪問http://java.sun.com/products/servlet/industry.html查看支持Servlet的服務器軟件清單。

   雖然最終運行Servlet的往往是商業級的服務器,但是開始學習的時候,用一個能夠在臺式機上運行的免費系統進行開發和測試也足夠了。下面是幾種當前最受歡迎的產品。

Apache Tomcat.

Tomcat是Servlet 2.2和JSP 1.1規范的官方參考實現。Tomcat既可以單獨作為小型Servlet、JSP測試服務器,也可以集成到Apache Web服務器。直到2000年早期,Tomcat還是唯一的支持Servlet 2.2和JSP 1.1規范的服務器,但已經有許多其它服務器宣布提供這方面的支持。

Tomcat和Apache一樣是免費的。不過,快速、穩定的Apache服務器安裝和配置起來有點麻煩,Tomcat也有同樣的缺點。和其他商業級Servlet引擎相比,配置Tomcat的工作量顯然要多一點。具體請參見http://jakarta.apache.org/。


JavaServer Web Development Kit (JSWDK).

JSWDK是Servlet 2.1和JSP 1.0的官方參考實現。把Servlet和JSP應用部署到正式運行它們的服務器之前,JSWDK可以單獨作為小型的Servlet、JSP測試服務器。JSWDK也是免費的,而且具有很好的穩定性,但它的安裝和配置也較為復雜。具體請參見http://java.sun.com/products/servlet/download.html。


Allaire JRun.

JRun是一個Servlet和JSP引擎,它可以集成到Netscape Enterprise或FastTrack Server、IIS、Microsoft Personal Web Server、版本較低的Apache、O'eilly的WebSite或者StarNine Web STAR。最多支持5個并發連接的限制版本是免費的,商業版本中不存在這個限制,而且增加了遠程管理控制臺之類的功能。具體請參見http://www.allaire.com/products/jrun/。


New Atlanta 的ServletExec

ServletExec是一個快速的Servlet和JSP引擎,它可以集成到大多數流行的Web服務器,支持平臺包括Solaris、Windows、MacOS、HP-UX和Linux。ServletExec可以免費下載和使用,但許多高級功能和管理工具只有在購買了許可之后才可以使用。New Atlanta還提供一個免費的Servlet調試器,該調試器可以在許多流行的Java IDE下工作。具體請參見http://newatlanta.com/。


Gefion的LiteWebServer (LWS)

LWS是一個支持Servlet 2.2和JSP 1.1的免費小型Web服務器。 Gefion還有一個免費的WAICoolRunner插件,利用該插件可以為Netscape FastTrack和Enterprise Server增加Servlet 2.2和JSP 1.1支持。具體請參見http://www.gefionsoftware.com/。


Sun的Java Web Server.

該服務器全部用Java寫成,而且是首先提供Servlet 2.1和JSP 1.0規范完整支持的Web服務器之一。雖然Sun現在已轉向Netscape/I-Planet Server,不再發展Java Web Server,但它仍舊是一個廣受歡迎的Servlet、JSP學習平臺。要得到免費試用版本,請訪問http://www.sun.com/software/jwebserver/try/.

?

三、第一個Servlet

3.1 Servlet基本結構

  
下面的代碼顯示了一個簡單Servlet的基本結構。該Servlet處理的是GET請求,所謂的GET請求,如果你不熟悉HTTP,可以把它看成是當用戶在瀏覽器地址欄輸入URL、點擊Web頁面中的鏈接、提交沒有指定METHOD的表單時瀏覽器所發出的請求。Servlet也可以很方便地處理POST請求。POST請求是提交那些指定了METHOD=“POST”的表單時所發出的請求,具體請參見稍后幾節的討論。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class SomeServlet extends HttpServlet {
??public void doGet(HttpServletRequest request,
????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
??????
??// 使用“request”讀取和請求有關的信息(比如Cookies)
??// 和表單數據
????
????// 使用“response”指定HTTP應答狀態代碼和應答頭
????// (比如指定內容類型,設置Cookie)
????
????PrintWriter out = response.getWriter();
????// 使用 "out"把應答內容發送到瀏覽器
??}
}




   如果某個類要成為Servlet,則它應該從HttpServlet 繼承,根據數據是通過GET還是POST發送,覆蓋doGet、doPost方法之一或全部。doGet和doPost方法都有兩個參數,分別為HttpServletRequest 類型和HttpServletResponse 類型。HttpServletRequest提供訪問有關請求的信息的方法,例如表單數據、HTTP請求頭等等。HttpServletResponse除了提供用于指定HTTP應答狀態(200,404等)、應答頭(Content-Type,Set-Cookie等)的方法之外,最重要的是它提供了一個用于向客戶端發送數據的PrintWriter 。對于簡單的Servlet來說,它的大部分工作是通過println語句生成向客戶端發送的頁面。

   注意doGet和doPost拋出兩個異常,因此你必須在聲明中包含它們。另外,你還必須導入java.io包(要用到PrintWriter等類)、javax.servlet包(要用到HttpServlet等類)以及javax.servlet.http包(要用到HttpServletRequest類和HttpServletResponse類)。

   最后,doGet和doPost這兩個方法是由service方法調用的,有時你可能需要直接覆蓋service方法,比如Servlet要處理GET和POST兩種請求時。?

3.2 輸出純文本的簡單Servlet

  
下面是一個輸出純文本的簡單Servlet。

3.2.1 HelloWorld.java
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {
??public void doGet(HttpServletRequest request,
??????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????PrintWriter out = response.getWriter();
????out.println("Hello World");
??}
}




3.2.2 Servlet的編譯和安裝

   不同的Web服務器上安裝Servlet的具體細節可能不同,請參考Web服務器文檔了解更權威的說明。假定使用Java Web Server(JWS)2.0,則Servlet應該安裝到JWS安裝目錄的servlets子目錄下。在本文中,為了避免同一服務器上不同用戶的Servlet命名沖突,我們把所有Servlet都放入一個獨立的包hall中;如果你和其他人共用一個服務器,而且該服務器沒有“虛擬服務器”機制來避免這種命名沖突,那么最好也使用包。把Servlet放入了包hall之后,HelloWorld.java實際上是放在servlets目錄的hall子目錄下。

   大多數其他服務器的配置方法也相似,除了JWS之外,本文的Servlet和JSP示例已經在BEA WebLogic和IBM WebSphere 3.0下經過測試。WebSphere具有優秀的虛擬服務器機制,因此,如果只是為了避免命名沖突的話并非一定要用包。

   對于沒有使用過包的初學者,下面我們介紹編譯包里面的類的兩種方法。

   一種方法是設置CLASSPATH,使其指向實際存放Servlet的目錄的上一級目錄(Servlet主目錄),然后在該目錄中按正常的方式編譯。例如,如果Servlet的主目錄是C:\JavaWebServer\servlets,包的名字(即主目錄下的子目錄名字)是hall,在Windows下,編譯過程如下:
??DOS> set CLASSPATH=C:\JavaWebServer\servlets;%CLASSPATH%
??DOS> cd C:\JavaWebServer\servlets\hall
??DOS> javac YourServlet.java



   第二種編譯包里面的Servlet的方法是進入Servlet主目錄,執行“javac directory\YourServlet.java”(Windows)或者“javac directory/YourServlet.java”(Unix)。例如,再次假定Servlet主目錄是C:\JavaWebServer\servlets,包的名字是hall,在Windows中編譯過程如下:
??DOS> cd C:\JavaWebServer\servlets
??DOS> javac hall\YourServlet.java



   注意在Windows下,大多數JDK 1.1版本的javac要求目錄名字后面加反斜杠(\)。JDK1.2已經改正這個問題,然而由于許多Web服務器仍舊使用JDK 1.1,因此大量的Servlet開發者仍舊在使用JDK 1.1。

   最后,Javac還有一個高級選項用于支持源代碼和.class文件的分開放置,即你可以用javac的“-d”選項把.class文件安裝到Web服務器所要求的目錄。

3.2.3 運行Servlet

   在Java Web Server下,Servlet應該放到JWS安裝目錄的servlets子目錄下,而調用Servlet的URL是http://host/servlet/ServletName。注意子目錄的名字是servlets(帶“s”),而URL使用的是“servlet”。由于HelloWorld Servlet放入包hall,因此調用它的URL應該是http://host/servlet/hall.HelloWorld。在其他的服務器上,安裝和調用Servlet的方法可能略有不同。

   大多數Web服務器還允許定義Servlet的別名,因此Servlet也可能用http://host/any-path/any-file.html形式的URL調用。具體如何進行配置完全依賴于服務器類型,請參考服務器文檔了解細節
3.3 輸出HTML的Servlet

   大多數Servlet都輸出HTML,而不象上例一樣輸出純文本。要輸出HTML還有兩個額外的步驟要做:告訴瀏覽器接下來發送的是HTML;修改println語句構造出合法的HTML頁面。

   第一步通過設置Content-Type(內容類型)應答頭完成。一般地,應答頭可以通過HttpServletResponse的setHeader方法設置,但由于設置內容類型是一個很頻繁的操作,因此Servlet API提供了一個專用的方法setContentType。注意設置應答頭應該在通過PrintWriter發送內容之前進行。下面是一個實例:

   HelloWWW.java
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWWW extends HttpServlet {
??public void doGet(HttpServletRequest request,
????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????response.setContentType("text/html");
????PrintWriter out = response.getWriter();
????out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
??????"Transitional//EN\">\n" +
????????????????"<HTML>\n" +
????????????????"<HEAD><TITLE>Hello WWW</TITLE></HEAD>\n" +
????????????????"<BODY>\n" +
????????????????"<H1>Hello WWW</H1>\n" +
????????????????"</BODY></HTML>");
??}
}




3.4 幾個HTML工具函數

   通過println語句輸出HTML并不方便,根本的解決方法是使用JavaServer Pages(JSP)。然而,對于標準的Servlet來說,由于Web頁面中有兩個部分(DOCTYPE和HEAD)一般不會改變,因此可以用工具函數來封裝生成這些內容的代碼。

   雖然大多數主流瀏覽器都會忽略DOCTYPE行,但嚴格地說HTML規范是要求有DOCTYPE行的,它有助于HTML語法檢查器根據所聲明的HTML版本檢查HTML文檔合法性。在許多Web頁面中,HEAD部分只包含<TITLE>。雖然許多有經驗的編寫者都會在HEAD中包含許多META標記和樣式聲明,但這里只考慮最簡單的情況。

   下面的Java方法只接受頁面標題為參數,然后輸出頁面的DOCTYPE、HEAD、TITLE部分。清單如下:

   ServletUtilities.java
package hall;

public class ServletUtilities {
??public static final String DOCTYPE =
????"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">";

??public static String headWithTitle(String title) {
????return(DOCTYPE + "\n" +
???????????"<HTML>\n" +
???????????"<HEAD><TITLE>" + title + "</TITLE></HEAD>\n");
??}

??// 其他工具函數的代碼在本文后面介紹
}




   HelloWWW2.java

   下面是應用了ServletUtilities之后重寫HelloWWW類得到的HelloWWW2:
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWWW2 extends HttpServlet {
??public void doGet(HttpServletRequest request,
????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????response.setContentType("text/html");
????PrintWriter out = response.getWriter();
????out.println(ServletUtilities.headWithTitle("Hello WWW") +
????????????????"<BODY>\n" +
????????????????"<H1>Hello WWW</H1>\n" +
????????????????"</BODY></HTML>");
??}
}

?

四、處理表單數據 4.1 表單數據概述

  
如果你曾經使用過Web搜索引擎,或者瀏覽過在線書店、股票價格、機票信息,或許會留意到一些古怪的URL,比如“http://host/path?user=Marty+Hall&;origin=bwi&dest=lax”。這個URL中位于問號后面的部分,即“user=Marty+Hall&origin=bwi&dest=lax”,就是表單數據,這是將Web頁面數據發送給服務器程序的最常用方法。對于GET請求,表單數據附加到URL的問號后面(如上例所示);對于POST請求,表單數據用一個單獨的行發送給服務器。

   以前,從這種形式的數據提取出所需要的表單變量是CGI編程中最麻煩的事情之一。首先,GET請求和POST請求的數據提取方法不同:對于GET請求,通常要通過QUERY_STRING環境變量提取數據;對于POST請求,則一般通過標準輸入提取數據。第二,程序員必須負責在“&”符號處截斷變量名字-變量值對,再分離出變量名字(等號左邊)和變量值(等號右邊)。第三,必須對變量值進行URL反編碼操作。因為發送數據的時候,字母和數字以原來的形式發送,但空格被轉換成加號,其他字符被轉換成“%XX”形式,其中XX是十六進制表示的字符ASCII(或者ISO Latin-1)編碼值。例如,如果HTML表單中名為“users”的域值為“~hall, ~gates, and ~mcnealy”,則實際向服務器發送的數據為“users=%7Ehall%2C+%7Egates%2C+and+%7Emcnealy”。最后,即第四個導致解析表單數據非常困難的原因在于,變量值既可能被省略(如“param1=val1&param2=&param3=val3”),也有可能一個變量擁有一個以上的值,即同一個變量可能出現一次以上(如“param1=val1&param2=val2&param1=val3”)。

   Java Servlet的好處之一就在于所有上述解析操作都能夠自動完成。只需要簡單地調用一下HttpServletRequest的getParameter方法、在調用參數中提供表單變量的名字(大小寫敏感)即可,而且GET請求和POST請求的處理方法完全相同。

   getParameter方法的返回值是一個字符串,它是參數中指定的變量名字第一次出現所對應的值經反編碼得到得字符串(可以直接使用)。如果指定的表單變量存在,但沒有值,getParameter返回空字符串;如果指定的表單變量不存在,則返回null。如果表單變量可能對應多個值,可以用getParameterValues來取代getParameter。getParameterValues能夠返回一個字符串數組。

   最后,雖然在實際應用中Servlet很可能只會用到那些已知名字的表單變量,但在調試環境中,獲得完整的表單變量名字列表往往是很有用的,利用getParamerterNames方法可以方便地實現這一點。getParamerterNames返回的是一個Enumeration,其中的每一項都可以轉換為調用getParameter的字符串。

4.2 實例:讀取三個表單變量

   下面是一個簡單的例子,它讀取三個表單變量param1、param2和param3,并以HTML列表的形式列出它們的值。請注意,雖然在發送應答內容之前必須指定應答類型(包括內容類型、狀態以及其他HTTP頭信息),但Servlet對何時讀取請求內容卻沒有什么要求。

   另外,我們也可以很容易地把Servlet做成既能處理GET請求,也能夠處理POST請求,這只需要在doPost方法中調用doGet方法,或者覆蓋service方法(service方法調用doGet、doPost、doHead等方法)。在實際編程中這是一種標準的方法,因為它只需要很少的額外工作,卻能夠增加客戶端編碼的靈活性。

   如果你習慣用傳統的CGI方法,通過標準輸入讀取POST數據,那么在Servlet中也有類似的方法,即在HttpServletRequest上調用getReader或者getInputStream,但這種方法對普通的表單變量來說太麻煩。然而,如果是要上載文件,或者POST數據是通過專門的客戶程序而不是HTML表單發送,那么就要用到這種方法。

   注意用第二種方法讀取POST數據時,不能再用getParameter來讀取這些數據。

   ThreeParams.java
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class ThreeParams extends HttpServlet {
??public void doGet(HttpServletRequest request,
???????????????HttpServletResponse response)
??????throws ServletException, IOException {
????response.setContentType("text/html");
????PrintWriter out = response.getWriter();
????String title = "讀取三個請求參數";
????out.println(ServletUtilities.headWithTitle(title) +
????????????????"<BODY>\n" +
????????????????"<H1 ALIGN=CENTER>" + title + "</H1>\n" +
????????????????"<UL>\n" +
????????????????"??<LI>param1: "
????????????????+ request.getParameter("param1") + "\n" +
????????????????"??<LI>param2: "
????????????????+ request.getParameter("param2") + "\n" +
????????????????"??<LI>param3: "
????????????????+ request.getParameter("param3") + "\n" +
????????????????"</UL>\n" +
????????????????"</BODY></HTML>");
??}

??public void doPost(HttpServletRequest request,
?????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????doGet(request, response);
??}
}

?

4.3 實例:輸出所有的表單數據

  
下面這個例子尋找表單所發送的所有變量名字,并把它們放入表格中,沒有值或者有多個值的變量都突出顯示。

   首先,程序通過HttpServletRequest的getParameterNames方法得到所有的變量名字,getParameterNames返回的是一個Enumeration。接下來,程序用循環遍歷這個Enumeration,通過hasMoreElements確定何時結束循環,利用nextElement得到Enumeration中的各個項。由于nextElement返回的是一個Object,程序把它轉換成字符串后再用這個字符串來調用getParameterValues。

   getParameterValues返回一個字符串數組,如果這個數組只有一個元素且等于空字符串,說明這個表單變量沒有值,Servlet以斜體形式輸出“No Value”;如果數組元素個數大于1,說明這個表單變量有多個值,Servlet以HTML列表形式輸出這些值;其他情況下Servlet直接把變量值放入表格。

   ShowParameters.java

   注意,ShowParameters.java用到了前面介紹過的ServletUtilities.java。
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class ShowParameters extends HttpServlet {
??public void doGet(HttpServletRequest request,
????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????response.setContentType("text/html");
????PrintWriter out = response.getWriter();
????String title = "讀取所有請求參數";
????out.println(ServletUtilities.headWithTitle(title) +
????????????????"<BODY BGCOLOR=\"#FDF5E6\">\n" +
????????????????"<H1 ALIGN=CENTER>" + title + "</H1>\n" +
????????????????"<TABLE BORDER=1 ALIGN=CENTER>\n" +
????????????????"<TR BGCOLOR=\"#FFAD00\">\n" +
????????????????"<TH>參數名字<TH>參數值");
????Enumeration paramNames = request.getParameterNames();
????while(paramNames.hasMoreElements()) {
??????String paramName = (String)paramNames.nextElement();
??????out.println("<TR><TD>" + paramName + "\n<TD>");
??????String[] paramValues = request.getParameterValues(paramName);
??????if (paramValues.length == 1) {
????????String paramValue = paramValues[0];
????????if (paramValue.length() == 0)
??????????out.print("<I>No Value</I>");
????????else
??????????out.print(paramValue);
??????} else {
????????out.println("<UL>");
????????for(int i=0; i<paramValues.length; i++) {
??????????out.println("<LI>" + paramValues[i]);
????????}
????????out.println("</UL>");
??????}
????}
????out.println("</TABLE>\n</BODY></HTML>");
??}

??public void doPost(HttpServletRequest request,
?????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????doGet(request, response);
??}
}




   測試表單

   下面是向上述Servlet發送數據的表單PostForm.html。就像所有包含密碼輸入域的表單一樣,該表單用POST方法發送數據。我們可以看到,在Servlet中同時實現doGet和doPost這兩種方法為表單制作帶來了方便。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
??<TITLE>示例表單</TITLE>
</HEAD>

<BODY BGCOLOR="#FDF5E6">
<H1 ALIGN="CENTER">用POST方法發送數據的表單</H1>

<FORM ACTION="/servlet/hall.ShowParameters"
??????METHOD="POST">
??Item Number:
??<INPUT TYPE="TEXT" NAME="itemNum"><BR>
??Quantity:
??<INPUT TYPE="TEXT" NAME="quantity"><BR>
??Price Each:
??<INPUT TYPE="TEXT" NAME="price" VALUE="$"><BR>
??<HR>
??First Name:
??<INPUT TYPE="TEXT" NAME="firstName"><BR>
??Last Name:
??<INPUT TYPE="TEXT" NAME="lastName"><BR>
??Middle Initial:
??<INPUT TYPE="TEXT" NAME="initial"><BR>
??Shipping Address:
??<TEXTAREA NAME="address" ROWS=3 COLS=40></TEXTAREA><BR>
??Credit Card:<BR>
????<INPUT TYPE="RADIO" NAME="cardType"
?????????????????????VALUE="Visa">Visa<BR>
????<INPUT TYPE="RADIO" NAME="cardType"
?????????????????????VALUE="Master Card">Master Card<BR>
????<INPUT TYPE="RADIO" NAME="cardType"
?????????????????????VALUE="Amex">American Express<BR>
????<INPUT TYPE="RADIO" NAME="cardType"
?????????????????????VALUE="Discover">Discover<BR>
????<INPUT TYPE="RADIO" NAME="cardType"
?????????????????????VALUE="Java SmartCard">Java SmartCard<BR>
??Credit Card Number:
??<INPUT TYPE="PASSWORD" NAME="cardNum"><BR>
??Repeat Credit Card Number:
??<INPUT TYPE="PASSWORD" NAME="cardNum"><BR><BR>
??<CENTER>
????<INPUT TYPE="SUBMIT" VALUE="Submit Order">
??</CENTER>
</FORM>

</BODY>
</HTML>

五、讀取HTTP請求頭

5.1 HTTP請求頭概述

  
HTTP客戶程序(例如瀏覽器),向服務器發送請求的時候必須指明請求類型(一般是GET或者POST)。如有必要,客戶程序還可以選擇發送其他的請求頭。大多數請求頭并不是必需的,但Content-Length除外。對于POST請求來說Content-Length必須出現。

   下面是一些最常見的請求頭:

Accept:瀏覽器可接受的MIME類型。
Accept-Charset:瀏覽器可接受的字符集。
Accept-Encoding:瀏覽器能夠進行解碼的數據編碼方式,比如gzip。Servlet能夠向支持gzip的瀏覽器返回經gzip編碼的HTML頁面。許多情形下這可以減少5到10倍的下載時間。
Accept-Language:瀏覽器所希望的語言種類,當服務器能夠提供一種以上的語言版本時要用到。
Authorization:授權信息,通常出現在對服務器發送的WWW-Authenticate頭的應答中。
Connection:表示是否需要持久連接。如果Servlet看到這里的值為“Keep-Alive”,或者看到請求使用的是HTTP 1.1(HTTP 1.1默認進行持久連接),它就可以利用持久連接的優點,當頁面包含多個元素時(例如Applet,圖片),顯著地減少下載所需要的時間。要實現這一點,Servlet需要在應答中發送一個Content-Length頭,最簡單的實現方法是:先把內容寫入ByteArrayOutputStream,然后在正式寫出內容之前計算它的大小。
Content-Length:表示請求消息正文的長度。
Cookie:這是最重要的請求頭信息之一,參見后面《Cookie處理》一章中的討論。
From:請求發送者的email地址,由一些特殊的Web客戶程序使用,瀏覽器不會用到它。
Host:初始URL中的主機和端口。
If-Modified-Since:只有當所請求的內容在指定的日期之后又經過修改才返回它,否則返回304“Not Modified”應答。
Pragma:指定“no-cache”值表示服務器必須返回一個刷新后的文檔,即使它是代理服務器而且已經有了頁面的本地拷貝。
Referer:包含一個URL,用戶從該URL代表的頁面出發訪問當前請求的頁面。
User-Agent:瀏覽器類型,如果Servlet返回的內容與瀏覽器類型有關則該值非常有用。
UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE瀏覽器所發送的非標準的請求頭,表示屏幕大小、顏色深度、操作系統和CPU類型。
   有關HTTP頭完整、詳細的說明,請參見http://www.w3.org/Protocols/的HTTP規范。

5.2 在Servlet中讀取請求頭

   在Servlet中讀取HTTP頭是非常方便的,只需要調用一下HttpServletRequest的getHeader方法即可。如果客戶請求中提供了指定的頭信息,getHeader返回對應的字符串;否則,返回null。部分頭信息經常要用到,它們有專用的訪問方法:getCookies方法返回Cookie頭的內容,經解析后存放在Cookie對象的數組中,請參見后面有關Cookie章節的討論;getAuthType和getRemoteUser方法分別讀取Authorization頭中的一部分內容;getDateHeader和getIntHeader方法讀取指定的頭,然后返回日期值或整數值。

   除了讀取指定的頭之外,利用getHeaderNames還可以得到請求中所有頭名字的一個Enumeration對象。

   最后,除了查看請求頭信息之外,我們還可以從請求主命令行獲得一些信息。getMethod方法返回請求方法,請求方法通常是GET或者POST,但也有可能是HEAD、PUT或者DELETE。getRequestURI方法返回URI(URI是URL的從主機和端口之后到表單數據之前的那一部分)。getRequestProtocol返回請求命令的第三部分,一般是“HTTP/1.0”或者“HTTP/1.1”。

5.3 實例:輸出所有的請求頭

   下面的Servlet實例把所有接收到的請求頭和它的值以表格的形式輸出。另外,該Servlet還會輸出主請求命令的三個部分:請求方法,URI,協議/版本。

   ShowRequestHeaders.java
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class ShowRequestHeaders extends HttpServlet {
??public void doGet(HttpServletRequest request,
????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????response.setContentType("text/html");
????PrintWriter out = response.getWriter();
????String title = "顯示所有請求頭";
????out.println(ServletUtilities.headWithTitle(title) +
????????????????"<BODY BGCOLOR=\"#FDF5E6\">\n" +
????????????????"<H1 ALIGN=CENTER>" + title + "</H1>\n" +
????????????????"<B>Request Method: </B>" +
????????????????request.getMethod() + "<BR>\n" +
????????????????"<B>Request URI: </B>" +
????????????????request.getRequestURI() + "<BR>\n" +
????????????????"<B>Request Protocol: </B>" +
????????????????request.getProtocol() + "<BR><BR>\n" +
????????????????"<TABLE BORDER=1 ALIGN=CENTER>\n" +
????????????????"<TR BGCOLOR=\"#FFAD00\">\n" +
????????????????"<TH>Header Name<TH>Header Value");
????Enumeration headerNames = request.getHeaderNames();
????while(headerNames.hasMoreElements()) {
??????String headerName = (String)headerNames.nextElement();
??????out.println("<TR><TD>" + headerName);
??????out.println("????<TD>" + request.getHeader(headerName));
????}
????out.println("</TABLE>\n</BODY></HTML>");
??}

??public void doPost(HttpServletRequest request,
?????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????doGet(request, response);
??}
}

?

六、訪問CGI變量 6.1 CGI變量概述

   如果你是從傳統的CGI編程轉而學習Java Servlet,或許已經習慣了“CGI變量”這一概念。CGI變量匯集了各種有關請求的信息:

部分來自HTTP請求命令和請求頭,例如Content-Length頭;
部分來自Socket本身,例如主機的名字和IP地址;
也有部分與服務器安裝配置有關,例如URL到實際路徑的映射。
  

6.2 標準CGI變量的Servlet等價表示

   下表假定request對象是提供給doGet和doPost方法的HttpServletRequest類型對象。 CGI變量??含義??從doGet或doPost訪問??
AUTH_TYPE??如果提供了Authorization頭,這里指定了具體的模式(basic或者digest)。??request.getAuthType()??
CONTENT_LENGTH??只用于POST請求,表示所發送數據的字節數。??嚴格地講,等價的表達方式應該是String.valueOf(request.getContentLength())(返回一個字符串)。但更常見的是用request.getContentLength()返回含義相同的整數。??
CONTENT_TYPE??如果指定的話,表示后面所跟數據的類型。??request.getContentType()??
DOCUMENT_ROOT??與http://host/對應的路徑。??getServletContext().getRealPath("/")
注意低版本Servlet規范中的等價表達方式是request.getRealPath("/")。

HTTP_XXX_YYY??訪問任意HTTP頭。??request.getHeader("Xxx-Yyy")??
PATH_INFO??URL中的附加路徑信息,即URL中Servlet路徑之后、查詢字符串之前的那部分。??request.getPathInfo()??
PATH_TRANSLATED??映射到服務器實際路徑之后的路徑信息。??request.getPathTranslated()??
QUERY_STRING??這是字符串形式的附加到URL后面的查詢字符串,數據仍舊是URL編碼的。在Servlet中很少需要用到未經解碼的數據,一般使用getParameter訪問各個參數。??request.getQueryString()??
REMOTE_ADDR??發出請求的客戶機的IP地址。??request.getRemoteAddr()??
REMOTE_HOST??發出請求的客戶機的完整的域名,如java.sun.com。如果不能確定該域名,則返回IP地址。??request.getRemoteHost()??
REMOTE_USER??如果提供了Authorization頭,則代表其用戶部分。它代表發出請求的用戶的名字。??request.getRemoteUser()??
REQUEST_METHOD??請求類型。通常是GET或者POST。但偶爾也會出現HEAD,PUT, DELETE,OPTIONS,或者 TRACE.??request.getMethod()??
SCRIPT_NAME??URL中調用Servlet的那一部分,不包含附加路徑信息和查詢字符串。??request.getServletPath()??
SERVER_NAME??Web服務器名字。??request.getServerName()??
SERVER_PORT??服務器監聽的端口。??嚴格地說,等價表達應該是返回字符串的String.valueOf(request.getServerPort())。但經常使用返回整數值的request.getServerPort()。??
SERVER_PROTOCOL??請求命令中的協議名字和版本(即HTTP/1.0或HTTP/1.1)。??request.getProtocol()??
SERVER_SOFTWARE??Servlet引擎的名字和版本。??getServletContext().getServerInfo()??


6.3 實例:讀取CGI變量

   下面這個Servlet創建一個表格,顯示除了HTTP_XXX_YYY之外的所有CGI變量。HTTP_XXX_YYY是HTTP請求頭信息,請參見上一節介紹。

   ShowCGIVariables.java
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class ShowCGIVariables extends HttpServlet {
??public void doGet(HttpServletRequest request,
????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????response.setContentType("text/html");
????PrintWriter out = response.getWriter();
????String[][] variables =
??????{ { "AUTH_TYPE", request.getAuthType() },
????????{ "CONTENT_LENGTH", String.valueOf(request.getContentLength()) },
????????{ "CONTENT_TYPE", request.getContentType() },
????????{ "DOCUMENT_ROOT", getServletContext().getRealPath("/") },
????????{ "PATH_INFO", request.getPathInfo() },
????????{ "PATH_TRANSLATED", request.getPathTranslated() },
????????{ "QUERY_STRING", request.getQueryString() },
????????{ "REMOTE_ADDR", request.getRemoteAddr() },
????????{ "REMOTE_HOST", request.getRemoteHost() },
????????{ "REMOTE_USER", request.getRemoteUser() },
????????{ "REQUEST_METHOD", request.getMethod() },
????????{ "SCRIPT_NAME", request.getServletPath() },
????????{ "SERVER_NAME", request.getServerName() },
????????{ "SERVER_PORT", String.valueOf(request.getServerPort()) },
????????{ "SERVER_PROTOCOL", request.getProtocol() },
????????{ "SERVER_SOFTWARE", getServletContext().getServerInfo() }
??????};
????String title = "顯示CGI變量";
????out.println(ServletUtilities.headWithTitle(title) +
????????????????"<BODY BGCOLOR=\"#FDF5E6\">\n" +
????????????????"<H1 ALIGN=CENTER>" + title + "</H1>\n" +
????????????????"<TABLE BORDER=1 ALIGN=CENTER>\n" +
????????????????"<TR BGCOLOR=\"#FFAD00\">\n" +
????????????????"<TH>CGI Variable Name<TH>Value");
????for(int i=0; i<variables.length; i++) {
??????String varName = variables[i][0];
??????String varValue = variables[i][1];
??????if (varValue == null)
????????varValue = "<I>Not specified</I>";
??????out.println("<TR><TD>" + varName + "<TD>" + varValue);
????}
????out.println("</TABLE></BODY></HTML>");
??}

??public void doPost(HttpServletRequest request,
?????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????doGet(request, response);
??}
}

?

七、HTTP應答狀態

7.1 狀態代碼概述

  
Web服務器響應瀏覽器或其他客戶程序的請求時,其應答一般由以下幾個部分組成:一個狀態行,幾個應答頭,一個空行,內容文檔。下面是一個最簡單的應答:
HTTP/1.1 200 OK
Content-Type: text/plain

Hello World


   狀態行包含HTTP版本、狀態代碼、與狀態代碼對應的簡短說明信息。在大多數情況下,除了Content-Type之外的所有應答頭都是可選的。但Content-Type是必需的,它描述的是后面文檔的MIME類型。雖然大多數應答都包含一個文檔,但也有一些不包含,例如對HEAD請求的應答永遠不會附帶文檔。有許多狀態代碼實際上用來標識一次失敗的請求,這些應答也不包含文檔(或只包含一個簡短的錯誤信息說明)。

   Servlet可以利用狀態代碼來實現許多功能。例如,可以把用戶重定向到另一個網站;可以指示出后面的文檔是圖片、PDF文件或HTML文件;可以告訴用戶必須提供密碼才能訪問文檔;等等。這一部分我們將具體討論各種狀態代碼的含義以及利用這些代碼可以做些什么。

  
7.2 設置狀態代碼

   如前所述,HTTP應答狀態行包含HTTP版本、狀態代碼和對應的狀態信息。由于狀態信息直接和狀態代碼相關,而HTTP版本又由服務器確定,因此需要Servlet設置的只有一個狀態代碼。

   Servlet設置狀態代碼一般使用HttpServletResponse的setStatus方法。setStatus方法的參數是一個整數(即狀態代碼),不過為了使得代碼具有更好的可讀性,可以用HttpServletResponse中定義的常量來避免直接使用整數。這些常量根據HTTP 1.1中的標準狀態信息命名,所有的名字都加上了SC前綴(Status Code的縮寫)并大寫,同時把空格轉換成了下劃線。也就是說,與狀態代碼404對應的狀態信息是“Not Found”,則HttpServletResponse中的對應常量名字為SC_NOT_FOUND。但有兩個例外:和狀態代碼302對應的常量根據HTTP 1.0命名,而307沒有對應的常量。

   設置狀態代碼并非總是意味著不要再返回文檔。例如,雖然大多數服務器返回404應答時會輸出簡單的“File Not Found”信息,但Servlet也可以定制這個應答。不過,定制應答時應當在通過PrintWriter發送任何內容之前先調用response.setStatus。

   雖然設置狀態代碼一般使用的是response.setStauts(int)方法,但為了簡單起見,HttpServletResponse為兩種常見的情形提供了專用方法:sendError方法生成一個404應答,同時生成一個簡短的HTML錯誤信息文檔;sendRedirect方法生成一個302應答,同時在Location頭中指示新文檔的URL。
7.3 HTTP 1.1狀態代碼及其含義

   下表顯示了常見的HTTP 1.1狀態代碼以及它們對應的狀態信息和含義。

   應當謹慎地使用那些只有HTTP 1.1支持的狀態代碼,因為許多瀏覽器還只能夠支持HTTP 1.0。如果你使用了HTTP 1.1特有的狀態代碼,最好能夠檢查一下請求的HTTP版本號(通過HttpServletRequest的getProtocol方法)。 狀態代碼??狀態信息??含義??
100??Continue??初始的請求已經接受,客戶應當繼續發送請求的其余部分。(HTTP 1.1新)??
101??Switching Protocols??服務器將遵從客戶的請求轉換到另外一種協議(HTTP 1.1新)??
200??OK??一切正常,對GET和POST請求的應答文檔跟在后面。如果不用setStatus設置狀態代碼,Servlet默認使用202狀態代碼。??
201??Created??服務器已經創建了文檔,Location頭給出了它的URL。??
202??Accepted??已經接受請求,但處理尚未完成。??
203??Non-Authoritative Information??文檔已經正常地返回,但一些應答頭可能不正確,因為使用的是文檔的拷貝(HTTP 1.1新)。??
204??No Content??沒有新文檔,瀏覽器應該繼續顯示原來的文檔。如果用戶定期地刷新頁面,而Servlet可以確定用戶文檔足夠新,這個狀態代碼是很有用的。??
205??Reset Content??沒有新的內容,但瀏覽器應該重置它所顯示的內容。用來強制瀏覽器清除表單輸入內容(HTTP 1.1新)。??
206??Partial Content??客戶發送了一個帶有Range頭的GET請求,服務器完成了它(HTTP 1.1新)。??
300??Multiple Choices??客戶請求的文檔可以在多個位置找到,這些位置已經在返回的文檔內列出。如果服務器要提出優先選擇,則應該在Location應答頭指明。??
301??Moved Permanently??客戶請求的文檔在其他地方,新的URL在Location頭中給出,瀏覽器應該自動地訪問新的URL。??
302??Found??類似于301,但新的URL應該被視為臨時性的替代,而不是永久性的。注意,在HTTP1.0中對應的狀態信息是“Moved Temporatily”,而HttpServletResponse中相應的常量是SC_MOVED_TEMPORARILY,而不是SC_FOUND。
出現該狀態代碼時,瀏覽器能夠自動訪問新的URL,因此它是一個很有用的狀態代碼。為此,Servlet提供了一個專用的方法,即sendRedirect。使用response.sendRedirect(url)比使用response.setStatus(response.SC_MOVED_TEMPORARILY)和response.setHeader("Location",url)更好。這是因為:

首先,代碼更加簡潔。
第二,使用sendRedirect,Servlet會自動構造一個包含新鏈接的頁面(用于那些不能自動重定向的老式瀏覽器)。
最后,sendRedirect能夠處理相對URL,自動把它們轉換成絕對URL。
注意這個狀態代碼有時候可以和301替換使用。例如,如果瀏覽器錯誤地請求http://host/~user(缺少了后面的斜杠),有的服務器返回301,有的則返回302。

嚴格地說,我們只能假定只有當原來的請求是GET時瀏覽器才會自動重定向。請參見307。

303??See Other??類似于301/302,不同之處在于,如果原來的請求是POST,Location頭指定的重定向目標文檔應該通過GET提取(HTTP 1.1新)。??
304??Not Modified??客戶端有緩沖的文檔并發出了一個條件性的請求(一般是提供If-Modified-Since頭表示客戶只想比指定日期更新的文檔)。服務器告訴客戶,原來緩沖的文檔還可以繼續使用。??
305??Use Proxy??客戶請求的文檔應該通過Location頭所指明的代理服務器提取(HTTP 1.1新)。??
307??Temporary Redirect??和302(Found)相同。許多瀏覽器會錯誤地響應302應答進行重定向,即使原來的請求是POST,即使它實際上只能在POST請求的應答是303時才能重定向。由于這個原因,HTTP 1.1新增了307,以便更加清除地區分幾個狀態代碼:當出現303應答時,瀏覽器可以跟隨重定向的GET和POST請求;如果是307應答,則瀏覽器只能跟隨對GET請求的重定向。
注意,HttpServletResponse中沒有為該狀態代碼提供相應的常量。(HTTP 1.1新)

400??Bad Request??請求出現語法錯誤。??
401??Unauthorized??客戶試圖未經授權訪問受密碼保護的頁面。應答中會包含一個WWW-Authenticate頭,瀏覽器據此顯示用戶名字/密碼對話框,然后在填寫合適的Authorization頭后再次發出請求。??
403??Forbidden??資源不可用。服務器理解客戶的請求,但拒絕處理它。通常由于服務器上文件或目錄的權限設置導致。??
404??Not Found??無法找到指定位置的資源。這也是一個常用的應答,HttpServletResponse專門提供了相應的方法:sendError(message)。??
405??Method Not Allowed??請求方法(GET、POST、HEAD、DELETE、PUT、TRACE等)對指定的資源不適用。(HTTP 1.1新)??
406??Not Acceptable??指定的資源已經找到,但它的MIME類型和客戶在Accpet頭中所指定的不兼容(HTTP 1.1新)。??
407??Proxy Authentication Required??類似于401,表示客戶必須先經過代理服務器的授權。(HTTP 1.1新)??
408??Request Timeout??在服務器許可的等待時間內,客戶一直沒有發出任何請求。客戶可以在以后重復同一請求。(HTTP 1.1新)??
409??Conflict??通常和PUT請求有關。由于請求和資源的當前狀態相沖突,因此請求不能成功。(HTTP 1.1新)??
410??Gone??所請求的文檔已經不再可用,而且服務器不知道應該重定向到哪一個地址。它和404的不同在于,返回407表示文檔永久地離開了指定的位置,而404表示由于未知的原因文檔不可用。(HTTP 1.1新)??
411??Length Required??服務器不能處理請求,除非客戶發送一個Content-Length頭。(HTTP 1.1新)??
412??Precondition Failed??請求頭中指定的一些前提條件失敗(HTTP 1.1新)。??
413??Request Entity Too Large??目標文檔的大小超過服務器當前愿意處理的大小。如果服務器認為自己能夠稍后再處理該請求,則應該提供一個Retry-After頭(HTTP 1.1新)。??
414??Request URI Too Long??URI太長(HTTP 1.1新)。??
416??Requested Range Not Satisfiable??服務器不能滿足客戶在請求中指定的Range頭。(HTTP 1.1新)??
500??Internal Server Error??服務器遇到了意料不到的情況,不能完成客戶的請求。??
501??Not Implemented??服務器不支持實現請求所需要的功能。例如,客戶發出了一個服務器不支持的PUT請求。??
502??Bad Gateway??服務器作為網關或者代理時,為了完成請求訪問下一個服務器,但該服務器返回了非法的應答。??
503??Service Unavailable??服務器由于維護或者負載過重未能應答。例如,Servlet可能在數據庫連接池已滿的情況下返回503。服務器返回503時可以提供一個Retry-After頭。??
504??Gateway Timeout??由作為代理或網關的服務器使用,表示不能及時地從遠程服務器獲得應答。(HTTP 1.1新)??
505??HTTP Version Not Supported??服務器不支持請求中所指明的HTTP版本。(HTTP 1.1新)
7.4 實例:訪問多個搜索引擎

   下面這個例子用到了除200之外的另外兩個常見狀態代碼:302和404。302通過sendRedirect方法設置,404通過sendError方法設置。

   在這個例子中,首先出現的HTML表單用來選擇搜索引擎、搜索字符串、每頁顯示的搜索結果數量。表單提交后,Servlet提取這三個變量,按照所選擇的搜索引擎的要求構造出包含這些變量的URL,然后把用戶重定向到這個URL。如果用戶不能正確地選擇搜索引擎,或者利用其他表單發送了一個不認識的搜索引擎名字,則返回一個提示搜索引擎找不到的404頁面。

   SearchEngines.java

   注意:這個Servlet要用到后面給出的SearchSpec類,SearchSpec的功能是構造適合不同搜索引擎的URL。
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.net.*;

public class SearchEngines extends HttpServlet {
??public void doGet(HttpServletRequest request,
????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????// getParameter自動解碼URL編碼的查詢字符串。由于我們
????// 要把查詢字符串發送給另一個服務器,因此再次使用
????// URLEncoder進行URL編碼
????String searchString =
??????URLEncoder.encode(request.getParameter("searchString"));
????String numResults =
??????request.getParameter("numResults");
????String searchEngine =
??????request.getParameter("searchEngine");
????SearchSpec[] commonSpecs = SearchSpec.getCommonSpecs();
????for(int i=0; i<commonSpecs.length; i++) {
??????SearchSpec searchSpec = commonSpecs[i];
??????if (searchSpec.getName().equals(searchEngine)) {
????????String url =
??????????response.encodeURL(searchSpec.makeURL(searchString,
????????????????????????????numResults));
????????response.sendRedirect(url);
????????return;
??????}
????}
????response.sendError(response.SC_NOT_FOUND,
???????????????????????"No recognized search engine specified.");
??}

??public void doPost(HttpServletRequest request,
?????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????doGet(request, response);
??}
}




   SearchSpec.java
package hall;

class SearchSpec {
??private String name, baseURL, numResultsSuffix;

??private static SearchSpec[] commonSpecs =
????{ new SearchSpec("google",
?????????????????????"http://www.google.com/search?q=",
?????????????????????"&num="),
??????new SearchSpec("infoseek",
?????????????????????"http://infoseek.go.com/Titles?qt=",
?????????????????????"&nh="),
??????new SearchSpec("lycos",
?????????????????????"http://lycospro.lycos.com/cgi-bin/pursuit?query=",
?????????????????????"&maxhits="),
??????new SearchSpec("hotbot",
?????????????????????"http://www.hotbot.com/?MT=",
?????????????????????"&DC=")
????};

??public SearchSpec(String name,
????????????????????String baseURL,
????????????????????String numResultsSuffix) {
????this.name = name;
????this.baseURL = baseURL;
????this.numResultsSuffix = numResultsSuffix;
??}

??public String makeURL(String searchString, String numResults) {
????return(baseURL + searchString + numResultsSuffix + numResults);
??}

??public String getName() {
????return(name);
??}

??public static SearchSpec[] getCommonSpecs() {
????return(commonSpecs);
??}
}




   SearchEngines.html

   下面是調用上述Servlet的HTML表單。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
??<TITLE>訪問多個搜索引擎</TITLE>
</HEAD>

<BODY BGCOLOR="#FDF5E6">

<FORM ACTION="/servlet/hall.SearchEngines">
??<CENTER>
????搜索關鍵字:
????<INPUT TYPE="TEXT" NAME="searchString"><BR>
????每頁顯示幾個查詢結果:
????<INPUT TYPE="TEXT" NAME="numResults"
???????????????????????VALUE=10 SIZE=3><BR>
????<INPUT TYPE="RADIO" NAME="searchEngine"
????????????????????????VALUE="google">
????Google |
????<INPUT TYPE="RADIO" NAME="searchEngine"
????????????????????????VALUE="infoseek">
????Infoseek |
????<INPUT TYPE="RADIO" NAME="searchEngine"
????????????????????????VALUE="lycos">
????Lycos |
????<INPUT TYPE="RADIO" NAME="searchEngine"
????????????????????????VALUE="hotbot">
????HotBot
????<BR>
????<INPUT TYPE="SUBMIT" VALUE="Search">
??</CENTER>
</FORM>

</BODY>
</HTML>

八、設置HTTP應答頭

8.1 HTTP應答頭概述

   Web服務器的HTTP應答一般由以下幾項構成:一個狀態行,一個或多個應答頭,一個空行,內容文檔。設置HTTP應答頭往往和設置狀態行中的狀態代碼結合起來。例如,有好幾個表示“文檔位置已經改變”的狀態代碼都伴隨著一個Location頭,而401(Unauthorized)狀態代碼則必須伴隨一個WWW-Authenticate頭。

   然而,即使在沒有設置特殊含義的狀態代碼時,指定應答頭也是很有用的。應答頭可以用來完成:設置Cookie,指定修改日期,指示瀏覽器按照指定的間隔刷新頁面,聲明文檔的長度以便利用持久HTTP連接,……等等許多其他任務。

   設置應答頭最常用的方法是HttpServletResponse的setHeader,該方法有兩個參數,分別表示應答頭的名字和值。和設置狀態代碼相似,設置應答頭應該在發送任何文檔內容之前進行。

   setDateHeader方法和setIntHeadr方法專門用來設置包含日期和整數值的應答頭,前者避免了把Java時間轉換為GMT時間字符串的麻煩,后者則避免了把整數轉換為字符串的麻煩。

   HttpServletResponse還提供了許多設置常見應答頭的簡便方法,如下所示:

setContentType:設置Content-Type頭。大多數Servlet都要用到這個方法。
setContentLength:設置Content-Length頭。對于支持持久HTTP連接的瀏覽器來說,這個函數是很有用的。
addCookie:設置一個Cookie(Servlet API中沒有setCookie方法,因為應答往往包含多個Set-Cookie頭)。
另外,如上節介紹,sendRedirect方法設置狀態代碼302時也會設置Location頭。
  
8.2 常見應答頭及其含義

  
有關HTTP頭詳細和完整的說明,請參見http://www.w3.org/Protocols/規范。

應答頭??說明??
Allow??服務器支持哪些請求方法(如GET、POST等)。??
Content-Encoding??文檔的編碼(Encode)方法。只有在解碼之后才可以得到Content-Type頭指定的內容類型。利用gzip壓縮文檔能夠顯著地減少HTML文檔的下載時間。Java的GZIPOutputStream可以很方便地進行gzip壓縮,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet應該通過查看Accept-Encoding頭(即request.getHeader("Accept-Encoding"))檢查瀏覽器是否支持gzip,為支持gzip的瀏覽器返回經gzip壓縮的HTML頁面,為其他瀏覽器返回普通頁面。??
Content-Length??表示內容長度。只有當瀏覽器使用持久HTTP連接時才需要這個數據。如果你想要利用持久連接的優勢,可以把輸出文檔寫入ByteArrayOutputStram,完成后查看其大小,然后把該值放入Content-Length頭,最后通過byteArrayStream.writeTo(response.getOutputStream()發送內容。??
Content-Type??表示后面的文檔屬于什么MIME類型。Servlet默認為text/plain,但通常需要顯式地指定為text/html。由于經常要設置Content-Type,因此HttpServletResponse提供了一個專用的方法setContentTyep。??
Date??當前的GMT時間。你可以用setDateHeader來設置這個頭以避免轉換時間格式的麻煩。??
Expires??應該在什么時候認為文檔已經過期,從而不再緩存它???
Last-Modified??文檔的最后改動時間。客戶可以通過If-Modified-Since請求頭提供一個日期,該請求將被視為一個條件GET,只有改動時間遲于指定時間的文檔才會返回,否則返回一個304(Not Modified)狀態。Last-Modified也可用setDateHeader方法來設置。??
Location??表示客戶應當到哪里去提取文檔。Location通常不是直接設置的,而是通過HttpServletResponse的sendRedirect方法,該方法同時設置狀態代碼為302。??
Refresh??表示瀏覽器應該在多少時間之后刷新文檔,以秒計。除了刷新當前文檔之外,你還可以通過setHeader("Refresh", "5; URL=http://host/path")讓瀏覽器讀取指定的頁面。
注意這種功能通常是通過設置HTML頁面HEAD區的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">實現,這是因為,自動刷新或重定向對于那些不能使用CGI或Servlet的HTML編寫者十分重要。但是,對于Servlet來說,直接設置Refresh頭更加方便。

注意Refresh的意義是“N秒之后刷新本頁面或訪問指定頁面”,而不是“每隔N秒刷新本頁面或訪問指定頁面”。因此,連續刷新要求每次都發送一個Refresh頭,而發送204狀態代碼則可以阻止瀏覽器繼續刷新,不管是使用Refresh頭還是<META HTTP-EQUIV="Refresh" ...>。

注意Refresh頭不屬于HTTP 1.1正式規范的一部分,而是一個擴展,但Netscape和IE都支持它。

Server??服務器名字。Servlet一般不設置這個值,而是由Web服務器自己設置。??
Set-Cookie??設置和頁面關聯的Cookie。Servlet不應使用response.setHeader("Set-Cookie", ...),而是應使用HttpServletResponse提供的專用方法addCookie。參見下文有關Cookie設置的討論。??
WWW-Authenticate??客戶應該在Authorization頭中提供什么類型的授權信息?在包含401(Unauthorized)狀態行的應答中這個頭是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。
注意Servlet一般不進行這方面的處理,而是讓Web服務器的專門機制來控制受密碼保護頁面的訪問(例如.htaccess)。
8.3 實例:內容改變時自動刷新頁面

  
下面這個Servlet用來計算大素數。因為計算非常大的數字(例如500位)可能要花不少時間,所以Servlet將立即返回已經找到的結果,同時在后臺繼續計算。后臺計算使用一個優先級較低的線程以避免過多地影響Web服務器的性能。如果計算還沒有完成,Servlet通過發送Refresh頭指示瀏覽器在幾秒之后繼續請求新的內容。

   注意,本例除了說明HTTP應答頭的用處之外,還顯示了Servlet的另外兩個很有價值的功能。首先,它表明Servlet能夠處理多個并發的連接,每個都有自己的線程。Servlet維護了一份已有素數計算請求的Vector表,通過查找素數個數(素數列表的長度)和數字個數(每個素數的長度)將當前請求和已有請求相匹配,把所有這些請求同步到這個列表上。第二,本例證明,在Servlet中維持請求之間的狀態信息是非常容易的。維持狀態信息在傳統的CGI編程中是一件很麻煩的事情。由于維持了狀態信息,瀏覽器能夠在刷新頁面時訪問到正在進行的計算過程,同時也使得Servlet能夠保存一個有關最近請求結果的列表,當一個新的請求指定了和最近請求相同的參數時可以立即返回結果。

   PrimeNumbers.java

   注意,該Servlet要用到前面給出的ServletUtilities.java。另外還要用到:PrimeList.java,用于在后臺線程中創建一個素數的Vector;Primes.java,用于隨機生成BigInteger類型的大數字,檢查它們是否是素數。(此處略去PrimeList.java和Primes.java的代碼。)
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class PrimeNumbers extends HttpServlet {
??private static Vector primeListVector = new Vector();
??private static int maxPrimeLists = 30;
??
??public void doGet(HttpServletRequest request,
????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????int numPrimes = ServletUtilities.getIntParameter(request, "numPrimes", 50);
????int numDigits = ServletUtilities.getIntParameter(request, "numDigits", 120);
????PrimeList primeList = findPrimeList(primeListVector, numPrimes, numDigits);
????if (primeList == null) {
??????primeList = new PrimeList(numPrimes, numDigits, true);
??????synchronized(primeListVector) {
????????if (primeListVector.size() >= maxPrimeLists)
??????????primeListVector.removeElementAt(0);
????????primeListVector.addElement(primeList);
??????}
????}
????Vector currentPrimes = primeList.getPrimes();
????int numCurrentPrimes = currentPrimes.size();
????int numPrimesRemaining = (numPrimes - numCurrentPrimes);
????boolean isLastResult = (numPrimesRemaining == 0);
????if (!isLastResult) {
??????response.setHeader("Refresh", "5");
????}
????response.setContentType("text/html");
????PrintWriter out = response.getWriter();
????String title = "Some " + numDigits + "-Digit Prime Numbers";
????out.println(ServletUtilities.headWithTitle(title) +
????????????????"<BODY BGCOLOR=\"#FDF5E6\">\n" +
????????????????"<H2 ALIGN=CENTER>" + title + "</H2>\n" +
????????????????"<H3>Primes found with " + numDigits +
????????????????" or more digits: " + numCurrentPrimes + ".</H3>");
????if (isLastResult)
??????out.println("<B>Done searching.</B>");
????else
??????out.println("<B>Still looking for " + numPrimesRemaining +
??????????????????" more<BLINK>...</BLINK></B>");
????out.println("<OL>");
????for(int i=0; i<numCurrentPrimes; i++) {
??????out.println("??<LI>" + currentPrimes.elementAt(i));
????}
????out.println("</OL>");
????out.println("</BODY></HTML>");
??}

??public void doPost(HttpServletRequest request,
?????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????doGet(request, response);
??}

??// 檢查是否存在同類型請求(已經完成,或者正在計算)。
??// 如存在,則返回現有結果而不是啟動新的后臺線程。
??private PrimeList findPrimeList(Vector primeListVector,
?????????????????????????????int numPrimes,
?????????????????????????????int numDigits) {
????synchronized(primeListVector) {
??????for(int i=0; i<primeListVector.size(); i++) {
????????PrimeList primes = (PrimeList)primeListVector.elementAt(i);
????????if ((numPrimes == primes.numPrimes()) &&
????????????(numDigits == primes.numDigits()))
??????????return(primes);
??????}
??????return(null);
????}
??}
}

   PrimeNumbers.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
??<TITLE>大素數計算</TITLE>
</HEAD>
<CENTER>
<BODY BGCOLOR="#FDF5E6">
<FORM ACTION="/servlet/hall.PrimeNumbers">
??<B>要計算幾個素數:</B>
??<INPUT TYPE="TEXT" NAME="numPrimes" VALUE=25 SIZE=4><BR>
??<B>每個素數的位數:</B>
??<INPUT TYPE="TEXT" NAME="numDigits" VALUE=150 SIZE=3><BR>
??<INPUT TYPE="SUBMIT" VALUE="開始計算">
</FORM>
</CENTER>
</BODY>
</HTML>

九、處理Cookie

9.1 Cookie概述

   Cookie是服務器發送給瀏覽器的體積很小的純文本信息,用戶以后訪問同一個Web服務器時瀏覽器會把它們原樣發送給服務器。通過讓服務器讀取它原先保存到客戶端的信息,網站能夠為瀏覽者提供一系列的方便,例如在線交易過程中標識用戶身份、安全要求不高的場合避免用戶重復輸入名字和密碼、門戶網站的主頁定制、有針對性地投放廣告,等等。

   Cookie的目的就是為用戶帶來方便,為網站帶來增值。雖然有著許多誤傳,事實上Cookie并不會造成嚴重的安全威脅。Cookie永遠不會以任何方式執行,因此也不會帶來病毒或攻擊你的系統。另外,由于瀏覽器一般只允許存放300個Cookie,每個站點最多存放20個Cookie,每個Cookie的大小限制為4 KB,因此Cookie不會塞滿你的硬盤,更不會被用作“拒絕服務”攻擊手段。

  
9.2 Servlet的Cookie API

   要把Cookie發送到客戶端,Servlet先要調用new Cookie(name,value)用合適的名字和值創建一個或多個Cookie(2.1節),通過cookie.setXXX設置各種屬性(2.2節),通過response.addCookie(cookie)把cookie加入應答頭(2.3節)。

   要從客戶端讀入Cookie,Servlet應該調用request.getCookies(),getCookies()方法返回一個Cookie對象的數組。在大多數情況下,你只需要用循環訪問該數組的各個元素尋找指定名字的Cookie,然后對該Cookie調用getValue方法取得與指定名字關聯的值,這部分內容將在2.4節討論。

   9.2.1 創建Cookie

   調用Cookie對象的構造函數可以創建Cookie。Cookie對象的構造函數有兩個字符串參數:Cookie名字和Cookie值。名字和值都不能包含空白字符以及下列字符:
??[ ] ( ) = , " / ? @ : ;




   9.2.2 讀取和設置Cookie屬性

   把Cookie加入待發送的應答頭之前,你可以查看或設置Cookie的各種屬性。下面摘要介紹這些方法:

getComment/setComment
獲取/設置Cookie的注釋。
getDomain/setDomain
獲取/設置Cookie適用的域。一般地,Cookie只返回給與發送它的服務器名字完全相同的服務器。使用這里的方法可以指示瀏覽器把Cookie返回給同一域內的其他服務器。注意域必須以點開始(例如.sitename.com),非國家類的域(如.com,.edu,.gov)必須包含兩個點,國家類的域(如.com.cn,.edu.uk)必須包含三個點。
getMaxAge/setMaxAge
獲取/設置Cookie過期之前的時間,以秒計。如果不設置該值,則Cookie只在當前會話內有效,即在用戶關閉瀏覽器之前有效,而且這些Cookie不會保存到磁盤上。參見下面有關LongLivedCookie的說明。
getName/setName
獲取/設置Cookie的名字。本質上,名字和值是我們始終關心的兩個部分。由于HttpServletRequest的getCookies方法返回的是一個Cookie對象的數組,因此通常要用循環來訪問這個數組查找特定名字,然后用getValue檢查它的值。
getPath/setPath
獲取/設置Cookie適用的路徑。如果不指定路徑,Cookie將返回給當前頁面所在目錄及其子目錄下的所有頁面。這里的方法可以用來設定一些更一般的條件。例如,someCookie.setPath("/"),此時服務器上的所有頁面都可以接收到該Cookie。
getSecure/setSecure
獲取/設置一個boolean值,該值表示是否Cookie只能通過加密的連接(即SSL)發送。
getValue/setValue
獲取/設置Cookie的值。如前所述,名字和值實際上是我們始終關心的兩個方面。不過也有一些例外情況,比如把名字作為邏輯標記(也就是說,如果名字存在,則表示true)。
getVersion/setVersion
獲取/設置Cookie所遵從的協議版本。默認版本0(遵從原先的Netscape規范);版本1遵從RFC 2109 , 但尚未得到廣泛的支持。
   9.2.3 在應答頭中設置Cookie

   Cookie可以通過HttpServletResponse的addCookie方法加入到Set-Cookie應答頭。下面是一個例子:
??Cookie userCookie = new Cookie("user", "uid1234");
??response.addCookie(userCookie);




   9.2.4 讀取保存到客戶端的Cookie

   要把Cookie發送到客戶端,先要創建Cookie,然后用addCookie發送一個Set-Cookie HTTP應答頭。這些內容已經在上面的2.1節介紹。從客戶端讀取Cookie時調用的是HttpServletRequest的getCookies方法。該方法返回一個與HTTP請求頭中的內容對應的Cookie對象數組。得到這個數組之后,一般是用循環訪問其中的各個元素,調用getName檢查各個Cookie的名字,直至找到目標Cookie。然后對這個目標Cookie調用getValue,根據獲得的結果進行其他處理。

   上述處理過程經常會遇到,為方便計下面我們提供一個getCookieValue方法。只要給出Cookie對象數組、Cookie名字和默認值,getCookieValue方法就會返回匹配指定名字的Cookie值,如果找不到指定Cookie,則返回默認值。

 
9.3 幾個Cookie工具函數

   下面是幾個工具函數。這些函數雖然簡單,但是,在和Cookie打交道的時候很有用。

   9.3.1 獲取指定名字的Cookie值

   該函數是ServletUtilities.java的一部分。getCookieValue通過循環依次訪問Cookie對象數組的各個元素,尋找是否有指定名字的Cookie,如找到,則返回該Cookie的值;否則,返回參數中給出的默認值。getCookieValue能夠在一定程度上簡化Cookie值的提取。
??public static String getCookieValue(Cookie[] cookies,
???????????????String cookieName,
???????????????String defaultValue) {
????for(int i=0; i<cookies.length; i++) {
??????Cookie cookie = cookies[i];
??????if (cookieName.equals(cookie.getName()))
????????return(cookie.getValue());
????}
????return(defaultValue);
??}

  
?9.3.2自動保存的Cookie

   下面是LongLivedCookie類的代碼。如果你希望Cookie能夠在瀏覽器退出的時候自動保存下來,則可以用這個LongLivedCookie類來取代標準的Cookie類。
package hall;

import javax.servlet.http.*;

public class LongLivedCookie extends Cookie {
??public static final int SECONDS_PER_YEAR = 60*60*24*365;
??public LongLivedCookie(String name, String value) {
????super(name, value);
????setMaxAge(SECONDS_PER_YEAR);
??}
}
9.4.實例:定制的搜索引擎界面

   下面也是一個搜索引擎界面的例子,通過修改前面HTTP狀態代碼的例子得到。在這個Servlet中,用戶界面是動態生成而不是由靜態HTML文件提供的。Servlet除了負責讀取表單數據并把它們發送給搜索引擎之外,還要把包含表單數據的Cookie發送給客戶端。以后客戶再次訪問同一表單時,這些Cookie的值將用來預先填充表單,使表單自動顯示最近使用過的數據。

   SearchEnginesFrontEnd.java

   該Servlet構造一個主要由表單構成的用戶界面。第一次顯示的時候,它和前面用靜態HTML頁面提供的界面差不多。然而,用戶選擇的值將被保存到Cookie(本頁面將數據發送到CustomizedSearchEngines Servlet,由后者設置Cookie)。用戶以后再訪問同一頁面時,即使瀏覽器是退出之后再啟動,表單中也會自動填好上一次搜索所填寫的內容。

   注意該Servlet用到了ServletUtilities.java,其中getCookieValue前面已經介紹過,headWithTitle用于生成HTML頁面的一部分。另外,這里也用到了前面已經說明的LongLiveCookie類,我們用它來創建作廢期限很長的Cookie。
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.net.*;

public class SearchEnginesFrontEnd extends HttpServlet {
??public void doGet(HttpServletRequest request,
?????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????Cookie[] cookies = request.getCookies();
????String searchString =
??????ServletUtilities.getCookieValue(cookies,
?????????????"searchString",
?????????????"Java Programming");
????String numResults =
??????ServletUtilities.getCookieValue(cookies,
?????????????"numResults",
?????????????"10");
????String searchEngine =
??????ServletUtilities.getCookieValue(cookies,
??????????????"searchEngine",
??????????????"google");
????response.setContentType("text/html");
????PrintWriter out = response.getWriter();
????String title = "Searching the Web";
????out.println(ServletUtilities.headWithTitle(title) +
????????????????"<BODY BGCOLOR=\"#FDF5E6\">\n" +
????????????????"<H1 ALIGN=\"CENTER\">Searching the Web</H1>\n" +
????????????????"\n" +
????????????????"<FORM ACTION=\"/servlet/hall.CustomizedSearchEngines\">\n" +
????????????????"<CENTER>\n" +
????????????????"Search String:\n" +
????????????????"<INPUT TYPE=\"TEXT\" NAME=\"searchString\"\n" +
????????????????"???????VALUE=\"" + searchString + "\"><BR>\n" +
????????????????"Results to Show Per Page:\n" +
????????????????"<INPUT TYPE=\"TEXT\" NAME=\"numResults\"\n" +
????????????????"???????VALUE=" + numResults + " SIZE=3><BR>\n" +
????????????????"<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +
????????????????"???????VALUE=\"google\"" +
????????????????checked("google", searchEngine) + ">\n" +
????????????????"Google |\n" +
????????????????"<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +
????????????????"???????VALUE=\"infoseek\"" +
????????????????checked("infoseek", searchEngine) + ">\n" +
????????????????"Infoseek |\n" +
????????????????"<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +
????????????????"???????VALUE=\"lycos\"" +
????????????????checked("lycos", searchEngine) + ">\n" +
????????????????"Lycos |\n" +
????????????????"<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +
????????????????"???????VALUE=\"hotbot\"" +
????????????????checked("hotbot", searchEngine) + ">\n" +
????????????????"HotBot\n" +
????????????????"<BR>\n" +
????????????????"<INPUT TYPE=\"SUBMIT\" VALUE=\"Search\">\n" +
????????????????"</CENTER>\n" +
????????????????"</FORM>\n" +
????????????????"\n" +
????????????????"</BODY>\n" +
????????????????"</HTML>\n");
??}

??private String checked(String name1, String name2) {
????if (name1.equals(name2))
??????return(" CHECKED");
????else
??????return("");
??}
}




   CustomizedSearchEngines.java

   前面的SearchEnginesFrontEnd Servlet把數據發送到CustomizedSearchEngines Servlet。本例在許多方面與前面介紹HTTP狀態代碼時的例子相似,區別在于,本例除了要構造一個針對搜索引擎的URL并向用戶發送一個重定向應答之外,還要發送保存用戶數據的Cookies。
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.net.*;

public class CustomizedSearchEngines extends HttpServlet {
??public void doGet(HttpServletRequest request,
????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????
????String searchString = request.getParameter("searchString");
????Cookie searchStringCookie =
??????new LongLivedCookie("searchString", searchString);
????response.addCookie(searchStringCookie);
????searchString = URLEncoder.encode(searchString);
????String numResults = request.getParameter("numResults");
????Cookie numResultsCookie =
??????new LongLivedCookie("numResults", numResults);
????response.addCookie(numResultsCookie);
????String searchEngine = request.getParameter("searchEngine");
????Cookie searchEngineCookie =
??????new LongLivedCookie("searchEngine", searchEngine);
????response.addCookie(searchEngineCookie);
????SearchSpec[] commonSpecs = SearchSpec.getCommonSpecs();
????for(int i=0; i<commonSpecs.length; i++) {
??????SearchSpec searchSpec = commonSpecs[i];
??????if (searchSpec.getName().equals(searchEngine)) {
????????String url =
??????????searchSpec.makeURL(searchString, numResults);
????????response.sendRedirect(url);
????????return;
??????}
????}
????response.sendError(response.SC_NOT_FOUND,
???????????????????????"No recognized search engine specified.");
??}

??public void doPost(HttpServletRequest request,
?????????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????doGet(request, response);
??}
}

十、會話狀態

10.1 會話狀態概述

  
HTTP協議的“無狀態”(Stateless)特點帶來了一系列的問題。特別是通過在線商店購物時,服務器不能順利地記住以前的事務就成了嚴重的問題。它使得“購物籃”之類的應用很難實現:當我們把商品加入購物籃時,服務器如何才能知道籃子里原先有些什么?即使服務器保存了上下文信息,我們仍舊會在電子商務應用中遇到問題。例如,當用戶從選擇商品的頁面(由普通的服務器提供)轉到輸入信用卡號和送達地址的頁面(由支持SSL的安全服務器提供),服務器如何才能記住用戶買了些什么?

   這個問題一般有三種解決方法:

Cookie。利用HTTP Cookie來存儲有關購物會話的信息,后繼的各個連接可以查看當前會話,然后從服務器的某些地方提取有關該會話的完整信息。這是一種優秀的,也是應用最廣泛的方法。然而,即使Servlet提供了一個高級的、使用方便的Cookie接口,仍舊有一些繁瑣的細節問題需要處理:
從其他Cookie中分別出保存會話標識的Cookie。
為Cookie設置合適的作廢時間(例如,中斷時間超過24小時的會話一般應重置)。
把會話標識和服務器端相應的信息關聯起來。(實際保存的信息可能要遠遠超過保存到Cookie的信息,而且象信用卡號等敏感信息永遠不應該用Cookie來保存。)
改寫URL。你可以把一些標識會話的數據附加到每個URL的后面,服務器能夠把該會話標識和它所保存的會話數據關聯起來。這也是一個很好的方法,而且還有當瀏覽器不支持Cookie或用戶已經禁用Cookie的情況下也有效這一優點。然而,大部分使用Cookie時所面臨的問題同樣存在,即服務器端的程序要進行許多簡單但單調冗長的處理。另外,還必須十分小心地保證每個URL后面都附加了必要的信息(包括非直接的,如通過Location給出的重定向URL)。如果用戶結束會話之后又通過書簽返回,則會話信息會丟失。
隱藏表單域。HTML表單中可以包含下面這樣的輸入域:<INPUT TYPE="HIDDEN" NAME="session" VALUE="...">。這意味著,當表單被提交時,隱藏域的名字和數據也被包含到GET或POST數據里,我們可以利用這一機制來維持會話信息。然而,這種方法有一個很大的缺點,它要求所有頁面都是動態生成的,因為整個問題的核心就是每個會話都要有一個唯一標識符。
   Servlet為我們提供了一種與眾不同的方案:HttpSession API。HttpSession API是一個基于Cookie或者URL改寫機制的高級會話狀態跟蹤接口:如果瀏覽器支持Cookie,則使用Cookie;如果瀏覽器不支持Cookie或者Cookie功能被關閉,則自動使用URL改寫方法。Servlet開發者無需關心細節問題,也無需直接處理Cookie或附加到URL后面的信息,API自動為Servlet開發者提供一個可以方便地存儲會話信息的地方。

  
10.2 會話狀態跟蹤API

  
在Servlet中使用會話信息是相當簡單的,主要的操作包括:查看和當前請求關聯的會話對象,必要的時候創建新的會話對象,查看與某個會話相關的信息,在會話對象中保存信息,以及會話完成或中止時釋放會話對象。

   10.2.1 查看當前請求的會話對象

   查看當前請求的會話對象通過調用HttpServletRequest的getSession方法實現。如果getSession方法返回null,你可以創建一個新的會話對象。但更經常地,我們通過指定參數使得不存在現成的會話時自動創建一個會話對象,即指定getSession的參數為true。因此,訪問當前請求會話對象的第一個步驟通常如下所示:
??HttpSession session = request.getSession(true);



   10.2.2 查看和會話有關的信息

   HttpSession對象生存在服務器上,通過Cookie或者URL這類后臺機制自動關聯到請求的發送者。會話對象提供一個內建的數據結構,在這個結構中可以保存任意數量的鍵-值對。在2.1或者更早版本的Servlet API中,查看以前保存的數據使用的是getValue("key")方法。getValue返回Object,因此你必須把它轉換成更加具體的數據類型。如果參數中指定的鍵不存在,getValue返回null。

   API 2.2版推薦用getAttribute來代替getValue,這不僅是因為getAttribute和setAttribute的名字更加匹配(和getValue匹配的是putValue,而不是setValue),同時也因為setAttribute允許使用一個附屬的HttpSessionBindingListener 來監視數值,而putValue則不能。

   但是,由于目前還只有很少的商業Servlet引擎支持2.2,下面的例子中我們仍舊使用getValue。這是一個很典型的例子,假定ShoppingCart是一個保存已購買商品信息的類:
??HttpSession session = request.getSession(true);
??ShoppingCart previousItems =
????(ShoppingCart)session.getValue("previousItems");
??if (previousItems != null) {
????doSomethingWith(previousItems);
??} else {
????previousItems = new ShoppingCart(...);
????doSomethingElseWith(previousItems);
??}



   大多數時候我們都是根據特定的名字尋找與它關聯的值,但也可以調用getValueNames得到所有屬性的名字。getValuesNames返回的是一個String數組。API 2.2版推薦使用getAttributeNames,這不僅是因為其名字更好,而且因為它返回的是一個Enumeration,和其他方法(比如HttpServletRequest的getHeaders和getParameterNames)更加一致。

   雖然開發者最為關心的往往是保存到會話對象的數據,但還有其他一些信息有時也很有用。

getID:該方法返回會話的唯一標識。有時該標識被作為鍵-值對中的鍵使用,比如會話中只保存一個值時,或保存上一次會話信息時。
isNew:如果客戶(瀏覽器)還沒有綁定到會話則返回true,通常意味著該會話剛剛創建,而不是引用自客戶端的請求。對于早就存在的會話,返回值為false。
getCreationTime:該方法返回建立會話的以毫秒計的時間,從1970.01.01(GMT)算起。要得到用于打印輸出的時間值,可以把該值傳遞給Date構造函數,或者GregorianCalendar的setTimeInMillis方法。
getLastAccessedTime:該方法返回客戶最后一次發送請求的以毫秒計的時間,從1970.01.01(GMT)算起。
getMaxInactiveInterval:返回以秒計的最大時間間隔,如果客戶請求之間的間隔不超過該值,Servlet引擎將保持會話有效。負數表示會話永遠不會超時。
10.2.3 在會話對象中保存數據

   如上節所述,讀取保存在會話中的信息使用的是getValue方法(或,對于2.2版的Servlet規范,使用getAttribute)。保存數據使用putValue(或setAttribute)方法,并指定鍵和相應的值。注意putValue將替換任何已有的值。有時候這正是我們所需要的(如下例中的referringPage),但有時我們卻需要提取原來的值并擴充它(如下例previousItems)。示例代碼如下:
??HttpSession session = request.getSession(true);
??session.putValue("referringPage", request.getHeader("Referer"));
??ShoppingCart previousItems =
????(ShoppingCart)session.getValue("previousItems");
??if (previousItems == null) {
????previousItems = new ShoppingCart(...);
??}
??String itemID = request.getParameter("itemID");
??previousItems.addEntry(Catalog.getEntry(itemID));

??session.putValue("previousItems", previousItems);



10.3 實例:顯示會話信息

   下面這個例子生成一個Web頁面,并在該頁面中顯示有關當前會話的信息。
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.net.*;
import java.util.*;

public class ShowSession extends HttpServlet {
??public void doGet(HttpServletRequest request,
?????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????HttpSession session = request.getSession(true);
????response.setContentType("text/html");
????PrintWriter out = response.getWriter();
????String title = "Searching the Web";
????String heading;
????Integer accessCount = new Integer(0);;
????if (session.isNew()) {
??????heading = "Welcome, Newcomer";
????} else {
??????heading = "Welcome Back";
??????Integer oldAccessCount =
????????// 在Servlet API 2.2中使用getAttribute而不是getValue
????????(Integer)session.getValue("accessCount");
??????if (oldAccessCount != null) {
????????accessCount =
??????????new Integer(oldAccessCount.intValue() + 1);
??????}
????}
????// 在Servlet API 2.2中使用putAttribute
????session.putValue("accessCount", accessCount);
??????
????out.println(ServletUtilities.headWithTitle(title) +
????????????????"<BODY BGCOLOR=\"#FDF5E6\">\n" +
????????????????"<H1 ALIGN=\"CENTER\">" + heading + "</H1>\n" +
????????????????"<H2>Information on Your Session:</H2>\n" +
????????????????"<TABLE BORDER=1 ALIGN=CENTER>\n" +
????????????????"<TR BGCOLOR=\"#FFAD00\">\n" +
????????????????"??<TH>Info Type<TH>Value\n" +
????????????????"<TR>\n" +
????????????????"??<TD>ID\n" +
????????????????"??<TD>" + session.getId() + "\n" +
????????????????"<TR>\n" +
????????????????"??<TD>Creation Time\n" +
????????????????"??<TD>" + new Date(session.getCreationTime()) + "\n" +
????????????????"<TR>\n" +
????????????????"??<TD>Time of Last Access\n" +
????????????????"??<TD>" + new Date(session.getLastAccessedTime()) + "\n" +
????????????????"<TR>\n" +
????????????????"??<TD>Number of Previous Accesses\n" +
????????????????"??<TD>" + accessCount + "\n" +
????????????????"</TABLE>\n" +
????????????????"</BODY></HTML>");
??}
??public void doPost(HttpServletRequest request,
?????????????????HttpServletResponse response)
??????throws ServletException, IOException {
????doGet(request, response);
??}
}

十一、JSP及語法概要

11.1 概述

   JavaServer Pages(JSP)使得我們能夠分離頁面的靜態HTML和動態部分。HTML可以用任何通常使用的Web制作工具編寫,編寫方式也和原來的一樣;動態部分的代碼放入特殊標記之內,大部分以“<%”開始,以“%>”結束。例如,下面是一個JSP頁面的片斷,如果我們用http://host/OrderConfirmation.jsp?title=Core+Web+Programming這個URL打開該頁面,則結果顯示“Thanks for ordering Core Web Programming”。
Thanks for ordering
<I><%= request.getParameter("title") %></I>

   JSP頁面文件通常以.jsp為擴展名,而且可以安裝到任何能夠存放普通Web頁面的地方。雖然從代碼編寫來看,JSP頁面更象普通Web頁面而不象Servlet,但實際上,JSP最終會被轉換成正規的Servlet,靜態HTML直接輸出到和Servlet service方法關聯的輸出流。

   JSP到Servlet的轉換過程一般在出現第一次頁面請求時進行。因此,如果你希望第一個用戶不會由于JSP頁面轉換成Servlet而等待太長的時間,希望確保Servlet已經正確地編譯并裝載,你可以在安裝JSP頁面之后自己請求一下這個頁面。

   另外也請注意,許多Web服務器允許定義別名,所以一個看起來指向HTML文件的URL實際上可能指向Servlet或JSP頁面。

   除了普通HTML代碼之外,嵌入JSP頁面的其他成分主要有如下三種:腳本元素(Scripting Element),指令(Directive),動作(Action)。腳本元素用來嵌入Java代碼,這些Java代碼將成為轉換得到的Servlet的一部分;JSP指令用來從整體上控制Servlet的結構;動作用來引入現有的組件或者控制JSP引擎的行為。為了簡化腳本元素,JSP定義了一組可以直接使用的變量(預定義變量),比如前面代碼片斷中的request就是其中一例。

   注意本文以JSP 1.0規范為基礎。和0.92版相比,新版本的JSP作了許多重大的改動。雖然這些改動只會使JSP變得更好,但應注意1.0的JSP頁面幾乎和早期的JSP引擎完全不兼容。

11.2 JSP語法概要表 JSP元素??語法??說明??備注??

JSP表達式??<%= expression %>??計算表達式并輸出結果。??等價的XML表達是:
<jsp:expression>
expression
</jsp:expression>

可以使用的預定義變量包括:request,response,out,session,application,config,pageContext。這些預定義變量也可以在JSP Scriptlet中使用。

JSP Scriptlet??<% code %>??插入到service方法的代碼。??等價的XML表達是:
<jsp:scriptlet>
code
</jsp:scriptlet>

JSP聲明??<%! code %>??代碼被插入到Servlet類(在service方法之外)。??等價的XML表達是:
<jsp:declaration>
code
</jsp:declaration>

page指令??<%@ page att="val" %>??作用于Servlet引擎的全局性指令。??等價的XML表達是
<jsp:directive.page att="val"\>。

合法的屬性如下表,其中粗體表示默認值:

import="package.class"
contentType="MIME-Type"
isThreadSafe="true|false"
session="true|false"
buffer="size kb|none"
autoflush="true|false"
extends="package.class"
info="message"
errorPage="url"
isErrorPage="true|false"
language="java"

include指令??<%@ include file="url" %>??當JSP轉換成Servlet時,應當包含本地系統上的指定文件。??等價的XML表達是:

<jsp:directive.include
file="url"\>.

其中URL必須是相對URL。

利用jsp:include動作可以在請求的時候(而不是JSP轉換成Servlet時)引入文件。

JSP注釋??<%-- comment --%>??注釋;JSP轉換成Servlet時被忽略。??如果要把注釋嵌入結果HTML文檔,使用普通的HTML注釋標記<-- comment -->。??
jsp:include動作??<jsp:include
page="relative URL"
flush="true"/>??當Servlet被請求時,引入指定的文件。??如果你希望在頁面轉換的時候包含某個文件,使用JSP include指令。
注意:在某些服務器上,被包含文件必須是HTML文件或JSP文件,具體由服務器決定(通常根據文件擴展名判斷)。

jsp:useBean動作??<jsp:useBean att=val*/> 或者
<jsp:useBean att=val*>
...
</jsp:useBean>??尋找或實例化一個Java Bean。??可能的屬性包括:
id="name"
scope="page|request
|session|application"
class="package.class"
type="package.class"
beanName="package.class"

jsp:setProperty動作??<jsp:setProperty att=val*/>??設置Bean的屬性。既可以設置一個確定的值,也可以指定屬性值來自請求參數。??合法的屬性包括:
name="beanName"
property="propertyName|*"
param="parameterName"
value="val"

jsp:getProperty動作??<jsp:getProperty
name="propertyName"
value="val"/>??提取并輸出Bean的屬性。?? ??
jsp:forward動作??<jsp:forward
page="relative URL"/>??把請求轉到另外一個頁面。?? ??
jsp:plugin動作??<jsp:plugin
attribute="value"*>
...
</jsp:plugin>??根據瀏覽器類型生成OBJECT或者EMBED標記,以便通過Java Plugin運行Java Applet。?? ??


11.3 關于模板文本(靜態HTML)

  
許多時候,JSP頁面的很大一部分都由靜態HTML構成,這些靜態HTML也稱為“模板文本”。模板文本和普通HTML幾乎完全相同,它們都遵從相同的語法規則,而且模板文本也是被Servlet直接發送到客戶端。此外,模板文本也可以用任何現有的頁面制作工具來編寫。

   唯一的例外在于,如果要輸出“<%”,則模板文本中應該寫成“<\%”。

?

?

?

十二、腳本元素、指令和預定義變量

12.1 JSP腳本元素

   JSP腳本元素用來插入Java代碼,這些Java代碼將出現在由當前JSP頁面生成的Servlet中。腳本元素有三種格式:

表達式格式<%= expression %>:計算表達式并輸出其結果。
Scriptlet格式<% code %>:把代碼插入到Servlet的service方法。
聲明格式<%! code %>:把聲明加入到Servlet類(在任何方法之外)。
   下面我們詳細說明它們的用法。

   12.1.1 JSP表達式

   JSP表達式用來把Java數據直接插入到輸出。其語法如下:
<%= Java Expression %>



   計算Java表達式得到的結果被轉換成字符串,然后插入到頁面。計算在運行時進行(頁面被請求時),因此可以訪問和請求有關的全部信息。例如,下面的代碼顯示頁面被請求的日期/時間:
Current time: <%= new java.util.Date() %>



   為簡化這些表達式,JSP預定義了一組可以直接使用的對象變量。后面我們將詳細介紹這些隱含聲明的對象,但對于JSP表達式來說,最重要的幾個對象及其類型如下:

request:HttpServletRequest;
response:HttpServletResponse;
session:和request關聯的HttpSession
out:PrintWriter(帶緩沖的版本,JspWriter),用來把輸出發送到客戶端
   下面是一個例子:
Your hostname: <%= request.getRemoteHost() %>



   最后,如果使用XML的話,JSP表達式也可以寫成下面這種形式:
<jsp:expression>
Java Expression
</jsp:expression>



   請記住XML元素和HTML不一樣。XML是大小寫敏感的,因此務必使用小寫。有關XML語法的說明,請參見《XML教程 》

   12.1.2 JSP Scriptlet

   如果你要完成的任務比插入簡單的表達式更加復雜,可以使用JSP Scriptlet。JSP Scriptlet允許你把任意的Java代碼插入Servlet。JSP Scriptlet語法如下:
<% Java Code %>



   和JSP表達式一樣,Scriptlet也可以訪問所有預定義的變量。例如,如果你要向結果頁面輸出內容,可以使用out變量:
<%
String queryData = request.getQueryString();
out.println("Attached GET data: " + queryData);
%>



   注意Scriptlet中的代碼將被照搬到Servlet內,而Scriptlet前面和后面的靜態HTML(模板文本)將被轉換成println語句。這就意味著,Scriptlet內的Java語句并非一定要是完整的,沒有關閉的塊將影響Scriptlet外的靜態HTML。例如,下面的JSP片斷混合了模板文本和Scriptlet:
<% if (Math.random() < 0.5) { %>
Have a <B>nice</B> day!
<% } else { %>
Have a <B>lousy</B> day!
<% } %>

上述JSP代碼將被轉換成如下Servlet代碼:
if (Math.random() < 0.5) {
??out.println("Have a <B>nice</B> day!");
} else {
??out.println("Have a <B>lousy</B> day!");
}



   如果要在Scriptlet內部使用字符“%>”,必須寫成“%\>”。另外,請注意<% code %>的XML等價表達是:
<jsp:scriptlet>
Code
</jsp:scriptlet>



   12.1.3 JSP聲明

   JSP聲明用來定義插入Servlet類的方法和成員變量,其語法如下:
<%! Java Code %>



   由于聲明不會有任何輸出,因此它們往往和JSP表達式或Scriptlet結合在一起使用。例如,下面的JSP代碼片斷輸出自從服務器啟動(或Servlet類被改動并重新裝載以來)當前頁面被請求的次數:
<%! private int accessCount = 0; %>
自從服務器啟動以來頁面訪問次數為:
<%= ++accessCount %>



   和Scriptlet一樣,如果要使用字符串“%>”,必須使用“%\>”代替。最后,<%! code %>的XML等價表達方式為:
<jsp:declaration>
Code
</jsp:declaration>



12.2 JSP指令

   JSP指令影響Servlet類的整體結構,它的語法一般如下:
<%@ directive attribute="value" %>



   另外,也可以把同一指令的多個屬性結合起來,例如:
<%@ directive attribute1="value1"
?????????attribute2="value2"
?????????...
?????????attributeN="valueN" %>



   JSP指令分為兩種類型:第一是page指令,用來完成下面這類任務:導入指定的類,自定義Servlet的超類,等等;第二是include指令,用來在JSP文件轉換成Servlet時引入其他文件。JSP規范也提到了taglib指令,其目的是讓JSP開發者能夠自己定義標記,但JSP 1.0不支持該指令,有希望它將成為JSP 1.1的主要改進之一。

?

12.2.1 page指令

   page指令的作用是定義下面一個或多個屬性,這些屬性大小寫敏感。



import="package.class",或者import="package.class1,...,package.classN":

用于指定導入哪些包,例如:<%@ page import="java.util.*" %>。import是唯一允許出現一次以上的屬性。


contentType="MIME-Type" 或contentType="MIME-Type; charset=Character-Set":

該屬性指定輸出的MIME類型。默認是text/html。例如,下面這個指令:
<%@ page contentType="text/plain" %>。
和下面的Scriptlet效果相同:
<% response.setContentType("text/plain"); %>


isThreadSafe="true|false"

默認值true表明Servlet按照標準的方式處理,即假定開發者已經同步對實例變量的訪問,由單個Servlet實例同時地處理多個請求。如果取值false,表明Servlet應該實現SingleThreadModel,請求或者是逐個進入,或者多個并行的請求分別由不同的Servlet實例處理。


session="true|false"

默認值true表明預定義變量session(類型為HttpSession)應該綁定到已有的會話,如果不存在已有的會話,則新建一個并綁定session變量。如果取值false,表明不會用到會話,試圖訪問變量session將導致JSP轉換成Servlet時出錯。


buffer="size kb|none"

該屬性指定JspWrite out的緩存大小。默認值和服務器有關,但至少應該是8 KB。


autoflush="true|false"

默認值true表明如果緩存已滿則刷新它。autoflush很少取false值,false值表示如果緩存已滿則拋出異常。如果buffer="none",autoflush不能取false值。


extends="package.class"

該屬性指出將要生成的Servlet使用哪個超類。使用該屬性應當十分小心,因為服務器可能已經在用自定義的超類。


info="message"

該屬性定義一個可以通過getServletInfo方法提取的字符串。


errorPage="url"

該屬性指定一個JSP頁面,所有未被當前頁面捕獲的異常均由該頁面處理。


isErrorPage="true|false"

該屬性指示當前頁面是否可以作為另一JSP頁面的錯誤處理頁面。默認值false。


language="java"

該屬性用來指示所使用的語言。目前沒有必要關注這個屬性,因為默認的Java是當前唯一可用的語言。
   定義指令的XML語法為:
<jsp:directive.directiveType attribute=value />



   例如,下面這個指令:
<%@ page import="java.util.*" %>



   它的XML等價表達是:
<jsp:directive.page import="java.util.*" />



   12.2.2 include指令

   include指令用于JSP頁面轉換成Servlet時引入其他文件。該指令語法如下:
<%@ include file="relative url" %>



   這里所指定的URL是和發出引用指令的JSP頁面相對的URL,然而,與通常意義上的相對URL一樣,你可以利用以“/”開始的URL告訴系統把URL視為從Web服務器根目錄開始。包含文件的內容也是JSP代碼,即包含文件可以包含靜態HTML、腳本元素、JSP指令和動作。

   例如,許多網站的每個頁面都有一個小小的導航條。由于HTML框架存在不少問題,導航條往往用頁面頂端或左邊的一個表格制作,同一份HTML代碼重復出現在整個網站的每個頁面上。include指令是實現該功能的非常理想的方法。使用include指令,開發者不必再把導航HTML代碼拷貝到每個文件中,從而可以更輕松地完成維護工作。

   由于include指令是在JSP轉換成Servlet的時候引入文件,因此如果導航條改變了,所有使用該導航條的JSP頁面都必須重新轉換成Servlet。如果導航條改動不頻繁,而且你希望包含操作具有盡可能好的效率,使用include指令是最好的選擇。然而,如果導航條改動非常頻繁,你可以使用jsp:include動作。jsp:include動作在出現對JSP頁面請求的時候才會引用指定的文件,請參見本文后面的具體說明。

12.3 實例:腳本元素和指令的應用

   下面是一個使用JSP表達式、Scriptlet、聲明、指令的簡單例子。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>JavaServer Pages</TITLE>
</HEAD>

<BODY BGCOLOR="#FDF5E6" TEXT="#000000" LINK="#0000EE"
??????VLINK="#551A8B" ALINK="#FF0000">
<CENTER>
<TABLE BORDER=5 BGCOLOR="#EF8429">
??<TR><TH CLASS="TITLE">
??????JSP應用實例</TABLE>
</CENTER>
<P>
下面是一些利用各種JSP功能生成的動態內容:
<UL>
??<LI><B>表達式.</B><BR>
??????你的主機名: <%= request.getRemoteHost() %>.
??<LI><B>JSP Scriptlet.</B><BR>
??????<% out.println("查詢字符串: " +
?????????????????????request.getQueryString()); %>
??<LI><B>聲明(和表達式).</B><BR>
??????<%! private int accessCount = 0; %>
??????服務器啟動以來訪問次數: <%= ++accessCount %>
??<LI><B>指令(和表達式).</B><BR>
??????<%@ page import = "java.util.*" %>
??????當前日期: <%= new Date() %>
</UL>

</BODY>
</HTML>



12.4 JSP預定義變量

   為了簡化JSP表達式和Scriptlet的代碼,JSP提供了8個預先定義的變量(或稱為隱含對象)。這些變量是request、response、out、session、application、config、pageContext和page。

   12.4.1 request

   這是和請求關聯的HttpServletRequest,通過它可以查看請求參數(調用getParameter),請求類型(GET,POST,HEAD,等),以及請求的HTTP頭(Cookie,Referer,等)。嚴格說來,如果請求所用的是HTTP之外的其他協議,request可以是ServletRequest的子類(而不是HttpServletRequest),但在實踐中幾乎不會用到。

   12.4.2 response

   這是和應答關聯的HttpServletResponse。注意,由于輸出流(參見下面的out)是帶緩沖的,因此,如果已經向客戶端發送了輸出內容,普通Servlet不允許再設置HTTP狀態代碼,但在JSP中卻是合法的。

   12.4.3 out

   這是用來向客戶端發送內容的PrintWriter。然而,為了讓response對象更為實用,out是帶緩存功能的PrintWriter,即JspWriter。JSP允許通過page指令的buffer屬性調整緩存的大小,甚至允許關閉緩存。

   out一般只在Scriptlet內使用,這是因為JSP表達式是自動發送到輸出流的,很少需要顯式地引用out。

   12.4.4 session

   這是和請求關聯的HttpSession對象。前面我們已經介紹過會話的自動創建,我們知道,即使不存在session引用,這個對象也是自動綁定的。但有一個例外,這就是如果你用page指令的session屬性關閉了會話,此時對session變量的引用將導致JSP頁面轉換成Servlet時出錯。

   12.4.5 application

   這是一個ServletContext,也可以通過getServletConfig().getContext()獲得。

   12.4.6 config

   這是當前頁面的ServletConfig對象。

   12.4.7 pageContext

   主要用來管理頁面的屬性。

   12.4.8 page

   它是this的同義詞,當前用處不大。它是為了Java不再是唯一的JSP編程語言而準備的占位符。

JSP動作利用XML語法格式的標記來控制Servlet引擎的行為。利用JSP動作可以動態地插入文件、重用JavaBean組件

下面是一個很簡單的例子,它的功能是裝載一個Bean,然后設置/讀取它的message屬性。

   BeanTest.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Reusing JavaBeans in JSP</TITLE>
</HEAD>

<BODY>
<CENTER>
<TABLE BORDER=5>
??<TR><TH CLASS="TITLE">
??????Reusing JavaBeans in JSP</TABLE>
</CENTER>
<P>

<jsp:useBean id="test" class="hall.SimpleBean" />
<jsp:setProperty name="test"
??????????property="message"
??????????value="Hello WWW" />
<H1>Message: <I>
<jsp:getProperty name="test" property="message" />
</I></H1>
?????????????
</BODY>
</HTML>



   SimpleBean.java

   BeanTest頁面用到了一個SimpleBean。SimpleBean的代碼如下:
package hall;

public class SimpleBean {
??private String message = "No message specified";

??public String getMessage() {
????return(message);
??}

??public void setMessage(String message) {
????this.message = message;
??}
}


13.3 關于jsp:useBean的進一步說明

   使用Bean最簡單的方法是先用下面的代碼裝載Bean:
<jsp:useBean id="name" class="package.class" />



   然后通過jsp:setProperty和jsp:getProperty修改和提取Bean的屬性。不過有兩點必須注意。第一,我們還可以用下面這種格式實例化Bean:
??<jsp:useBean ...>
????Body
??</jsp:useBean>



   它的意思是,只有當第一次實例化Bean時才執行Body部分,如果是利用現有的Bean實例則不執行Body部分。正如下面將要介紹的,jsp:useBean并非總是意味著創建一個新的Bean實例。

   第二,除了id和class外,jsp:useBean還有其他三個屬性,即:scope,type,beanName。下表簡要說明這些屬性的用法。 屬性??用法??
id??命名引用該Bean的變量。如果能夠找到id和scope相同的Bean實例,jsp:useBean動作將使用已有的Bean實例而不是創建新的實例。??
class??指定Bean的完整包名。??
scope??指定Bean在哪種上下文內可用,可以取下面的四個值之一:page,request,session和application。
默認值是page,表示該Bean只在當前頁面內可用(保存在當前頁面的PageContext內)。
request表示該Bean在當前的客戶請求內有效(保存在ServletRequest對象內)。
session表示該Bean對當前HttpSession內的所有頁面都有效。
最后,如果取值application,則表示該Bean對所有具有相同ServletContext的頁面都有效。
scope之所以很重要,是因為jsp:useBean只有在不存在具有相同id和scope的對象時才會實例化新的對象;如果已有id和scope都相同的對象則直接使用已有的對象,此時jsp:useBean開始標記和結束標記之間的任何內容都將被忽略。

type??指定引用該對象的變量的類型,它必須是Bean類的名字、超類名字、該類所實現的接口名字之一。請記住變量的名字是由id屬性指定的。??
beanName??指定Bean的名字。如果提供了type屬性和beanName屬性,允許省略class屬性。??


13.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放入jsp: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自己提供默認屬性值,只有當請求參數明確指定了新值時才修改默認屬性值。
例如,下面的代碼片斷表示:如果存在numItems請求參數的話,把numberOfItems屬性的值設置為請求參數numItems的值;否則什么也不做。

<jsp:setProperty name="orderBean"
property="numberOfItems"
param="numItems" />

如果同時省略value和param,其效果相當于提供一個param且其值等于property的值。進一步利用這種借助請求參數和屬性名字相同進行自動賦值的思想,你還可以在property(Bean屬性的名字)中指定“*”,然后省略value和param。此時,服務器會查看所有的Bean屬性和請求參數,如果兩者名字相同則自動賦值。



   下面是一個利用JavaBean計算素數的例子。如果請求中有一個numDigits參數,則該值被傳遞給Bean的numDigits屬性;numPrimes也類似。

   JspPrimes.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>在JSP中使用JavaBean</TITLE>
</HEAD>

<BODY>

<CENTER>
<TABLE BORDER=5>
??<TR><TH CLASS="TITLE">
??????在JSP中使用JavaBean</TABLE>
</CENTER>
<P>

<jsp:useBean id="primeTable" class="hall.NumberedPrimes" />
<jsp:setProperty name="primeTable" property="numDigits" />
<jsp:setProperty name="primeTable" property="numPrimes" />

Some <jsp:getProperty name="primeTable" property="numDigits" />
digit primes:
<jsp:getProperty name="primeTable" property="numberedList" />

</BODY>
</HTML>



   注:NumberedPrimes的代碼略。

13.5 jsp:getProperty動作

   jsp:getProperty動作提取指定Bean屬性的值,轉換成字符串,然后輸出。jsp:getProperty有兩個必需的屬性,即:name,表示Bean的名字;property,表示要提取哪個屬性的值。下面是一個例子,更多的例子可以在前文找到。
<jsp:useBean id="itemBean" ... />
...
<UL>
??<LI>Number of items:
??????<jsp:getProperty name="itemBean" property="numItems" />
??<LI>Cost of each:
??????<jsp:getProperty name="itemBean" property="unitCost" />
</UL>



13.6 jsp:forward動作

  
jsp:forward動作把請求轉到另外的頁面。jsp:forward標記只有一個屬性page。page屬性包含的是一個相對URL。page的值既可以直接給出,也可以在請求的時候動態計算,如下面的例子所示:
<jsp:forward page="/utils/errorReporter.jsp" />
<jsp:forward page="<%= someJavaExpression %>" />



13.7 jsp:plugin動作

   jsp:plugin動作用來根據瀏覽器的類型,插入通過Java插件 運行Java Applet所必需的OBJECT或EMBED元素。

附錄:JSP注釋和字符引用約定

  
下面是一些特殊的標記或字符,你可以利用它們插入注釋或可能被視為具有特殊含義的字符。 語法??用途??
<%-- comment --%>??JSP注釋,也稱為“隱藏注釋”。JSP引擎將忽略它。標記內的所有JSP腳本元素、指令和動作都將不起作用。??
<!-- comment -->??HTML注釋,也稱為“輸出的注釋”,直接出現在結果HTML文檔中。標記內的所有JSP腳本元素、指令和動作正常執行。??
<\%??在模板文本(靜態HTML)中實際上希望出現“<%”的地方使用。??
%\>??在腳本元素內實際上希望出現“%>”的地方使用。??
\'??使用單引號的屬性內的單引號。不過,你既可以使用單引號也可以使用雙引號,而另外一種引號將具有普通含義。??
\"??使用雙引號的屬性內的雙引號。參見“\'”的說明。

?

?

?

?

?

總結

以上是生活随笔為你收集整理的Java Servlet和JSP教程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

国产乱人无码伦av在线a | 玩弄少妇高潮ⅹxxxyw | 色窝窝无码一区二区三区色欲 | 人妻尝试又大又粗久久 | 亚洲中文字幕成人无码 | 3d动漫精品啪啪一区二区中 | 性色欲情网站iwww九文堂 | 99riav国产精品视频 | 高清国产亚洲精品自在久久 | 欧美变态另类xxxx | 欧美人与善在线com | 国产suv精品一区二区五 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 巨爆乳无码视频在线观看 | 国产成人无码专区 | 亚洲国产成人av在线观看 | 高清无码午夜福利视频 | 精品欧美一区二区三区久久久 | 国产欧美精品一区二区三区 | 午夜嘿嘿嘿影院 | 天海翼激烈高潮到腰振不止 | 2020久久香蕉国产线看观看 | 国产国产精品人在线视 | 性欧美videos高清精品 | 精品国偷自产在线视频 | 精品无码av一区二区三区 | 无码av最新清无码专区吞精 | 国内精品人妻无码久久久影院蜜桃 | 国产精品第一区揄拍无码 | 国产精品99久久精品爆乳 | 女人被爽到呻吟gif动态图视看 | 国产麻豆精品一区二区三区v视界 | 久久久久亚洲精品中文字幕 | 精品国产一区av天美传媒 | 国产亚洲日韩欧美另类第八页 | 特级做a爰片毛片免费69 | 久9re热视频这里只有精品 | 国产成人精品一区二区在线小狼 | 久久亚洲中文字幕精品一区 | 国产欧美精品一区二区三区 | 精品偷自拍另类在线观看 | 久久久成人毛片无码 | aa片在线观看视频在线播放 | 亚洲中文字幕无码中文字在线 | 国产成人精品久久亚洲高清不卡 | 日韩人妻无码中文字幕视频 | 日韩人妻系列无码专区 | 天干天干啦夜天干天2017 | 男女作爱免费网站 | 久久精品人人做人人综合试看 | 亚洲欧美精品aaaaaa片 | 国产精品久久久久久久9999 | 永久免费精品精品永久-夜色 | 网友自拍区视频精品 | 久久综合九色综合欧美狠狠 | 噜噜噜亚洲色成人网站 | 亚洲一区二区三区含羞草 | 天堂在线观看www | 久久久久人妻一区精品色欧美 | 露脸叫床粗话东北少妇 | 女高中生第一次破苞av | 国产精品igao视频网 | 99久久久无码国产精品免费 | 女高中生第一次破苞av | 成在人线av无码免观看麻豆 | 巨爆乳无码视频在线观看 | 精品国产麻豆免费人成网站 | 人妻aⅴ无码一区二区三区 | 亚洲性无码av中文字幕 | 精品国精品国产自在久国产87 | 装睡被陌生人摸出水好爽 | 蜜桃视频插满18在线观看 | 精品国产av色一区二区深夜久久 | 一本久道高清无码视频 | 在线观看免费人成视频 | 中文字幕乱码中文乱码51精品 | 亚洲va欧美va天堂v国产综合 | 黑人玩弄人妻中文在线 | 日日鲁鲁鲁夜夜爽爽狠狠 | 中文字幕人成乱码熟女app | 人妻中文无码久热丝袜 | 亚洲精品成人福利网站 | 香港三级日本三级妇三级 | 九月婷婷人人澡人人添人人爽 | 精品人人妻人人澡人人爽人人 | 国产精品-区区久久久狼 | 国内老熟妇对白xxxxhd | 精品久久久无码人妻字幂 | 色偷偷人人澡人人爽人人模 | 亚洲理论电影在线观看 | 99re在线播放 | 亚洲精品一区二区三区在线观看 | 久久精品人妻少妇一区二区三区 | 国产人妻大战黑人第1集 | 中国大陆精品视频xxxx | 亚洲а∨天堂久久精品2021 | 精品无码国产一区二区三区av | 国产性生交xxxxx无码 | 国产成人综合色在线观看网站 | 学生妹亚洲一区二区 | 欧美一区二区三区视频在线观看 | 伊人久久婷婷五月综合97色 | 天天摸天天碰天天添 | 久久99精品国产麻豆蜜芽 | 亚洲一区二区三区四区 | 午夜精品久久久久久久久 | 天堂在线观看www | 亚洲欧洲日本无在线码 | 日日橹狠狠爱欧美视频 | 婷婷六月久久综合丁香 | 精品 日韩 国产 欧美 视频 | 激情亚洲一区国产精品 | 国产精品对白交换视频 | 玩弄中年熟妇正在播放 | 曰韩无码二三区中文字幕 | 玩弄中年熟妇正在播放 | 伊在人天堂亚洲香蕉精品区 | 欧美 亚洲 国产 另类 | 成人av无码一区二区三区 | 黑森林福利视频导航 | 午夜福利不卡在线视频 | 十八禁视频网站在线观看 | 中文字幕乱码亚洲无线三区 | 精品国产精品久久一区免费式 | 日韩成人一区二区三区在线观看 | 一本久久a久久精品亚洲 | 小sao货水好多真紧h无码视频 | 人妻体内射精一区二区三四 | 亚洲毛片av日韩av无码 | aⅴ亚洲 日韩 色 图网站 播放 | 亚洲 激情 小说 另类 欧美 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产成人综合美国十次 | 国产成人精品视频ⅴa片软件竹菊 | 在线播放免费人成毛片乱码 | 久久精品人人做人人综合试看 | 亚洲一区二区三区含羞草 | 国产精品久久久 | 国产午夜福利100集发布 | 色综合久久久久综合一本到桃花网 | 四虎永久在线精品免费网址 | 日本丰满护士爆乳xxxx | 在线播放免费人成毛片乱码 | 伊人色综合久久天天小片 | 少妇无码av无码专区在线观看 | 无码国模国产在线观看 | 大肉大捧一进一出视频出来呀 | 无码国模国产在线观看 | 荫蒂添的好舒服视频囗交 | 亚洲欧美日韩综合久久久 | 国产va免费精品观看 | 国产精品高潮呻吟av久久 | 欧美日韩视频无码一区二区三 | 乌克兰少妇性做爰 | 亚洲熟妇色xxxxx欧美老妇y | 午夜精品一区二区三区在线观看 | 国产在热线精品视频 | 国产精品丝袜黑色高跟鞋 | 亚洲爆乳精品无码一区二区三区 | 欧美日韩亚洲国产精品 | 无套内射视频囯产 | 99久久精品无码一区二区毛片 | 男人的天堂av网站 | 国产在线精品一区二区三区直播 | 日本一卡2卡3卡四卡精品网站 | 国产亚洲精品久久久久久 | 亚洲精品一区二区三区婷婷月 | 精品国产aⅴ无码一区二区 | 亚洲欧美国产精品专区久久 | 亚洲成色www久久网站 | 精品偷拍一区二区三区在线看 | 国产香蕉97碰碰久久人人 | 激情内射亚州一区二区三区爱妻 | 欧美乱妇无乱码大黄a片 | 国产亚洲精品久久久久久 | 日本高清一区免费中文视频 | 国产欧美亚洲精品a | 天干天干啦夜天干天2017 | 少妇人妻偷人精品无码视频 | 无码纯肉视频在线观看 | 西西人体www44rt大胆高清 | 久久久久久亚洲精品a片成人 | 爽爽影院免费观看 | 无码国内精品人妻少妇 | 国产成人精品视频ⅴa片软件竹菊 | 一区二区三区高清视频一 | 色婷婷香蕉在线一区二区 | 国产成人无码av片在线观看不卡 | 国产又粗又硬又大爽黄老大爷视 | 蜜桃无码一区二区三区 | 一二三四社区在线中文视频 | 婷婷色婷婷开心五月四房播播 | 无码国模国产在线观看 | 亚洲一区二区三区国产精华液 | 欧美成人家庭影院 | 大乳丰满人妻中文字幕日本 | 俺去俺来也在线www色官网 | 成人毛片一区二区 | 无码人妻久久一区二区三区不卡 | 波多野结衣高清一区二区三区 | 日本熟妇浓毛 | 无码人妻精品一区二区三区不卡 | 在线欧美精品一区二区三区 | 97久久超碰中文字幕 | 啦啦啦www在线观看免费视频 | 国产无遮挡吃胸膜奶免费看 | 少妇人妻偷人精品无码视频 | 午夜理论片yy44880影院 | 露脸叫床粗话东北少妇 | 亚洲国产精华液网站w | 国产亚洲精品久久久久久久 | 久久人妻内射无码一区三区 | 久久无码人妻影院 | 亚洲精品久久久久久一区二区 | 亚洲熟妇色xxxxx欧美老妇y | 乌克兰少妇性做爰 | 天堂一区人妻无码 | 人妻熟女一区 | 日韩av激情在线观看 | 亚洲人成人无码网www国产 | 久久人人爽人人爽人人片av高清 | 日本饥渴人妻欲求不满 | 婷婷色婷婷开心五月四房播播 | 天天av天天av天天透 | 少妇人妻av毛片在线看 | 人人妻人人澡人人爽人人精品 | 无码吃奶揉捏奶头高潮视频 | 夜夜夜高潮夜夜爽夜夜爰爰 | 久久精品国产99久久6动漫 | 久久精品丝袜高跟鞋 | 中文字幕久久久久人妻 | 国产乱人伦av在线无码 | 又色又爽又黄的美女裸体网站 | 亚洲国产成人av在线观看 | 99麻豆久久久国产精品免费 | 国内老熟妇对白xxxxhd | 大胆欧美熟妇xx | 狠狠色欧美亚洲狠狠色www | 九九久久精品国产免费看小说 | 亚洲人成影院在线观看 | 久久综合久久自在自线精品自 | 国产真实夫妇视频 | av小次郎收藏 | 国产成人无码a区在线观看视频app | 久久国产精品萌白酱免费 | 欧美精品无码一区二区三区 | 一本大道久久东京热无码av | 精品国产青草久久久久福利 | 中文无码成人免费视频在线观看 | 亚洲综合久久一区二区 | 中文字幕无码热在线视频 | 欧美高清在线精品一区 | 老熟女乱子伦 | 久久99精品久久久久久动态图 | 婷婷丁香六月激情综合啪 | 一本精品99久久精品77 | 人人妻人人澡人人爽人人精品 | 风流少妇按摩来高潮 | 国产在热线精品视频 | www国产亚洲精品久久网站 | 婷婷丁香五月天综合东京热 | 中文字幕无线码免费人妻 | 国产三级精品三级男人的天堂 | 欧美 丝袜 自拍 制服 另类 | 精品熟女少妇av免费观看 | 中文字幕色婷婷在线视频 | 国产真实乱对白精彩久久 | 国产免费久久久久久无码 | 国产精品亚洲а∨无码播放麻豆 | 麻豆精品国产精华精华液好用吗 | 少妇厨房愉情理9仑片视频 | 欧美老熟妇乱xxxxx | 亚洲国精产品一二二线 | 欧美人与禽zoz0性伦交 | 亚洲国精产品一二二线 | 中文字幕人妻无码一夲道 | 成年美女黄网站色大免费视频 | аⅴ资源天堂资源库在线 | 国产精品丝袜黑色高跟鞋 | 亚洲经典千人经典日产 | 国产猛烈高潮尖叫视频免费 | 国产精品理论片在线观看 | 亚洲精品一区二区三区在线 | 成人毛片一区二区 | 天堂无码人妻精品一区二区三区 | 99精品视频在线观看免费 | 午夜无码人妻av大片色欲 | 成熟人妻av无码专区 | 精品无码一区二区三区爱欲 | 亚洲 日韩 欧美 成人 在线观看 | 熟女少妇人妻中文字幕 | 波多野结衣乳巨码无在线观看 | 国产精品久久久久无码av色戒 | 国产高清不卡无码视频 | 狠狠cao日日穞夜夜穞av | 夜夜影院未满十八勿进 | 亚洲国产欧美日韩精品一区二区三区 | 成年美女黄网站色大免费视频 | 精品国产乱码久久久久乱码 | 亚洲aⅴ无码成人网站国产app | 欧美国产日韩亚洲中文 | 小sao货水好多真紧h无码视频 | 久精品国产欧美亚洲色aⅴ大片 | 露脸叫床粗话东北少妇 | 国产99久久精品一区二区 | 伊人久久婷婷五月综合97色 | 性色欲网站人妻丰满中文久久不卡 | 日日摸日日碰夜夜爽av | 亚洲精品国产a久久久久久 | 欧美人与禽zoz0性伦交 | 天堂а√在线地址中文在线 | 亚洲精品中文字幕久久久久 | 亚洲综合在线一区二区三区 | 男女猛烈xx00免费视频试看 | 欧美日韩亚洲国产精品 | 欧美亚洲日韩国产人成在线播放 | 极品尤物被啪到呻吟喷水 | 欧美怡红院免费全部视频 | 国产亚洲精品久久久久久 | 精品国产av色一区二区深夜久久 | 欧美放荡的少妇 | 国产手机在线αⅴ片无码观看 | 国产精品永久免费视频 | 好男人社区资源 | 日日碰狠狠躁久久躁蜜桃 | 中文字幕+乱码+中文字幕一区 | 国产午夜无码精品免费看 | 撕开奶罩揉吮奶头视频 | 鲁鲁鲁爽爽爽在线视频观看 | 三级4级全黄60分钟 | 精品久久久久香蕉网 | 亚洲成a人一区二区三区 | 欧美三级a做爰在线观看 | 日韩精品a片一区二区三区妖精 | 国产精品国产三级国产专播 | 亚洲日本va中文字幕 | 国产精品无套呻吟在线 | 久久精品人妻少妇一区二区三区 | 亚洲国产欧美国产综合一区 | 欧美人与物videos另类 | 国产99久久精品一区二区 | 激情国产av做激情国产爱 | 日日天干夜夜狠狠爱 | 国产精品高潮呻吟av久久4虎 | 2019午夜福利不卡片在线 | 国产手机在线αⅴ片无码观看 | 玩弄中年熟妇正在播放 | 中文字幕亚洲情99在线 | 亚洲人成人无码网www国产 | 无码人妻出轨黑人中文字幕 | 国产精品嫩草久久久久 | 中文字幕 人妻熟女 | 无遮无挡爽爽免费视频 | 亚洲综合伊人久久大杳蕉 | 精品一区二区三区无码免费视频 | 四虎永久在线精品免费网址 | 欧美兽交xxxx×视频 | 国产av一区二区三区最新精品 | 亚洲精品一区二区三区四区五区 | 亚洲の无码国产の无码影院 | 国产午夜亚洲精品不卡 | 国产成人无码a区在线观看视频app | 亚洲 日韩 欧美 成人 在线观看 | 成人性做爰aaa片免费看不忠 | 丰满肥臀大屁股熟妇激情视频 | 免费无码av一区二区 | 色五月五月丁香亚洲综合网 | 亚洲国产精品久久人人爱 | 国产av一区二区三区最新精品 | √天堂中文官网8在线 | 国产精品欧美成人 | 伊在人天堂亚洲香蕉精品区 | 成熟妇人a片免费看网站 | 久久人妻内射无码一区三区 | 最新版天堂资源中文官网 | 午夜无码区在线观看 | 国产午夜亚洲精品不卡下载 | 欧美猛少妇色xxxxx | 久久精品中文字幕一区 | 久久久精品国产sm最大网站 | 国产精品亚洲五月天高清 | 日韩精品成人一区二区三区 | 亚洲欧美中文字幕5发布 | 东京无码熟妇人妻av在线网址 | 亚洲s码欧洲m码国产av | 无码av免费一区二区三区试看 | 67194成是人免费无码 | 纯爱无遮挡h肉动漫在线播放 | 少妇无码吹潮 | 天堂а√在线中文在线 | 午夜性刺激在线视频免费 | 久久午夜夜伦鲁鲁片无码免费 | 强辱丰满人妻hd中文字幕 | 国精品人妻无码一区二区三区蜜柚 | 少女韩国电视剧在线观看完整 | av小次郎收藏 | 日韩精品成人一区二区三区 | 国产后入清纯学生妹 | 国产激情艳情在线看视频 | 久久久国产一区二区三区 | 亚洲精品中文字幕乱码 | 亚洲精品一区三区三区在线观看 | 欧美zoozzooz性欧美 | 国产农村妇女高潮大叫 | 天天拍夜夜添久久精品大 | 久久亚洲中文字幕精品一区 | 国产成人亚洲综合无码 | 欧美阿v高清资源不卡在线播放 | 国产激情精品一区二区三区 | 鲁一鲁av2019在线 | 国产成人亚洲综合无码 | 伊人久久婷婷五月综合97色 | 国产人妖乱国产精品人妖 | 丰满人妻精品国产99aⅴ | 人妻夜夜爽天天爽三区 | 日韩精品无码一本二本三本色 | 小泽玛莉亚一区二区视频在线 | 性欧美疯狂xxxxbbbb | 色欲av亚洲一区无码少妇 | 麻花豆传媒剧国产免费mv在线 | 97无码免费人妻超级碰碰夜夜 | 扒开双腿吃奶呻吟做受视频 | 久久亚洲中文字幕无码 | 亚洲aⅴ无码成人网站国产app | 亚洲s色大片在线观看 | 久在线观看福利视频 | 成 人 免费观看网站 | 无码国产乱人伦偷精品视频 | 欧美大屁股xxxxhd黑色 | 蜜臀av在线播放 久久综合激激的五月天 | 色婷婷综合激情综在线播放 | 图片区 小说区 区 亚洲五月 | 波多野结衣一区二区三区av免费 | 国产麻豆精品一区二区三区v视界 | 精品无人区无码乱码毛片国产 | 小泽玛莉亚一区二区视频在线 | 在线精品亚洲一区二区 | 青青青爽视频在线观看 | 国产人妻人伦精品 | 久久天天躁夜夜躁狠狠 | aⅴ在线视频男人的天堂 | 国产精品毛片一区二区 | 丰满少妇弄高潮了www | 国产人妖乱国产精品人妖 | 欧美日本精品一区二区三区 | 中文字幕色婷婷在线视频 | 无码精品国产va在线观看dvd | 国产精品二区一区二区aⅴ污介绍 | 色爱情人网站 | 亚洲呦女专区 | 欧美zoozzooz性欧美 | 亚洲欧美精品aaaaaa片 | 久久国产精品偷任你爽任你 | 人妻少妇精品久久 | 国产精品嫩草久久久久 | 亚洲熟妇色xxxxx欧美老妇y | 蜜桃av抽搐高潮一区二区 | а天堂中文在线官网 | av无码不卡在线观看免费 | 日本一卡二卡不卡视频查询 | 成人无码精品一区二区三区 | 午夜精品久久久久久久 | 97se亚洲精品一区 | 无码任你躁久久久久久久 | 丰满人妻被黑人猛烈进入 | 丁香啪啪综合成人亚洲 | 成人无码视频在线观看网站 | 亚洲精品久久久久久久久久久 | 亚洲国产精品无码一区二区三区 | 午夜性刺激在线视频免费 | 亚洲国产av美女网站 | 好爽又高潮了毛片免费下载 | 久久成人a毛片免费观看网站 | 国产精品久久久午夜夜伦鲁鲁 | 大肉大捧一进一出好爽视频 | 久久久国产精品无码免费专区 | 成在人线av无码免观看麻豆 | 国产两女互慰高潮视频在线观看 | 国产色视频一区二区三区 | 午夜无码区在线观看 | 国产偷国产偷精品高清尤物 | 亚洲欧洲无卡二区视頻 | 亚洲国产精品成人久久蜜臀 | 日本大乳高潮视频在线观看 | 日本在线高清不卡免费播放 | 久久久久久九九精品久 | 熟妇女人妻丰满少妇中文字幕 | 欧美一区二区三区视频在线观看 | 精品久久久无码人妻字幂 | 九九久久精品国产免费看小说 | 波多野结衣av在线观看 | 国模大胆一区二区三区 | 2019nv天堂香蕉在线观看 | 蜜桃av抽搐高潮一区二区 | 亚洲啪av永久无码精品放毛片 | 国产av无码专区亚洲a∨毛片 | 国产综合色产在线精品 | 国产乱子伦视频在线播放 | 成人性做爰aaa片免费看不忠 | 九九综合va免费看 | 亚洲区小说区激情区图片区 | 国产人成高清在线视频99最全资源 | 国产激情无码一区二区 | 国产高清av在线播放 | 国产精品99爱免费视频 | 成人欧美一区二区三区 | 呦交小u女精品视频 | 一区二区三区高清视频一 | 亚洲午夜久久久影院 | 中文字幕无码av激情不卡 | 成在人线av无码免观看麻豆 | 久在线观看福利视频 | 任你躁国产自任一区二区三区 | 亚洲国产av美女网站 | 亚洲一区二区三区播放 | 久久久久成人片免费观看蜜芽 | 思思久久99热只有频精品66 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 一本大道久久东京热无码av | 欧美野外疯狂做受xxxx高潮 | 久久精品国产日本波多野结衣 | 男女爱爱好爽视频免费看 | 日本成熟视频免费视频 | 在线成人www免费观看视频 | 久久精品国产99久久6动漫 | 国产欧美亚洲精品a | 亚洲熟女一区二区三区 | 性色av无码免费一区二区三区 | аⅴ资源天堂资源库在线 | 任你躁国产自任一区二区三区 | 国产精品人人爽人人做我的可爱 | 99久久精品无码一区二区毛片 | 丰满少妇熟乱xxxxx视频 | 成年美女黄网站色大免费全看 | 国产精品久久久一区二区三区 | 爽爽影院免费观看 | 九九久久精品国产免费看小说 | 丰满少妇熟乱xxxxx视频 | 一二三四社区在线中文视频 | 国产口爆吞精在线视频 | 国产激情综合五月久久 | 5858s亚洲色大成网站www | 国产精品高潮呻吟av久久 | 亚洲天堂2017无码中文 | 波多野结衣aⅴ在线 | 国产精品人人妻人人爽 | 亚洲小说春色综合另类 | 在线精品国产一区二区三区 | 精品厕所偷拍各类美女tp嘘嘘 | 强伦人妻一区二区三区视频18 | 国产成人综合在线女婷五月99播放 | 在线a亚洲视频播放在线观看 | 日日夜夜撸啊撸 | 狠狠噜狠狠狠狠丁香五月 | 国产黄在线观看免费观看不卡 | 亚洲综合无码久久精品综合 | 国产成人无码a区在线观看视频app | 亚洲国产欧美在线成人 | 日本一区二区三区免费高清 | 一二三四社区在线中文视频 | 狠狠亚洲超碰狼人久久 | 亚洲日韩一区二区三区 | 亚洲爆乳无码专区 | 天堂亚洲2017在线观看 | 牛和人交xxxx欧美 | 欧美日韩在线亚洲综合国产人 | 粉嫩少妇内射浓精videos | 国产sm调教视频在线观看 | 给我免费的视频在线观看 | 黑人巨大精品欧美黑寡妇 | 性做久久久久久久久 | 六十路熟妇乱子伦 | 中国大陆精品视频xxxx | av无码电影一区二区三区 | 国产成人精品无码播放 | 强奷人妻日本中文字幕 | 成在人线av无码免观看麻豆 | 奇米影视888欧美在线观看 | 67194成是人免费无码 | 无码一区二区三区在线 | 国产精品久久久久久久影院 | 好男人www社区 | 国产香蕉97碰碰久久人人 | 久久这里只有精品视频9 | 国产激情无码一区二区app | 国产午夜无码精品免费看 | 四虎影视成人永久免费观看视频 | 呦交小u女精品视频 | 色综合久久久久综合一本到桃花网 | 小鲜肉自慰网站xnxx | 黄网在线观看免费网站 | 领导边摸边吃奶边做爽在线观看 | 久久亚洲精品中文字幕无男同 | 国产亚洲人成在线播放 | 中文无码精品a∨在线观看不卡 | 亚洲国产欧美日韩精品一区二区三区 | 丝袜 中出 制服 人妻 美腿 | 国产两女互慰高潮视频在线观看 | 国产香蕉尹人综合在线观看 | 少妇无码av无码专区在线观看 | 午夜男女很黄的视频 | 日产精品高潮呻吟av久久 | 国产精品沙发午睡系列 | 国产欧美精品一区二区三区 | 伊人久久大香线蕉av一区二区 | 色五月五月丁香亚洲综合网 | 99精品久久毛片a片 | 97人妻精品一区二区三区 | 久久精品国产精品国产精品污 | 亚洲 激情 小说 另类 欧美 | 午夜男女很黄的视频 | 影音先锋中文字幕无码 | 亚洲精品国产a久久久久久 | 国产精品久久久久无码av色戒 | 无码毛片视频一区二区本码 | 99久久久国产精品无码免费 | 亚洲精品国产精品乱码视色 | 色综合久久久无码中文字幕 | 宝宝好涨水快流出来免费视频 | 日本熟妇乱子伦xxxx | 欧美zoozzooz性欧美 | 男人的天堂av网站 | 精品亚洲成av人在线观看 | 亚洲小说图区综合在线 | 亚洲成a人片在线观看无码 | 99精品国产综合久久久久五月天 | 男人扒开女人内裤强吻桶进去 | 亚洲 激情 小说 另类 欧美 | 狠狠色丁香久久婷婷综合五月 | 欧美性黑人极品hd | 久青草影院在线观看国产 | 国产成人午夜福利在线播放 | 欧美日韩一区二区综合 | 亚洲国产欧美在线成人 | 特级做a爰片毛片免费69 | 荡女精品导航 | 国产精品毛多多水多 | 亚洲综合伊人久久大杳蕉 | 国产成人综合美国十次 | 成 人 免费观看网站 | 午夜精品一区二区三区的区别 | 清纯唯美经典一区二区 | 久久综合香蕉国产蜜臀av | 中文字幕久久久久人妻 | 国产成人无码午夜视频在线观看 | 77777熟女视频在线观看 а天堂中文在线官网 | 亚洲综合无码久久精品综合 | 最近中文2019字幕第二页 | 2020久久香蕉国产线看观看 | 成熟女人特级毛片www免费 | 日本一卡2卡3卡四卡精品网站 | 色综合久久久久综合一本到桃花网 | 精品欧洲av无码一区二区三区 | 伊人久久大香线焦av综合影院 | 国内揄拍国内精品人妻 | 国产精品二区一区二区aⅴ污介绍 | 红桃av一区二区三区在线无码av | 欧美精品无码一区二区三区 | 亚洲欧美国产精品专区久久 | 日韩av无码中文无码电影 | 婷婷六月久久综合丁香 | 日韩在线不卡免费视频一区 | 久久99精品久久久久久 | 中文字幕乱码人妻无码久久 | 高清国产亚洲精品自在久久 | 99精品无人区乱码1区2区3区 | 中国大陆精品视频xxxx | 玩弄少妇高潮ⅹxxxyw | 亚洲熟妇色xxxxx亚洲 | 欧美国产日韩久久mv | 西西人体www44rt大胆高清 | 丰满少妇女裸体bbw | 亚洲日韩av片在线观看 | 色老头在线一区二区三区 | 国产精品无码久久av | 蜜臀av在线观看 在线欧美精品一区二区三区 | 成人免费视频一区二区 | av小次郎收藏 | 丰满人妻精品国产99aⅴ | 亚洲国产日韩a在线播放 | 日日摸夜夜摸狠狠摸婷婷 | 色偷偷人人澡人人爽人人模 | 久久99精品国产麻豆蜜芽 | 亚洲爆乳精品无码一区二区三区 | 乱人伦中文视频在线观看 | 婷婷丁香五月天综合东京热 | 久久久国产一区二区三区 | 天天躁日日躁狠狠躁免费麻豆 | 内射老妇bbwx0c0ck | 性开放的女人aaa片 | 99麻豆久久久国产精品免费 | 六十路熟妇乱子伦 | 亚洲精品一区二区三区大桥未久 | 亚洲熟妇色xxxxx欧美老妇 | 国产精华av午夜在线观看 | 狂野欧美性猛xxxx乱大交 | 国产电影无码午夜在线播放 | 久久精品国产大片免费观看 | 久久精品国产大片免费观看 | 一区二区三区乱码在线 | 欧洲 | 波多野结衣一区二区三区av免费 | 亚洲一区av无码专区在线观看 | 欧美兽交xxxx×视频 | 国产成人亚洲综合无码 | 麻豆国产丝袜白领秘书在线观看 | 97久久超碰中文字幕 | 天天做天天爱天天爽综合网 | 性做久久久久久久免费看 | 亚洲一区av无码专区在线观看 | 粗大的内捧猛烈进出视频 | 无套内射视频囯产 | 久久无码专区国产精品s | 国产精品久久久久久久9999 | 国产日产欧产精品精品app | 成人精品视频一区二区 | 亚洲欧美精品伊人久久 | 国产电影无码午夜在线播放 | 日韩精品久久久肉伦网站 | 久久国产精品精品国产色婷婷 | 亚拍精品一区二区三区探花 | 丰满人妻一区二区三区免费视频 | 欧美第一黄网免费网站 | 一本久久伊人热热精品中文字幕 | 性生交大片免费看l | 人妻有码中文字幕在线 | 天堂久久天堂av色综合 | 亚洲人成网站免费播放 | 久久精品国产一区二区三区肥胖 | 国产精品鲁鲁鲁 | 国产精品免费大片 | 97夜夜澡人人双人人人喊 | 亚洲精品中文字幕乱码 | 成人精品视频一区二区 | 天天摸天天碰天天添 | 美女黄网站人色视频免费国产 | 国产激情无码一区二区 | 国产人成高清在线视频99最全资源 | 成熟妇人a片免费看网站 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 欧美性猛交内射兽交老熟妇 | 亚洲色在线无码国产精品不卡 | 少妇性俱乐部纵欲狂欢电影 | 一二三四社区在线中文视频 | 亚洲va欧美va天堂v国产综合 | 久久精品成人欧美大片 | 国产真人无遮挡作爱免费视频 | 欧美刺激性大交 | 无遮无挡爽爽免费视频 | 妺妺窝人体色www在线小说 | 高潮毛片无遮挡高清免费 | 欧美精品一区二区精品久久 | 久久人人爽人人人人片 | 欧美激情综合亚洲一二区 | 俺去俺来也在线www色官网 | 亚洲 激情 小说 另类 欧美 | 国产无av码在线观看 | 国产 浪潮av性色四虎 | 高清无码午夜福利视频 | 一区二区三区乱码在线 | 欧洲 | 波多野结衣一区二区三区av免费 | 成人欧美一区二区三区 | 一本加勒比波多野结衣 | 欧美人与禽猛交狂配 | 亚洲男人av天堂午夜在 | 未满小14洗澡无码视频网站 | 国产无遮挡又黄又爽又色 | 久久久久成人片免费观看蜜芽 | 国产亚洲视频中文字幕97精品 | 51国偷自产一区二区三区 | 欧美老妇交乱视频在线观看 | 999久久久国产精品消防器材 | 国产成人精品必看 | 国内精品人妻无码久久久影院 | 麻豆国产人妻欲求不满谁演的 | 色五月五月丁香亚洲综合网 | 人妻插b视频一区二区三区 | 精品欧洲av无码一区二区三区 | 强奷人妻日本中文字幕 | 国产精品福利视频导航 | 国产后入清纯学生妹 | 无码精品国产va在线观看dvd | 青草青草久热国产精品 | 亚洲一区av无码专区在线观看 | 99久久精品日本一区二区免费 | 亚洲va中文字幕无码久久不卡 | 人人妻人人澡人人爽精品欧美 | 亚洲s色大片在线观看 | 久久精品人人做人人综合试看 | 在线精品亚洲一区二区 | 色一情一乱一伦一区二区三欧美 | 一区二区三区乱码在线 | 欧洲 | 亲嘴扒胸摸屁股激烈网站 | 久久天天躁狠狠躁夜夜免费观看 | 日本一卡二卡不卡视频查询 | 亚洲欧美日韩成人高清在线一区 | 国产午夜手机精彩视频 | 午夜性刺激在线视频免费 | 人人爽人人爽人人片av亚洲 | 妺妺窝人体色www婷婷 | 国产亚洲精品久久久久久国模美 | 俄罗斯老熟妇色xxxx | 国产精品久久久久久亚洲毛片 | 国产精品久久久久久亚洲影视内衣 | 无套内谢的新婚少妇国语播放 | 国产一精品一av一免费 | 国产日产欧产精品精品app | 又紧又大又爽精品一区二区 | 男女作爱免费网站 | 亚洲日韩乱码中文无码蜜桃臀网站 | 美女极度色诱视频国产 | 又大又硬又爽免费视频 | 无码毛片视频一区二区本码 | 97久久国产亚洲精品超碰热 | 亚洲另类伦春色综合小说 | 日日麻批免费40分钟无码 | 在线观看欧美一区二区三区 | 国产成人综合色在线观看网站 | 少妇性l交大片欧洲热妇乱xxx | 欧美精品国产综合久久 | 亚洲の无码国产の无码影院 | av在线亚洲欧洲日产一区二区 | 亚洲国产精华液网站w | 熟妇激情内射com | 亚洲色欲色欲欲www在线 | 精品国产av色一区二区深夜久久 | 嫩b人妻精品一区二区三区 | 精品少妇爆乳无码av无码专区 | 噜噜噜亚洲色成人网站 | 久久 国产 尿 小便 嘘嘘 | 97夜夜澡人人双人人人喊 | 色偷偷人人澡人人爽人人模 | 在线播放亚洲第一字幕 | 精品厕所偷拍各类美女tp嘘嘘 | 领导边摸边吃奶边做爽在线观看 | 内射老妇bbwx0c0ck | 色欲久久久天天天综合网精品 | 国产在线一区二区三区四区五区 | 大乳丰满人妻中文字幕日本 | 中文字幕无码免费久久9一区9 | 丰满肥臀大屁股熟妇激情视频 | 亚洲精品一区二区三区在线 | 国产又粗又硬又大爽黄老大爷视 | 亚洲国产成人av在线观看 | 精品熟女少妇av免费观看 | 亚洲国产精品一区二区美利坚 | 久久精品国产一区二区三区肥胖 | 国产亚洲视频中文字幕97精品 | 老司机亚洲精品影院无码 | 天堂а√在线地址中文在线 | 一本久道久久综合婷婷五月 | 图片区 小说区 区 亚洲五月 | 永久免费观看美女裸体的网站 | 久久综合给久久狠狠97色 | 国产亚洲精品久久久久久久久动漫 | 日本爽爽爽爽爽爽在线观看免 | 亚无码乱人伦一区二区 | 国产精品久久久午夜夜伦鲁鲁 | 日韩无套无码精品 | 国产亚洲精品久久久久久 | 亚洲无人区午夜福利码高清完整版 | 欧美日韩一区二区三区自拍 | 午夜福利试看120秒体验区 | 国产精品久久久午夜夜伦鲁鲁 | 日日天日日夜日日摸 | 日日天干夜夜狠狠爱 | 国产成人一区二区三区别 | 日欧一片内射va在线影院 | 国产97在线 | 亚洲 | 无码人妻少妇伦在线电影 | 又黄又爽又色的视频 | 1000部夫妻午夜免费 | 夜夜夜高潮夜夜爽夜夜爰爰 | 亚洲一区av无码专区在线观看 | 国产精品无码久久av | 5858s亚洲色大成网站www | 一本大道伊人av久久综合 | 色 综合 欧美 亚洲 国产 | 国产黄在线观看免费观看不卡 | 国产免费无码一区二区视频 | 日本一卡二卡不卡视频查询 | 黄网在线观看免费网站 | 亚洲国产欧美日韩精品一区二区三区 | 亚洲午夜福利在线观看 | 大乳丰满人妻中文字幕日本 | 久久精品丝袜高跟鞋 | 无码国产色欲xxxxx视频 | 国产精品毛多多水多 | 人妻少妇精品视频专区 | 未满小14洗澡无码视频网站 | 欧美日韩一区二区免费视频 | 亚洲精品国产a久久久久久 | 国产av久久久久精东av | 中文字幕色婷婷在线视频 | 俄罗斯老熟妇色xxxx | aⅴ亚洲 日韩 色 图网站 播放 | 性史性农村dvd毛片 | 4hu四虎永久在线观看 | 午夜福利一区二区三区在线观看 | 亚洲欧美日韩综合久久久 | 超碰97人人射妻 | 人妻少妇精品无码专区二区 | 国产xxx69麻豆国语对白 | 少妇久久久久久人妻无码 | 国产免费无码一区二区视频 | 玩弄少妇高潮ⅹxxxyw | 网友自拍区视频精品 | 国产亚洲欧美日韩亚洲中文色 | 亚洲一区二区三区无码久久 | 小泽玛莉亚一区二区视频在线 | 精品国产一区二区三区av 性色 | 黑森林福利视频导航 | 亚洲の无码国产の无码影院 | 在线观看免费人成视频 | 亚洲欧美精品aaaaaa片 | 扒开双腿疯狂进出爽爽爽视频 | 丝袜足控一区二区三区 | 国产香蕉尹人综合在线观看 | 精品无码成人片一区二区98 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 久久人妻内射无码一区三区 | 亚洲国产精华液网站w | 免费人成网站视频在线观看 | 中国女人内谢69xxxx | 亚洲自偷自拍另类第1页 | 青草视频在线播放 | 精品一区二区三区无码免费视频 | 伊在人天堂亚洲香蕉精品区 | 爱做久久久久久 | 亚洲aⅴ无码成人网站国产app | 国产凸凹视频一区二区 | 国产精品高潮呻吟av久久4虎 | 天天爽夜夜爽夜夜爽 | 欧美怡红院免费全部视频 | 色综合久久网 | 亚无码乱人伦一区二区 | 精品偷自拍另类在线观看 | 蜜桃臀无码内射一区二区三区 | 少妇无套内谢久久久久 | 亚洲爆乳无码专区 | 久久久久久av无码免费看大片 | 中国女人内谢69xxxxxa片 | 中文无码成人免费视频在线观看 | 欧美野外疯狂做受xxxx高潮 | 欧美熟妇另类久久久久久不卡 | 亚洲成av人片天堂网无码】 | 国产成人无码av片在线观看不卡 | 午夜福利试看120秒体验区 | 巨爆乳无码视频在线观看 | 人人妻人人澡人人爽精品欧美 | 久久久亚洲欧洲日产国码αv | 一本久道高清无码视频 | 中文字幕 人妻熟女 | 久久综合九色综合97网 | 狠狠亚洲超碰狼人久久 | 精品国产青草久久久久福利 | 免费人成在线视频无码 | 亚洲一区二区三区含羞草 | 婷婷六月久久综合丁香 | 国产精品成人av在线观看 | 99视频精品全部免费免费观看 | 人人爽人人澡人人人妻 | 国产亚洲视频中文字幕97精品 | 国产精品亚洲а∨无码播放麻豆 | 99精品无人区乱码1区2区3区 | 国产精品.xx视频.xxtv | a片在线免费观看 | 天天摸天天碰天天添 | 国精产品一区二区三区 | 国产成人精品优优av | 国产午夜无码视频在线观看 | 我要看www免费看插插视频 | 对白脏话肉麻粗话av | 日韩视频 中文字幕 视频一区 | 又色又爽又黄的美女裸体网站 | 狠狠噜狠狠狠狠丁香五月 | 亚洲成av人在线观看网址 | 亚洲国产成人av在线观看 | 国产精品美女久久久 | 成人三级无码视频在线观看 | 粗大的内捧猛烈进出视频 | 亚洲日本va中文字幕 | 国产无遮挡又黄又爽免费视频 | 国产精品多人p群无码 | 永久免费精品精品永久-夜色 | 久久综合给久久狠狠97色 | 露脸叫床粗话东北少妇 | 亚洲人交乣女bbw | а√资源新版在线天堂 | 极品嫩模高潮叫床 | 国产亚洲精品久久久闺蜜 | 日日碰狠狠躁久久躁蜜桃 | 成人免费无码大片a毛片 | 亚洲国精产品一二二线 | 最新国产麻豆aⅴ精品无码 | 18禁黄网站男男禁片免费观看 | 亚洲午夜久久久影院 | 国产精品久久久久无码av色戒 | 日日摸日日碰夜夜爽av | 色偷偷人人澡人人爽人人模 | 美女毛片一区二区三区四区 | 久久久久成人精品免费播放动漫 | 国产精品久久久av久久久 | 国产卡一卡二卡三 | 国产真人无遮挡作爱免费视频 | 丝袜人妻一区二区三区 | 98国产精品综合一区二区三区 | 性生交大片免费看女人按摩摩 | 欧美阿v高清资源不卡在线播放 | 日本肉体xxxx裸交 | 又大又黄又粗又爽的免费视频 | 成人无码精品一区二区三区 | 精品乱码久久久久久久 | 亚洲中文字幕av在天堂 | 成人无码精品1区2区3区免费看 | 国语精品一区二区三区 | 国产色精品久久人妻 | 在线欧美精品一区二区三区 | 少妇人妻av毛片在线看 | 国产精品永久免费视频 | 国产av久久久久精东av | 日本精品久久久久中文字幕 | 98国产精品综合一区二区三区 | 免费无码午夜福利片69 | 久久久久成人精品免费播放动漫 | 强伦人妻一区二区三区视频18 | 一本色道婷婷久久欧美 | 一二三四在线观看免费视频 | 国内精品久久久久久中文字幕 | 色综合久久久久综合一本到桃花网 | 精品久久久中文字幕人妻 | 亚洲欧美日韩成人高清在线一区 | 国产精品人人妻人人爽 | 18无码粉嫩小泬无套在线观看 | 亚洲日韩一区二区三区 | 久久久久久久久蜜桃 | 国产精品久久久久久久9999 | 亚洲精品中文字幕 | 麻豆精品国产精华精华液好用吗 | 亚洲精品午夜无码电影网 | 老子影院午夜伦不卡 | 精品久久久中文字幕人妻 | 国产偷抇久久精品a片69 | 中国女人内谢69xxxx | 国产精品爱久久久久久久 | 国产av人人夜夜澡人人爽麻豆 | 免费视频欧美无人区码 | 中文字幕无码av波多野吉衣 | 亚洲日韩精品欧美一区二区 | 无码午夜成人1000部免费视频 | 97人妻精品一区二区三区 | 亚洲欧美中文字幕5发布 | 中国女人内谢69xxxxxa片 | 女人被男人躁得好爽免费视频 | 蜜桃av抽搐高潮一区二区 | 大地资源网第二页免费观看 | 国产香蕉尹人视频在线 | 荫蒂添的好舒服视频囗交 | 色老头在线一区二区三区 | 最近中文2019字幕第二页 | 女人被男人躁得好爽免费视频 | 亚洲の无码国产の无码影院 | 又紧又大又爽精品一区二区 | 狠狠色噜噜狠狠狠狠7777米奇 | 76少妇精品导航 | 欧美精品国产综合久久 | 日韩人妻少妇一区二区三区 | a国产一区二区免费入口 | 日韩av激情在线观看 | 亚洲综合久久一区二区 | 人人爽人人爽人人片av亚洲 | 久久精品女人的天堂av | 亚洲精品久久久久avwww潮水 | 青春草在线视频免费观看 | 国产极品美女高潮无套在线观看 | 天天拍夜夜添久久精品大 | 欧美黑人巨大xxxxx | 男女性色大片免费网站 | 少妇性l交大片欧洲热妇乱xxx | 国色天香社区在线视频 | 牲欲强的熟妇农村老妇女 | 国产精品美女久久久久av爽李琼 | 亚洲а∨天堂久久精品2021 | 动漫av一区二区在线观看 | 免费无码的av片在线观看 | av无码电影一区二区三区 | 国产精品igao视频网 | 99视频精品全部免费免费观看 | 未满成年国产在线观看 | 激情亚洲一区国产精品 | 1000部啪啪未满十八勿入下载 | 天天拍夜夜添久久精品大 | 日韩无套无码精品 | 国产精品亚洲一区二区三区喷水 | 丝袜人妻一区二区三区 | 丰满护士巨好爽好大乳 | 极品嫩模高潮叫床 | 97精品国产97久久久久久免费 | 无码免费一区二区三区 | 日韩人妻无码一区二区三区久久99 | 乌克兰少妇性做爰 | 欧美激情内射喷水高潮 | 无码播放一区二区三区 | 牲欲强的熟妇农村老妇女视频 | 蜜桃视频插满18在线观看 | 国语自产偷拍精品视频偷 | 色 综合 欧美 亚洲 国产 | 欧美亚洲日韩国产人成在线播放 | 欧美熟妇另类久久久久久不卡 | 激情爆乳一区二区三区 | 亚洲国产av精品一区二区蜜芽 | 国产69精品久久久久app下载 | 国产在线aaa片一区二区99 | 午夜丰满少妇性开放视频 | 国产精品人妻一区二区三区四 | 亚洲欧洲中文日韩av乱码 | 成年美女黄网站色大免费视频 | 99久久久无码国产aaa精品 | 人人爽人人澡人人人妻 | 久久99精品久久久久久动态图 | 中文无码精品a∨在线观看不卡 | 久久成人a毛片免费观看网站 | 久久午夜无码鲁丝片 | 久久久久久久久888 | 中文无码伦av中文字幕 | 女人被爽到呻吟gif动态图视看 | 老熟妇乱子伦牲交视频 | 亚洲乱码中文字幕在线 | 天堂一区人妻无码 | 人妻无码αv中文字幕久久琪琪布 | 亚洲大尺度无码无码专区 | 免费男性肉肉影院 | 久久无码中文字幕免费影院蜜桃 | 99riav国产精品视频 | 国产成人精品久久亚洲高清不卡 | 色综合久久网 | 久久五月精品中文字幕 | 少妇人妻av毛片在线看 | 欧美国产日产一区二区 | 国产成人精品三级麻豆 | 久久国产精品_国产精品 | 天天综合网天天综合色 | 久久99精品国产麻豆 | 久久久久成人精品免费播放动漫 | 爆乳一区二区三区无码 | 无码av免费一区二区三区试看 | 3d动漫精品啪啪一区二区中 | 精品久久综合1区2区3区激情 | 亚洲精品中文字幕乱码 | 无码人妻出轨黑人中文字幕 | 麻豆精品国产精华精华液好用吗 | 99久久久无码国产精品免费 | 乱人伦人妻中文字幕无码久久网 | 久久亚洲中文字幕无码 | 日日摸日日碰夜夜爽av | 亚洲а∨天堂久久精品2021 | 亚洲gv猛男gv无码男同 | 午夜福利试看120秒体验区 | 无码av最新清无码专区吞精 | 激情亚洲一区国产精品 | 国产麻豆精品一区二区三区v视界 | 99视频精品全部免费免费观看 | 欧美成人午夜精品久久久 | 人妻插b视频一区二区三区 | 国产精品va在线观看无码 | 国产女主播喷水视频在线观看 | 一二三四在线观看免费视频 | 美女黄网站人色视频免费国产 | 扒开双腿吃奶呻吟做受视频 | 欧美一区二区三区 | 国产精品免费大片 | 人人妻人人澡人人爽人人精品 | 久久精品女人的天堂av | 一区二区三区乱码在线 | 欧洲 | 亚洲区欧美区综合区自拍区 | 日日干夜夜干 | 丰满肥臀大屁股熟妇激情视频 | 亚洲中文字幕成人无码 | 98国产精品综合一区二区三区 | 少妇无码吹潮 | 亚洲日韩一区二区三区 | 日韩精品无码一区二区中文字幕 | 青草青草久热国产精品 | 巨爆乳无码视频在线观看 | 久久久久成人片免费观看蜜芽 | 亚洲欧洲无卡二区视頻 | 一本色道久久综合狠狠躁 | 精品久久久久久亚洲精品 | 免费无码av一区二区 | 日欧一片内射va在线影院 | 天堂在线观看www | 国产乱人伦偷精品视频 | 国产色xx群视频射精 | 熟女少妇人妻中文字幕 | 乱人伦人妻中文字幕无码 | 正在播放老肥熟妇露脸 | 永久免费精品精品永久-夜色 | 亚洲国产欧美在线成人 | 国产做国产爱免费视频 | 久久国产精品二国产精品 | 精品水蜜桃久久久久久久 | 97se亚洲精品一区 | 狠狠色色综合网站 | 亚洲一区二区三区香蕉 | 欧美三级a做爰在线观看 | 中文无码伦av中文字幕 | 人人爽人人澡人人高潮 | 亚洲の无码国产の无码影院 | 亚洲高清偷拍一区二区三区 | 亚洲熟妇色xxxxx亚洲 | 国产成人精品必看 | 人妻少妇精品无码专区动漫 | 强开小婷嫩苞又嫩又紧视频 | 精品成在人线av无码免费看 | 亚洲成av人综合在线观看 | 乌克兰少妇xxxx做受 | 内射白嫩少妇超碰 | 鲁鲁鲁爽爽爽在线视频观看 | 超碰97人人射妻 | 免费无码的av片在线观看 | 两性色午夜免费视频 | 久久午夜无码鲁丝片午夜精品 | 国产精品亚洲lv粉色 | 久久天天躁狠狠躁夜夜免费观看 | 国产日产欧产精品精品app | 亚洲日本一区二区三区在线 | 天干天干啦夜天干天2017 | 亚洲中文字幕va福利 | 久久国产劲爆∧v内射 | 成熟妇人a片免费看网站 | 亚洲精品综合一区二区三区在线 | 精品成人av一区二区三区 | 天堂一区人妻无码 | 亚洲精品综合五月久久小说 | 久久国产自偷自偷免费一区调 | 婷婷色婷婷开心五月四房播播 | 国产情侣作爱视频免费观看 | 成年美女黄网站色大免费视频 | 好屌草这里只有精品 | 国产精品va在线播放 | 久久精品无码一区二区三区 | 人妻插b视频一区二区三区 | 中国女人内谢69xxxxxa片 | 亚洲日韩中文字幕在线播放 | 婷婷五月综合缴情在线视频 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 在线成人www免费观看视频 | 欧美激情一区二区三区成人 | 嫩b人妻精品一区二区三区 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 国产综合色产在线精品 | 粗大的内捧猛烈进出视频 | 领导边摸边吃奶边做爽在线观看 | av无码电影一区二区三区 | 日韩精品无码免费一区二区三区 | а√天堂www在线天堂小说 | 澳门永久av免费网站 | 国产又爽又黄又刺激的视频 | 无码人妻精品一区二区三区下载 | 精品国产青草久久久久福利 | 中文字幕无码日韩专区 | 成 人 网 站国产免费观看 | a国产一区二区免费入口 | 欧美人与物videos另类 | 色狠狠av一区二区三区 | 丰满护士巨好爽好大乳 | 99久久精品日本一区二区免费 | 久久午夜无码鲁丝片 | 亚洲人亚洲人成电影网站色 | 鲁鲁鲁爽爽爽在线视频观看 | 色综合久久久无码网中文 | 久9re热视频这里只有精品 | 亚洲精品欧美二区三区中文字幕 | 老头边吃奶边弄进去呻吟 | 国产精品久久久一区二区三区 | 狂野欧美性猛xxxx乱大交 | 国产高清不卡无码视频 | 一区二区三区乱码在线 | 欧洲 | 国产亚洲精品久久久久久 | 在线а√天堂中文官网 | 狠狠噜狠狠狠狠丁香五月 | 熟妇激情内射com | 国产成人av免费观看 | 国产av一区二区精品久久凹凸 | 一本久道久久综合狠狠爱 | √天堂中文官网8在线 | 99久久人妻精品免费二区 | 人人爽人人澡人人高潮 | 久久久国产一区二区三区 | 亚洲男人av香蕉爽爽爽爽 | 国产成人av免费观看 | 久久亚洲精品中文字幕无男同 | 99riav国产精品视频 | 日韩人妻无码中文字幕视频 | 久久久久se色偷偷亚洲精品av | 欧美成人免费全部网站 | 老子影院午夜伦不卡 | 国模大胆一区二区三区 | 丰满岳乱妇在线观看中字无码 | 少女韩国电视剧在线观看完整 | 中文字幕乱妇无码av在线 | 欧美日韩视频无码一区二区三 | 国产香蕉尹人综合在线观看 | 国产成人精品一区二区在线小狼 | 熟女俱乐部五十路六十路av | 国产成人一区二区三区别 | 欧美freesex黑人又粗又大 | 国产无遮挡又黄又爽又色 | 亚洲狠狠色丁香婷婷综合 | 国产精品va在线观看无码 | 精品久久8x国产免费观看 | 亚洲日韩乱码中文无码蜜桃臀网站 | 日产国产精品亚洲系列 | 成人精品视频一区二区 | 综合人妻久久一区二区精品 | 欧美成人免费全部网站 | 超碰97人人射妻 | 88国产精品欧美一区二区三区 | 美女极度色诱视频国产 | 亚洲一区二区三区偷拍女厕 | 色婷婷av一区二区三区之红樱桃 | 狠狠色丁香久久婷婷综合五月 | 久久久久99精品成人片 | 高中生自慰www网站 | 人妻少妇被猛烈进入中文字幕 | 日韩精品乱码av一区二区 | 精品欧洲av无码一区二区三区 | 一个人免费观看的www视频 | 人人爽人人澡人人人妻 | 欧美刺激性大交 | av无码久久久久不卡免费网站 | 一个人看的视频www在线 | 亚洲日本va中文字幕 | 97精品人妻一区二区三区香蕉 | 少妇太爽了在线观看 | 日本乱偷人妻中文字幕 | 国产成人综合美国十次 | av人摸人人人澡人人超碰下载 | 少妇性l交大片欧洲热妇乱xxx | 久久综合九色综合97网 | 国产小呦泬泬99精品 | 色欲久久久天天天综合网精品 | 成 人影片 免费观看 | 欧美日韩一区二区免费视频 | 蜜臀aⅴ国产精品久久久国产老师 | 久久综合色之久久综合 | 国产超级va在线观看视频 | 未满小14洗澡无码视频网站 | 一个人看的www免费视频在线观看 | 性生交大片免费看女人按摩摩 | 亚洲国产一区二区三区在线观看 | 亚洲乱码国产乱码精品精 | 日本精品高清一区二区 | 国内丰满熟女出轨videos | 少妇厨房愉情理9仑片视频 | 久久久久久久人妻无码中文字幕爆 | 国产小呦泬泬99精品 | 国产农村乱对白刺激视频 | 少女韩国电视剧在线观看完整 | 无码国产乱人伦偷精品视频 | 国产精品福利视频导航 | 131美女爱做视频 | 激情内射日本一区二区三区 | 色综合久久网 | 亚洲欧美日韩成人高清在线一区 | 鲁一鲁av2019在线 | 久久久久久a亚洲欧洲av冫 | 国产精品永久免费视频 | 在线亚洲高清揄拍自拍一品区 | 高清无码午夜福利视频 | 在线 国产 欧美 亚洲 天堂 | 装睡被陌生人摸出水好爽 | 少妇久久久久久人妻无码 | 亚洲精品一区三区三区在线观看 | 帮老师解开蕾丝奶罩吸乳网站 | 大屁股大乳丰满人妻 | 亚洲熟妇色xxxxx欧美老妇y | 国产精品久久久久久久9999 | 色妞www精品免费视频 | 精品无码国产一区二区三区av | 久久亚洲精品成人无码 | 国产成人综合美国十次 | 国产又爽又黄又刺激的视频 | 国产性生大片免费观看性 | 日韩av激情在线观看 | www成人国产高清内射 | 少妇人妻偷人精品无码视频 | 色窝窝无码一区二区三区色欲 | 亚洲自偷自偷在线制服 | 丰满肥臀大屁股熟妇激情视频 | 国产精品高潮呻吟av久久4虎 | 精品一区二区不卡无码av | 乱人伦中文视频在线观看 | 人人澡人人妻人人爽人人蜜桃 | 亚洲色大成网站www | 午夜熟女插插xx免费视频 | 国产欧美熟妇另类久久久 | 精品少妇爆乳无码av无码专区 | www国产精品内射老师 | 永久免费观看美女裸体的网站 | 亚洲日本va午夜在线电影 | 国产精品久久久久久久9999 | 国语精品一区二区三区 | 国产成人综合色在线观看网站 | 久久亚洲国产成人精品性色 | 亚洲国产精品一区二区美利坚 | 亚洲国产日韩a在线播放 | 性欧美牲交xxxxx视频 | 久久午夜无码鲁丝片秋霞 | 99久久精品无码一区二区毛片 | 纯爱无遮挡h肉动漫在线播放 | 日本一区二区三区免费高清 | 午夜肉伦伦影院 | 日韩av激情在线观看 | 性色欲网站人妻丰满中文久久不卡 | 亚洲日本va午夜在线电影 | 国产成人无码区免费内射一片色欲 | 久久无码中文字幕免费影院蜜桃 | 国产 精品 自在自线 | 老熟女重囗味hdxx69 | 久久人人爽人人人人片 | 日韩无套无码精品 | www国产亚洲精品久久网站 | 色欲综合久久中文字幕网 | 香港三级日本三级妇三级 | 在线 国产 欧美 亚洲 天堂 | 少妇太爽了在线观看 | 无套内谢老熟女 | 一区二区三区高清视频一 | 黑人巨大精品欧美黑寡妇 | 无码国产激情在线观看 | 亚洲男女内射在线播放 | 国产精品亚洲lv粉色 | 国产精品福利视频导航 | 国产亚洲精品久久久久久国模美 | 亚洲色成人中文字幕网站 | aa片在线观看视频在线播放 | 亚洲人成无码网www | 国产精品亚洲综合色区韩国 | 成人一区二区免费视频 | 老头边吃奶边弄进去呻吟 | 国产精品福利视频导航 | 免费国产成人高清在线观看网站 | 亚洲春色在线视频 | 精品一区二区不卡无码av | 蜜桃视频韩日免费播放 | 水蜜桃av无码 | 日韩欧美成人免费观看 | 日本又色又爽又黄的a片18禁 | 最近的中文字幕在线看视频 | 日本欧美一区二区三区乱码 | 我要看www免费看插插视频 | 中文字幕av无码一区二区三区电影 | 亚洲精品一区国产 | 中文字幕色婷婷在线视频 | 精品成人av一区二区三区 | 午夜性刺激在线视频免费 | 女人被爽到呻吟gif动态图视看 | 最新版天堂资源中文官网 | 欧美亚洲国产一区二区三区 | 黄网在线观看免费网站 | 国产精品久久久久久亚洲毛片 | 国产精品99爱免费视频 | 巨爆乳无码视频在线观看 | 性色av无码免费一区二区三区 | 精品久久综合1区2区3区激情 | 成人免费视频在线观看 | 色婷婷综合激情综在线播放 | 初尝人妻少妇中文字幕 | 99精品国产综合久久久久五月天 | 两性色午夜视频免费播放 | 国产精品亚洲专区无码不卡 | 成人精品视频一区二区三区尤物 | 对白脏话肉麻粗话av | 丰满少妇熟乱xxxxx视频 | 欧美性生交xxxxx久久久 | 俺去俺来也www色官网 | 99精品久久毛片a片 | 性欧美牲交xxxxx视频 | 国产亚洲精品精品国产亚洲综合 | 亚洲爆乳大丰满无码专区 | 国产精品无码一区二区桃花视频 | 婷婷色婷婷开心五月四房播播 | 狠狠色欧美亚洲狠狠色www | 三级4级全黄60分钟 | 精品国产精品久久一区免费式 | 国产又爽又黄又刺激的视频 | 免费国产成人高清在线观看网站 | 国产av一区二区三区最新精品 | 狂野欧美激情性xxxx | 欧美丰满老熟妇xxxxx性 | 性欧美牲交在线视频 | 国产精品久久国产三级国 | 日本精品少妇一区二区三区 | 无码av岛国片在线播放 | 最近的中文字幕在线看视频 | 久久午夜夜伦鲁鲁片无码免费 | 51国偷自产一区二区三区 | 亚洲综合在线一区二区三区 | 亚洲日韩av一区二区三区四区 | 色诱久久久久综合网ywww | 国产精品久久国产精品99 | 精品少妇爆乳无码av无码专区 | 久久成人a毛片免费观看网站 | 亚洲另类伦春色综合小说 | a片免费视频在线观看 | 少妇被黑人到高潮喷出白浆 | 国产午夜精品一区二区三区嫩草 | 国产精品99爱免费视频 | 国产午夜福利100集发布 | 精品久久综合1区2区3区激情 | 亚洲精品国产第一综合99久久 | 高潮喷水的毛片 | 亚洲综合无码久久精品综合 | 性欧美大战久久久久久久 | 一本久道高清无码视频 | 国产福利视频一区二区 | 久久99精品久久久久婷婷 | 波多野结衣av一区二区全免费观看 | 全球成人中文在线 | 日本一区二区更新不卡 | 久久婷婷五月综合色国产香蕉 | 亚洲狠狠婷婷综合久久 | 荫蒂被男人添的好舒服爽免费视频 | 国产在线aaa片一区二区99 | 国产网红无码精品视频 | 蜜桃视频插满18在线观看 | 免费人成在线视频无码 | 亚洲成a人片在线观看无码3d | 少妇高潮喷潮久久久影院 | 亚洲狠狠色丁香婷婷综合 | 正在播放老肥熟妇露脸 | 色一情一乱一伦一视频免费看 | 国产精品理论片在线观看 | 九月婷婷人人澡人人添人人爽 | 又大又黄又粗又爽的免费视频 | 欧美精品国产综合久久 | 成人性做爰aaa片免费看不忠 | 六月丁香婷婷色狠狠久久 | 又大又硬又黄的免费视频 | 夜夜高潮次次欢爽av女 | 国产内射爽爽大片视频社区在线 | 欧美人与物videos另类 | 任你躁国产自任一区二区三区 | 97夜夜澡人人爽人人喊中国片 | 麻豆国产人妻欲求不满谁演的 | 5858s亚洲色大成网站www | 大乳丰满人妻中文字幕日本 | 中文字幕无码av激情不卡 | 理论片87福利理论电影 | 狠狠色噜噜狠狠狠狠7777米奇 | 四虎国产精品一区二区 | 窝窝午夜理论片影院 | 无码人妻久久一区二区三区不卡 | 无码av最新清无码专区吞精 | 国产精品99久久精品爆乳 | 国产乱人无码伦av在线a | 国产又爽又猛又粗的视频a片 | 国精产品一品二品国精品69xx | 国产尤物精品视频 | 玩弄人妻少妇500系列视频 | 亚洲成色在线综合网站 | 免费国产成人高清在线观看网站 | 少妇性荡欲午夜性开放视频剧场 | 午夜精品久久久久久久 | 欧洲美熟女乱又伦 | 中文字幕无码热在线视频 | 波多野结衣aⅴ在线 | 亚洲国产精品美女久久久久 | 激情五月综合色婷婷一区二区 | 亚洲精品一区二区三区在线观看 | 99久久久国产精品无码免费 | 成 人 免费观看网站 | 国产人妻精品一区二区三区不卡 | 精品国产一区二区三区av 性色 | 中文字幕无码日韩欧毛 | 亚洲性无码av中文字幕 | 亚洲日本va午夜在线电影 | 两性色午夜视频免费播放 | 人妻夜夜爽天天爽三区 | 国产精品福利视频导航 | 中文字幕人妻无码一夲道 | 精品久久久中文字幕人妻 | 九月婷婷人人澡人人添人人爽 | 亚洲人成网站色7799 | 成人亚洲精品久久久久 | 18禁止看的免费污网站 | 欧美性生交xxxxx久久久 | 亚洲国产av精品一区二区蜜芽 | 一本久久a久久精品vr综合 | 少妇无码av无码专区在线观看 | 色综合久久久无码中文字幕 | 久久国产精品_国产精品 | 99国产精品白浆在线观看免费 | 精品偷自拍另类在线观看 | 国产成人综合在线女婷五月99播放 | 中文字幕无码热在线视频 | 无遮挡啪啪摇乳动态图 | 亚洲天堂2017无码 | 国产成人精品视频ⅴa片软件竹菊 | 最近中文2019字幕第二页 | 国产精品永久免费视频 | 日本爽爽爽爽爽爽在线观看免 | 99在线 | 亚洲 | 好男人www社区 | 丁香啪啪综合成人亚洲 | 国产在线一区二区三区四区五区 | 日本一区二区更新不卡 | 最新国产麻豆aⅴ精品无码 | 日本免费一区二区三区最新 | a片在线免费观看 | 日日鲁鲁鲁夜夜爽爽狠狠 | 露脸叫床粗话东北少妇 | 永久免费精品精品永久-夜色 | 亚洲欧美精品aaaaaa片 | 国产精品丝袜黑色高跟鞋 | 乱码午夜-极国产极内射 | 日韩少妇白浆无码系列 | 我要看www免费看插插视频 | 久久精品女人天堂av免费观看 | 一本大道久久东京热无码av | 极品嫩模高潮叫床 | 青青青爽视频在线观看 | 亚洲日本在线电影 | 国产精品爱久久久久久久 | 少妇性l交大片欧洲热妇乱xxx | 久久综合香蕉国产蜜臀av | 蜜桃视频韩日免费播放 | 沈阳熟女露脸对白视频 | 无码人妻丰满熟妇区五十路百度 | 装睡被陌生人摸出水好爽 | 欧美真人作爱免费视频 | 精品国产国产综合精品 | 国产精品亚洲专区无码不卡 | 波多野结衣高清一区二区三区 | 亚洲欧洲无卡二区视頻 | 精品夜夜澡人妻无码av蜜桃 | 国产高清不卡无码视频 | 国产成人午夜福利在线播放 | 色偷偷人人澡人人爽人人模 | 国产精品va在线播放 | 伊在人天堂亚洲香蕉精品区 | 久久久久亚洲精品男人的天堂 | 高潮毛片无遮挡高清免费视频 | 一区二区三区高清视频一 | 综合激情五月综合激情五月激情1 | 天天躁夜夜躁狠狠是什么心态 | 未满小14洗澡无码视频网站 | 粉嫩少妇内射浓精videos | 色综合久久久无码网中文 | 天天拍夜夜添久久精品大 | 大胆欧美熟妇xx | 欧美自拍另类欧美综合图片区 | 欧美国产日产一区二区 | 国产亚洲精品久久久久久国模美 | 日产国产精品亚洲系列 | 精品欧洲av无码一区二区三区 | 国内精品一区二区三区不卡 | 国产午夜福利100集发布 | 亚洲va中文字幕无码久久不卡 | 亚洲经典千人经典日产 | 国内精品人妻无码久久久影院蜜桃 | 亚洲欧洲无卡二区视頻 | 国产亚洲美女精品久久久2020 | 国产精品.xx视频.xxtv | 丰满人妻翻云覆雨呻吟视频 | 亚洲狠狠色丁香婷婷综合 | 婷婷六月久久综合丁香 | 麻豆果冻传媒2021精品传媒一区下载 | 亚洲毛片av日韩av无码 | 激情内射日本一区二区三区 | 精品无码国产自产拍在线观看蜜 | 又大又紧又粉嫩18p少妇 | 亚洲精品国偷拍自产在线观看蜜桃 | 强开小婷嫩苞又嫩又紧视频 | 领导边摸边吃奶边做爽在线观看 | 麻豆md0077饥渴少妇 |