<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 完整的 Java Servlet 教程 > 原文: [https://howtodoinjava.com/servlets/complete-java-servlets-tutorial/](https://howtodoinjava.com/servlets/complete-java-servlets-tutorial/) Servlet 是符合 Java Servlet API 的 Java 類,該 Java Servlet API 允許 Java 類響應請求。 盡管 Servlet 可以響應任何類型的請求,但最常見的是將其編寫為響應基于 Web 的請求。 必須將 servlet 部署到 Java servlet 容器中才能使用。 盡管許多開發人員都使用諸如 [**Java Server Pages(JSP)**](https://en.wikipedia.org/wiki/JavaServer_Pages "jsp")和 [**Java Server Faces(JSF)**](https://en.wikipedia.org/wiki/JavaServer_Faces "jsf")之類的 servlet 框架,但這兩種技術通過 servlet 容器將頁面編譯為后臺的 Java servlet。 也就是說,Java servlet 技術的**基礎知識**對于任何 Java Web 開發人員都可能非常有用。 在本教程中,我們將涵蓋以下主題,以全面了解 Java Servlet 技術。 ```java Table of Contents Writing your first Servlet Servlet Life Cycle Methods Develop Servlet with @WebServlet Annotation Packaging and Deploying Servlet into Tomcat Server Writing dynamic content in Servlet response Handling Servlet Request and Response Listening for Servlet Container Events Passing Servlet Initialization Parameters Adding Servlet Filters for Specific URL Requests Downloading a binary file using Servlet Forward request to another servlet using RequestDispatcher.forward() Redirect request to another servlet using HttpServletResponse.sendRedirect() Writing and Reading Cookie using Servlets ``` 讓我們開始逐步了解 servlet。 ## 編寫您的第一個 Servlet 我們的第一個 servlet 是非常簡單的 servlet,它具有很少的代碼,因此您只能專注于重要的事情。 ```java package com.howtodoinjava.servlets; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyFirstServlet extends HttpServlet { private static final long serialVersionUID = -1915463532411657451L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { // Write some content out.println("<html>"); out.println("<head>"); out.println("<title>MyFirstServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h2>Servlet MyFirstServlet at " + request.getContextPath() + "</h2>"); out.println("</body>"); out.println("</html>"); } finally { out.close(); } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //Do some other work } @Override public String getServletInfo() { return "MyFirstServlet"; } } ``` **要在 Web 容器上方注冊上述 Servlet,您將為您的應用創建一個入口`web.xml`文件。** ```java <?xml version="1.0"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <welcome-file-list> <welcome-file>/MyFirstServlet</welcome-file> </welcome-file-list> <servlet> <servlet-name>MyFirstServlet</servlet-name> <servlet-class>com.howtodoinjava.servlets.MyFirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyFirstServlet</servlet-name> <url-pattern>/MyFirstServlet</url-pattern> </servlet-mapping> </web-app> ``` Servlet 上面沒有做一些重要的事情,您可能需要學習。 1. `MyFirstServlet`擴展了`HttpServlet`。 這是強制性的,因為所有 servlet 必須是擴展`javax.servlet.GenericServlet`的通用 servlet 或擴展`javax.servlet.http.HttpServlet`的 HTTP servlet。 2. 覆蓋`doGet()`和`doPost()`方法。 這些方法在`HttpServlet`類中定義。 每當 GET 或 POST 請求到來時,都會將其映射到其相應的方法,例如,如果您對此 Servlet 發出 HTTP GET 請求,然后調用`doGet()`方法。 3. 還有一些其他有用的方法,您可以覆蓋它們以在運行時控制應用,例如`getServletInfo()`。 4. `HttpServletRequest`和`HttpServletResponse`是所有`doXXX()`方法的默認參數。 我們將在后面的部分中了解有關這些對象的更多信息。 這就是您應該知道的簡單 servlet 的全部內容。 ## Servlet 生命周期方法 無論何時在您的應用中,都會加載并使用一個 servlet。 在該 Servlet 的初始化和銷毀??過程中發生了一系列事件。 這些被稱為 servlet 的**生命周期事件(或方法)**。 讓我們詳細了解它們。 三種方法對于 Servlet 的生命周期至關重要。 它們是`init()`,`service()`和`destroy()`。 它們由每個 servlet 實現,并在運行時在特定時間調用。 1)在 Servlet 生命周期的初始化階段, **Web 容器通過調用`init()`方法**并傳遞實現`javax.servlet.ServletConfig`接口的對象來初始化 Servlet 實例。 此配置對象允許 Servlet 訪問 Web 應用的`web.xml`文件中定義的名稱 - 值初始化參數。 它**在該 Servlet 實例**的生存期內僅被調用一次。 初始化方法的定義如下所示: ```java public void init() throws ServletException { //custom initialization code } ``` 2)初始化后,Servlet 實例可以為客戶端請求提供服務。 **Web 容器針對每個請求**調用 servlet 的`service()`方法。 `service()`方法確定發出的請求的類型,并將其分派給適當的方法以處理該請求。 Servlet 的開發人員必須提供這些方法的實現。 如果對不是由 Servlet 實現的方法提出了請求,則將調用父類的方法,通常會導致將錯誤返回給請求者。 幾乎在所有情況下都無需覆蓋此方法。 ```java protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } } ``` 3)最后, **Web 容器調用`destroy()`方法,該方法使 Servlet 退出服務**。 如果要在 Servlet 超出范圍之前關閉或銷毀某些文件系統或網絡資源,則應調用此方法。 像`init()`一樣,`destroy()`方法在 Servlet 的生命周期中僅被調用一次。 ```java public void destroy() { // } ``` 通常,在大多數情況下,您不需要在 servlet 中覆蓋它們中的任何一個。 > **閱讀更多**: [Web 服務器如何工作?](//howtodoinjava.com/for-fun-only/a-birds-eye-view-on-how-web-servers-work/ "A birds-eye view on “how web servers work?”") ## 使用`@WebServlet`注解開發 Servlet 如果您不太喜歡 xml 配置,而是特別喜歡注解,那么 Servlets API 也可以。 您可以使用[`@WebServlet`](https://docs.oracle.com/javaee/6/api/javax/servlet/annotation/WebServlet.html "WebServlet")注解,如下例所示,然后您無需在`web.xml`中進行任何輸入。 **容器將自動將您的 servlet 注冊到運行時,并像往常一樣處理它**。 ```java package com.howtodoinjava.servlets; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name = "MyFirstServlet", urlPatterns = {"/MyFirstServlet"}) public class MyFirstServlet extends HttpServlet { private static final long serialVersionUID = -1915463532411657451L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //Do some work } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //Do some other work } } ``` ## 將 Servlet 打包和部署到 Tomcat 服務器 如果您使用的是任何 IDE(例如 eclipse),則打包和部署應用只是一個步驟。 `Right click on project > Run As > Run As Server`。 如果尚未配置服務器,則準備好進行滾動。 如果您不使用任何 IDE,那么您需要做一些額外的工作,例如從命令提示符下編譯應用,使用 ANT 創建 WAR 文件等。但是我非常相信當今的每個人都使用一些 IDE 進行開發,因此我將 不要在本節中浪費更多時間。 當您在 tomcat 中部署我們的第一個 servlet 并在瀏覽器中訪問 URL“`http://localhost:8080/servletexamples/MyFirstServlet`”時,您將獲得以下響應。 ![servlet example](https://img.kancloud.cn/a4/98/a498ea453a34487036829cb7ee8a5fa0_659x166.png) ## 在 Servlet 響應中編寫動態內容 Java servlet 之所以如此有用的原因之一是因為它們允許將動態內容顯示在網頁上。 內容可以取自服務器本身,數據庫,另一個網站或許多其他可從 Web 訪問的資源。 Servlet 不是靜態網頁。 他們充滿活力,可以說是他們最大的優勢。 讓我們以一個 servlet 為例,該 servlet 負責向用戶顯示當前日期和時間,以及其名稱和一些自定義消息。 讓我們為其編寫代碼。 ```java package com.howtodoinjava.servlets; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name = "CalendarServlet", urlPatterns = {"/CalendarServlet"}) public class CalendarServlet extends HttpServlet { private static final long serialVersionUID = -1915463532411657451L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Map<String,String> data = getData(); response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { // Write some content out.println("<html>"); out.println("<head>"); out.println("<title>CalendarServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h2>Hello " + data.get("username") + ", " + data.get("message") + "</h2>"); out.println("<h2>The time right now is : " + new Date() + "</h2>"); out.println("</body>"); out.println("</html>"); } finally { out.close(); } } //This method will access some external system as database to get user name, and his personalized message private Map<String, String> getData() { Map<String, String> data = new HashMap<String, String>(); data.put("username", "Guest"); data.put("message", "Welcome to my world !!"); return data; } } ``` 當您在 tomcat 中的 servlet 上方運行并在瀏覽器中訪問 URL“`http://localhost:8080/servletexamples/CalendarServlet`”時,將得到以下響應。 ![dynamic content in servlet](https://img.kancloud.cn/d7/bd/d7bddd83bc0692ff10ce53385de3a9dc_694x259.png) ## 處理 Servlet 請求和響應 Servlet 使創建符合請求和響應生命周期的 Web 應用變得容易。 它們具有提供 HTTP 響應的能力,并且還可以在同一代碼體內處理業務邏輯。 處理業務邏輯的能力使 servlet 比標準 HTML 代碼強大得多。 在實際的應用中,HTML Web 表單包含發送到 Servlet 的參數。 然后,該 Servlet 以某種方式處理這些參數,并發布客戶端可以看到的響應。 對于`HttpServlet`對象,客戶端是 Web 瀏覽器,響應是 Web 頁面。 `<form>`動作屬性指出應使用該屬性來處理表單中包含的值。 要獲取請求參數,請調用`HttpServletRequest`對象的`getParameter()`方法,并傳遞您要獲取的輸入參數的 ID。 ```java String value1 = req.getParameter("param1"); String value1 = req.getParameter("param2"); ``` 一旦獲得值,就可以根據需要對其進行處理。 然后,如上節所述,為客戶準備響應。 使用`HttpServletResponse`對象將該響應發送回客戶端。 請求和響應處理的基本用法可以這樣完成: ```java @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); String username = request.getParameter("username"); String password = request.getParameter("password"); boolean success = validateUser(username, password); try { // Write some content out.println("<html>"); out.println("<head>"); out.println("<title>LoginServlet</title>"); out.println("</head>"); out.println("<body>"); if(success) { out.println("<h2>Welcome Friend</h2>"); }else{ out.println("<h2>Validate your self again.</h2>"); } out.println("</body>"); out.println("</html>"); } finally { out.close(); } } ``` 為了發送內容,您將必須使用從`HttpServletResponse`獲得的`PrintWriter`對象。 寫入其中的任何內容都將寫入輸出流,并且數據將發送回客戶端。 ## 監聽 Servlet 容器事件 有時了解某些事件在應用服務器容器中何時發生很有用。 此概念在許多不同的情況下都可能有用,但是最常用于啟動時初始化應用或關閉后清除應用。 Servlet 監聽器可以向應用注冊,以指示何時啟動或關閉它。 因此,通過監聽此類事件,servlet 可以有機會在它們發生時執行某些操作。 要創建一個基于容器事件執行操作的監聽器,必須開發一個實現`ServletContextListener`接口的類。 需要實現的方法是`contextInitialized()`和`contextDestroyed()`。 這兩種方法都接受`ServletContextEvent`作為參數,并且分別在每次初始化或關閉 servlet 容器時自動調用它們。 若要向容器注冊監聽器,可以使用以下技術之一: 1)使用`@WebListener`注解。 2)在`web.xml`應用部署描述符中注冊監聽器。 3)使用在`ServletContext`上定義的`addListener()`方法。 請注意,`ServletContextListener`不是 servlet API 中的唯一列表器。 還有更多例如: * `javax.servlet.ServletRequestListener` * `javax.servlet.ServletRequestAttrbiteListener` * `javax.servlet.ServletContextListener` * `javax.servlet.ServletContextAttributeListener` * `javax.servlet.HttpSessionListener` * `javax.servlet.HttpSessionAttributeListener` 可以由您的列表器類根據您想聽所有事件的選擇來實現它們; 例如,每當創建或銷毀新的用戶會話時,都會通知`HttpSessionListener`。 ## 傳遞 Servlet 初始化參數 當今大多數應用都需要設置一些配置參數,您可以在應用/控制器啟動時將其傳遞給他們。 Servlet 還可以接收初始化參數,在為第一個請求提供服務之前,它們可以用來完全構造它們。 顯然,您可以在 servlet 本身中對配置值進行硬編碼,但是更改其中的任何一個將需要您重新重新編譯整個應用,而且沒人愿意這樣做。 ```java <web-app> <servlet> <servlet-name>SimpleServlet</servlet-name> <servlet-class>com.howtodoinjava.servlets.SimpleServlet</servlet-class> <!-- Servlet init param --> <init-param> <param-name>name</param-name> <param-value>value</param-value> </init-param> </servlet> </web-app> ``` 設置后,可以通過調用`getServletConfig().getInitializationParameter()`并傳遞參數名稱在代碼內使用該參數,如以下代碼行所示: ```java String value = getServletConfig().getInitParameter("name"); ``` ## 為特定的 URL 請求添加 Servlet 過濾器 Web 過濾器對于預處理請求和訪問給定 URL 時調用某些功能很有用。 與其直接調用在給定 URL 上存在的 servlet,否則將在 servlet 之前調用任何包含相同 URL 模式的過濾器。 這在許多情況下可能是有用的,這對于執行日志記錄,認證或在沒有用戶交互的情況下在后臺進行的其他服務而言可能是最有用的。 過濾器必須實現`javax.servlet.Filter`接口。 此接口中包含的方法包括`init()`,`destroy()`和`doFilter()`。 容器調用`init()`和`destroy()`方法。 `doFilter()`方法用于實現過濾器類的任務。 如果要鏈接過濾器,或者給定 URL 模式存在多個過濾器,則將按照在`web.xml`部署描述符中對其進行配置的順序來調用它們。 要將`web.xml`文件配置為包含過濾器,請使用`<filter>`和`<filter-mapping>` XML 元素及其關聯的子元素標簽。 ```java <filter> <filter-name>LoggingFilter</filter-name> <filter-class>LoggingFilter</filter-class> </filter> <filter-mapping> <filter-name>LogingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` 如果要使用注解為特定的 servlet 配置過濾器,則可以使用`@WebFilter`注解。 ## 使用 Servlet 下載二進制文件 對于幾乎所有 Web 應用來說,下載文件都是一項基本任務。 要下載文件,servlet 必須提供與要下載的文件相匹配的相同類型的響應。 它還必須在響應標頭中指出要包含附件,如下所示。 ```java String mimeType = context.getMimeType( fileToDownload ); response.setContentType( mimeType != null ? mimeType : "text/plain" ); response.setHeader( "Content-Disposition", "attachment; filename=\"" + fileToDownload + "\"" ); ``` 您可以通過調用`ServletContext.getResourceAsStream()`方法并傳遞文件路徑來獲取對要下載(存儲在文件系統中)文件的引用。 這將返回一個`InputStream`對象,該對象可用于讀取文件的內容。 然后創建一個字節緩沖區,該緩沖區將在讀取文件時用于從文件中獲取數據塊。 最后的實際任務是讀取文件內容并將其復制到輸出流。 這是使用`while`循環完成的,該循環將繼續從`InputStream`讀取,直到處理完所有內容為止。 使用循環將數據塊讀入并寫入輸出流。 之后,將調用`ServletOutputStream`對象的`flush`方法以清除內容并釋放資源。 讓我們看一下示例代碼 ```java private void downloadFile(HttpServletRequest request, HttpServletResponse response, String fileToDownload) throws IOException { final int BYTES = 1024; int length = 0; ServletOutputStream outStream = response.getOutputStream(); ServletContext context = getServletConfig().getServletContext(); String mimeType = context.getMimeType( fileToDownload ); response.setContentType( mimeType != null ? mimeType : "text/plain" ); response.setHeader( "Content-Disposition", "attachment; filename=\"" + fileToDownload + "\"" ); InputStream in = context.getResourceAsStream("/" + fileToDownload); byte[] bbuf = new byte[BYTES]; while ((in != null) && ((length = in.read(bbuf)) != -1)) { outStream.write(bbuf, 0, length); } outStream.flush(); outStream.close(); } ``` ## 使用`RequestDispatcher.forward()`將請求轉發到另一個 servlet 有時,您的應用要求 servlet 應該將請求移交給其他 servlet,以完成需要完成的任務。 此外,應在不將客戶端重定向到另一個 URL 的情況下移交請求,即瀏覽器中的 URL 不應更改。 這樣做的功能直接內置在`ServletContext`中,因此一旦獲得對`ServletContext`的引用,就可以簡單地調用`getRequestDispatcher()`方法來獲取一個`RequestDispatcher`對象,該對象可用于分派請求。 調用`getRequestDispatcher()`方法時,傳遞一個字符串,其中包含要將您的請求傳遞到的 servlet 的名稱。 獲得`RequestDispatcher`對象后,通過將`HttpServletRequest`和`HttpServletResponse`對象傳遞給它來調用其前向方法。 轉發方法執行移交請求的任務。 ```java RequestDispatcher rd = servletContext.getRequestDispatcher("/NextServlet"); rd.forward(request, response); ``` ## 使用`HttpServletResponse.sendRedirect()`將請求重定向到另一個 servlet 盡管在某些情況下,您不希望像上一節中所看到的那樣通知用戶 servlet 重定向已發生,但是在某些情況下,我們實際上希望發生這種情況。 當您訪問應用中的特定 URL 時,您想將瀏覽器重定向到另一個 URL。 為此,您將需要調用`HttpServletResponse`對象的`sendRedirect()`方法。 ```java httpServletResponse.sendRedirect("/anotherURL"); ``` 與 servlet 鏈接相反,這種簡單的重定向不會將`HttpRequest`對象傳遞到目標地址。 ## 使用 Servlet 編寫和讀取 Cookie 許多應用都希望將用戶瀏覽歷史記錄的當前狀態存儲在客戶端計算機中,以便當用戶再次返回到應用時,他從離開的地方開始。 通常為此要求使用 cookie。 您可以將 Cookie 視為存儲在客戶計算機上的基于鍵值對的數據。 當在瀏覽器中訪問應用時,應用將能夠讀取或寫入這些值。 要創建 cookie,只需實例化一個新的`javax.servlet.http.Cookie`對象并為其分配名稱和值。 一旦實例化了 cookie,就可以設置將有助于配置 cookie 的屬性。 在此食譜的示例中,調用了 cookie 的`setMaxAge()`和`setHttpOnly()`方法,設置了 cookie 的生存時間,并確保防止客戶端腳本編寫。 從 Servlet 3.0 API 開始,將 cookie 標記為僅 HTTP 的功能已變得可用。 這樣可以保護 cookie 免受客戶端腳本攻擊,從而使 cookie 更加安全。 ```java Cookie cookie = new Cookie("sessionId","123456789"); cookie.setHttpOnly(true); cookie.setMaxAge(-30); response.addCookie(cookie); ``` 這里的響應是傳遞給`doXXX()`方法的`HttpServletResponse`的實例。 要回讀服務器父項上的 cookie 信息,請使用以下代碼: ```java Cookie[] cookies = request.getCookies(); for(Cookie cookie : cookies) { //cookie.getName(); //cookie.getValue() } ``` 以上就是有關 Servlet 技術的本教程。 隨意刪除評論/反饋。 **祝您學習愉快!**
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看