剛才發現,這里的圖片不能正常顯示,所以我給個鏈接,大家可以下載下來看從瀏覽器訪問servlet流程圖.png
2. 生命周期Servlet的一生都是由容器來管理的。
①WEB服務器首先會檢查是否已經裝載并創建了該servlet實例對象。如果是直接進行第④步,否則執行第②步;
②裝載并創建該Servlet類的一個實例對象(此時該對象還只是一個普通的java類);
③調用Servlet實例對象的init()方法,使Java類成為一個真正的Servlet;
④創建一個用于封裝HTTP請求消息的HttpServletRequest對象和一個代表HTTP響應消息的HttpServletResponse對象,然后調用service()方法并將請求和響應作為參數傳遞進去。service()方法將根據客戶端的請求方式來決定調用對應的doXXX()方法;
⑤WEB應用被停止或重啟之前,Servlet引擎將卸載Servlet,在卸載之前調用Servlet的destroy()方法。
①實現Servlet接口
② 通過繼承 GenericServlet
③通過繼承 HttpServlet
99%的情況下我們使用的是第三種方式來發開。
3.2 手動開發一個Web應用前一節中我們Web應用的目錄結構,只有按照這個目錄結構的規范,tomcat才能正確的解析這些內容。下面我們手動(不用IDE)使用實現Servlet接口的方法來開發并部署一個Servlet應用:
需求:請使用實現Servlet接口的方式,來開發一個Servlet ,要求該Servlet 可以顯示Hello,world。
①在Tomcat的webapps下建立一個web應用HelloWorld(即,建立一個名為HelloWorld的文件夾)
② 在HelloWorld下建立 WEB-INF->web.xml [web.xml可以從 ROOT/WEB-INF/web.xml拷貝]
③在WEB-INF 下建立 classes 目錄(簡單起見我們在這里放Servlet的.java文件和.class文件),建立lib文件夾
④添加Servlet的jar包到環境變量的classpath中
⑤開發HelloWorld.java
1 package com.yyl; 2 import javax.servlet.*; 3 import javax.servlet.http.*; 4 import java.io.*; 5 class HelloWorld implements Servlet 6 { 7 //該函數用于初始化servlet,就是將該Servlet的Java對象轉為Servlet,該函數只會被調用一次 8 public void init(ServletConfig config) throws ServletException{ 9 }10 11 //得到ServletConfig對象12 public ServletConfig getServletConfig(){13 return null;14 }15 16 //該函數是服務函數,我們的業務邏輯代碼就是寫在這里,該函數每次都會被調用17 public void service(ServletRequest req,ServletResponse res) throws ServletException,java.io.IOException{18 res.getWriter().View Code現在我們在web.xml文件部署我們的Servlet:
1 <?xml version="1.0" encoding="ISO-8859-1"?> 2 <!-- 3 Licensed to the Apache Software Foundation (ASF) under one or more 4 contributor license agreements. See the NOTICE file distributed with 5 this work for additional information regarding copyright ownership. 6 The ASF licenses this file to You under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with 8 the License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.011 12 Unless required by applicable law or agreed to in writing, software13 distributed under the License is distributed on an "AS IS" BASIS,14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15 See the License for the specific language governing permissions and16 limitations under the License.17 -->18 19 <web-app xmlns="http://java.sun.com/xml/ns/javaee"20 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"21 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"22 version="2.5">23 24 <!--根據serlvet規范,需要將Servlet部署到web.xml文件,該部署配置可以從examples下拷貝-->25 <servlet>26 <!--servlet-name 給該Servlet取名, 該名字可以自己定義:默認就使用該Servlet的名字-->27 <servlet-name>HelloWorld</servlet-name><!--③-->28 <!--servlet-class要指明該Servlet 放在哪個包下 的,形式是 包/包/../類-->29 <servlet-class>com.yyl.HelloWorld</servlet-class><!-- 注意:后面不要帶.java④-->30 </servlet>31 <!--Servlet的映射-->32 <servlet-mapping>33 <!--這個Servlet-name要和上面的servlet-name名字一樣-->34 <servlet-name>HelloWorld</servlet-name><!--②-->35 <!--url-pattern 這里就是將來訪問該Servlet的資源名部分-->36 <url-pattern>/ABC</url-pattern><!--①-->37 </servlet-mapping>38 </web-app>View Code訪問頁面:
如何使用IDE來開發Servlet應該沒必要說明了吧!
3.3 HttpServlet的繼承體系
由于GenericServlet極少使用,所以就沒有列舉,但是HttpServlet中有很多方法都是從它那里繼承而來的。
ServletConfig對象
每一個Servlet都有一個ServletConfig對象,它用于在將普通Java類轉為Servlet時傳遞部署時信息;用于訪問ServletContext。參數在web.xml文件中配置,如:
1 <servlet>2 <init-param>3 <param-name>email</param-name>4 <param-value>yaoyinglong@Gmail.com</param-value>5 </init-param>6 </servlet>View CodeServletContext
每一個Web應用都有一個ServletContext,用于訪問Web應用參數(也在web.xml文件中配置)。
上面這兩個對象在以后用到會詳細說明,暫時有個印象就可以了。
4. 使用通配符將servlet映射到URL中前提聲明:當映射一個servlet時候,可以多層次,即(用“/”分割),如:
<url-pattern>/servlet/abc/index.html</url-pattern>通配符有兩種格式:
第一種格式 *.擴展名 比如 *.do *.ss
第二種格式 以 / 開頭 同時以 /* 結尾 比如 /* 、/news/*
在匹配的時候,要參考的標準:
(1) 看誰的匹配度高,誰就被選擇
(2) *.do 的優先級最低
5. Servlet單例問題針對多客戶端的多次Servlet請求,通常情況下,服務器只會創建一個Servlet實例對象。也就是說Servlet實例對象一旦創建,它就會駐留在內存中,為后續的其他請求服務,直至web服務器退出或者reload該web應用,servlet實例對象才會才會銷毀(參考Servlet的生命周期)。
當Servlet被第一次訪問后,就被加載到內存,以后該實例對各個請求服務。即在使用中是單例,因此會出現線程安全問題。
這里給大家一個原則:
(1)如果一個變量需要多個用戶共享,則應當在訪問該變量的時候,加同步機制
synchronized (對象){
//同步代碼
}
(2)如果一個變量不需要共享,則直接在 doGet() 或者 doPost()定義。這樣不會存在線程安全問題。
6. 請求和響應易混點6.1 getServerPort()、getLocalPort()、getRemotePort()這些是在服務器端調用的,所以相對于服務器來說,遠程指的是客戶。所以getRemotePort()得到的是客戶的端口。
getServerPort() 指的是請求原來發送到那個端口。而 getLocalPort()請求最后發送到那個端口。
6.2 對于輸出的兩個選擇ServletOuptputStream用于輸出字節,PrintWriter用于輸出字符。
獲取方式:都是把返回類型的第一個詞去掉加get。
PrintWriter實際上包裝了ServletOutputStream(即PrintWriter有ServletOuptputStream的一個引用)而且會把調用委托給ServletOutputStream。返回給客戶的輸出流只有一個,但是PrintWriter會裝飾這個流,為它增加更高層的"字符友好"方法。
6.3 設置相應首部和增加相應首部setHeader和addHeader
7. 請求轉發
- 共同點:當響應中還沒有這個首部(方法的第一個參數),他們都會增加這個首部和相應的值。
- 不同點:如果響應中已經有這個首部,setHeader是用這個值替換原來的值,而addHeader是在原來值的基礎上,再加上這個值。
兩種方法:
- 將請求重定向(301)到完全不同的URL。
- 把請求分派給Web應用的另一組件。
重定向
servlet調用sendRedirect(string)。請求返回到客戶瀏覽器,瀏覽器發現響應碼為301,立即找到location首部,使用該location的值建立一個新的請求。這時用戶會發現瀏覽器的地址欄已經改變了。
servlet調用的sendRedirect(string) 中的參數string可以是一個表示外部的絕對URL如:http://www.baidu.com。也可以是一個相對的URL。相對URL以"/"開頭表示:相對于本次請求的域名或Tomcat的webapp目錄。相對URL沒有以"/"開頭表示:相對于本次請求的上一級目錄。
請求分派
request.getRequestDispatcher("所請求的資源名").forward(request,response)。這里的"所請求的資源名"不能加上Web應用的名稱,因為請求分派只會在本Web應用中查找該資源。但是可以以斜線("/")開頭。
請求分派,請求不會返回瀏覽器,請求只有一次,并且客戶端的瀏覽器的URL不會發生改變。重定向的請求為兩次。
新聞熱點
疑難解答