在Tomcat初次嘗試中,我們搭建了用於測試Servlet和JSP的基本環境。我們現在要轉向網絡應用的具體開發。
Web服務器的基本工作方式是請求-處理-回復。請求和回復是在網絡上,以HTTP協議為基礎的通信(參考HTTP協議)。請求是客戶點菜,回復像是服務員上菜,而處理則是在後廚中,廚師根據請求的菜單,准備菜品的過程。
廚師通常是服務器上的一個應用程序。這個應用程序可以提取請求中的信息,並根據這些信息准備回復。這樣的應用程序可以是許多中語言寫成的,比如C, C++, Perl, Ruby, Python, Ruby, PHP等等。由於不同語言的設計理念和編譯器特征的不同,這些語言寫成的應用程序也有不同的特點(各種各樣的廚師)。比如C和C++語言會有比較高的運行效率,PHP的Web應用廣泛,Ruby和Python開發方便等等。
(在語言之爭中,Web服務器的“後廚”是一塊兵家必爭之地)
Servlet是Java語言提供的的“廚師”。在Java中,“一切皆對象”。Servlet是一類特殊的Java對象。Java語言利用Servlet對象,來實現對HTTP請求的處理。
下面是一個簡單的Servlet例子,源文件為TestPage.java:
package foo; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class TestPage extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { PrintWriter out = response.getWriter(); out.println("<html><body>" + "<p>Hello World!</p>" + "</body></html>"); } }
這個Servlet的功能是回復字符串"<html><body><p>Hello World!</p></body></html>"。這一段字符串實際上是一個HTML文本。它將作為HTTP回復的主體部分,發回給客戶端。
這裡定義了一個TestPage類,該類繼承HttpServlet抽象類(參考HttpServlet)。我們覆蓋了doGet()方法。doGet()方法處理GET方法的HTTP請求。如果HTTP請求的方法為POST,則應該覆蓋doPost()方法。每個Servlet都應該覆蓋doGet()和doPost()之一。doGet()和doPost()方法接收兩個參數request和response,分別為HttpServletRequest類型和HttpServletResponse類型。這兩個參數分別代表該次HTTP通信的請求和回復。
HttpServletRequest和HttpServletResponse為兩個接口。在方法的內部,我們可以操作request和response對象。比如,通過response的getWriter方法,來獲得Writer,從而寫入HTML文本。這些寫入的文本將作為HTTP回復的主體傳遞回客戶端。再比如,我們可以使用request的getMethod()方法來獲知HTTP請求的方法。可以參考下面的官方文檔:
HttpServletRequest的更多方法
HttpServletResponse的更多方法
此外,PrintWriter類來自java.io包。參考Java IO
查看本欄目
doGet()是真正的工作室。我們通過定義該方法(或者doPost())方法,來讓廚師做特定的事情。Servlet編寫的關鍵在於寫出一個符合需求的doGet()方法或者doPost()方法。
doGet()與doPost()
正如第一行package語句所說明的(參考Java包),TestPage類被放入到foo包中。我們還import了其他的Java包。Servlet是基於Java的,所以它可以借助Java語言所提供的豐富的工具。
使用下面命令編譯TestPage.java
$javac -classpath /path-to-tomcat/lib/servlet-api.jar:classes:. TestPage.java
上面的path-to-tomcat是Tomcat的安裝路徑。我們需要包括servlet-api.jar,原因是,javax.servlet包屬於J2EE,它並不屬於JSE。
將編譯生成的TestPage.class文件放入到下面的文件夾中。(如果文件夾不存在,需要自行創建):
/path-to-tomcat/webapps/test/WEB-INF/classes/foo
(在TesPage.java中,利用package語句,說明該類在foo包中。這裡的路徑符合之前的package定義。)
修改或者新建/path-to-tomcat/webapps/test/WEB-INFO/web.xml
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="true"> <servlet> <servlet-name>Test</servlet-name> <servlet-class>foo.TestPage</servlet-class> </servlet> <servlet-mapping> <servlet-name>Test</servlet-name> <url-pattern>/MyServlet</url-pattern> </servlet-mapping> </web-app>
查看本欄目
這樣的一個xml文件被稱作部署描述(DD, Deployment Descriptor)。DD告訴Container如何運行Servlet和JSP。
上面的<servlet>標簽是將該Servlet(foo.TestPage.class)命名為Test。
在<servlet-mapping>標簽中,我們將Test這個Servlet對應於URL: /MyServlet。這說明,當有請求訪問該URL時,則將請求傳遞給Test這個Servlet處理。
上面修改的主要目的,是說明Servlet與URL的對應關系。
隨後,可以訪問localhost:8080/test/MyServlet,來查看訪問頁面。
看一下Servlet完成一次請求處理的過程:
從客戶端(Guest)向服務器發送HTTP請求,該HTTP請求傳遞給Servlet Container。該Container負責:
分析HTTP請求的信息,並新建request對象,將HTTP請求中的信息放入request對象
新建response對象
根據web.xml,查找URL對應的Servlet對象。如果Servlet對象不存在,則新建相應Servlet對象。
創建新的線程,用於處理本次請求。線程擁有指向request和response對象的引用。
線程將調用Servlet的doGet()或者doPost()方法。線程運行結束後,response對象將傳回給Container。Container根據response對象中的信息,生成一個符合HTTP協議的回復,傳回給客戶端。
注意,即使是新建的Servlet對象,它也不會隨著線程的結束而結束。Servlet將繼續存在。下次相同的URL訪問將不必新建Servlet。
上面制作了一個簡單的Servlet,主要用於說明制作Servlet的過程。Servlet的許多強大功能還有待以後展開。
每個Servlet就像是後廚的一個廚師。我們可以用不同的URL對應來選擇不同的廚師。一個復雜的網站往往需要許多個不同功能的Servlet。
作者:Vamei 出處:http://www.cnblogs.com/vamei