# Servlet入門
### 基本概述
????Servlet(Server?Applet),全稱Java?Servlet,未有中文譯文。是用Java編寫的服務器端程序。其主要功能在于交互式地瀏覽和修改數據,生成動態Web內容。狹義的Servlet是指Java語言實現的一個接口,廣義的Servlet是指任何實現了這個Servlet接口的類,一般情況下,人們將Servlet理解為后者。
????Servlet運行于支持Java的應用服務器中。從原理上講,Servlet可以響應任何類型的請求,但絕大多數情況下Servlet只用來擴展基于HTTP協議的Web服務器。
PS:學習Servlet是學習JSP的基礎,故很重要。
?
### Servlet在網絡中的位置

### Servlet的生命周期

1、WEB服務器(Tomcat)首先會找到該Servlet并裝載該Servlet
2、WEB服務器(Tomcat)會創建該Servlet的實例
3、WEB服務器(Tomcat)會調用實例對象的init()方法
4、WEB服務器(Tomcat)創建一個封裝HTTP請求消息的HttpServletRequest對象和一個代表HTTP響應消息的HttpServletResponse對象,然后調用service()方法并將請求對象和響應對象作為參數傳遞進去。(實現是通過多線程技術)
5、WEB服務器在某種情況,停止對該Servlet支持,Servlet引擎將卸載該Servlet,在卸載之前會調用Servlet的destroy()方法進行銷毀
### 手工開發Servlet的方式
1、在Tomcat主目錄的webapps文件夾下建立一個web應用web1
2、在web1下建立文件夾WEB-INF,在該文件夾中建立web.xml?[web.xml可以從?ROOT/WEB-INF/web.xml拷貝]?
3、在WEB-INF目錄下建立classes目錄(Servlet在該目錄下開發),建立lib目錄
4、在classes目錄下開發Servlet
5、在web.xml中配置web.xml
6、編譯Servlet文件(編譯時需要將servlet-api.jar包加入環境變量classpath中,該jar包在Tomcat主目錄的lib文件夾下)
7、運行Tomcat
8、訪問Servlet
### 開發Servlet的三種方法
#### 1、實現Servlet接口
~~~
/**
使用實現Servlet接口的方式開發一個Servlet
要求:顯示當前時間
*/
package com.pc;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class Servlet2 implements Servlet{
// 該方法用于初始化Servlet,就是把該Servlet裝載入內存,該方法只會被調用一次
public void init(ServletConfig config){
}
// 得到ServletConfig對象
public ServletConfig getServletConfig(){
return null;
}
// 該方法是服務方法,業務邏輯代碼寫在這
// 該方法每次都會被調用
public void service(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException{
// 在控制臺輸出
System.out.println("hello world:" + new java.util.Date().toString());
// 在瀏覽器返回
res.getWriter().println("hello world:" + new java.util.Date().toLocaleString());
}
// 該方法得到Servlet配置信息
public java.lang.String getServletInfo(){
return null;
}
// 銷毀該Servlet,從內存中清除,該方法只會被調用一次
public void destroy(){
}
}
~~~
?
PS:不僅要寫Servlet文件,還要在web.xml中添加配置信息,配置信息格式如下:
~~~
<!-- servlet部署到web.xml文件,該部署配置可以從examples下拷貝 -->
<servlet>
<!--servlet-name 該名字可以自定義,但是默認就使用servlet的名字 -->
<servlet-name>Servlet2</servlet-name>
<!--servlet-class要指明該servlet放在那個包下的 -->
<servlet-class>com.pc.Servlet2</servlet-class>
</servlet>
<!-- servlet的映射 -->
<servlet-mapping>
<!-- 這個servlet-name要和上面的servlet-name名字一樣,這樣才能匹配的上 -->
<servlet-name>Servlet2</servlet-name>
<!-- url-pattern 這是訪問該servlet的資源部分 默認命名規范:就是該servlet的名字-->
<url-pattern>/Servlet2</url-pattern>
</servlet-mapping>
~~~
PS:
1、在classes文件夾下編譯(當然Servlet文件也應該在這里)
javac?-encoding?UTF-8?-d?.?Servlet文件名.java
2、不重啟更新web應用
首先,在Tomcat主目錄的conf文件夾中找到tomcat-users.xml文件,打開它,并在<tomcat-user></tomcat-user>標簽中添加如下語句
~~~
<tomcat-users>
<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>
</tomcat-users>
~~~
然后,在localhost:8080主界面點擊,進入manager界面,找到該應用,點擊reload按鈕即可。
#### 2、繼承GenericServlet類
~~~
/**
使用繼承GenericServlet的方式開發一個Servlet
*/
package com.pc;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class Servlet3 extends GenericServlet{
// 該方法是服務方法,業務邏輯代碼寫在這
// 該方法每次都會被調用
public void service(ServletRequest req,ServletResponse res) throws ServletException,IOException{
res.getWriter().println("hellow,world, GenericServle.");
}
}
~~~
PS:不僅要寫Servlet文件,還要在web.xml中添加配置信息,配置信息格式如下:
~~~
<servlet>
<servlet-name>Servlet3</servlet-name>
<servlet-class>com.pc.Servlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet3</servlet-name>
<url-pattern>/Servlet3</url-pattern>
</servlet-mapping>
~~~
#### 3、繼承HttpServlet類
~~~
/**
使用繼承HttpServlet的方式開發一個Servlet
要求:顯示當前時間
*/
package com.pc;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class Servlet4 extends HttpServlet{
// 在HttpServlet中,設計者分別提供了對Post提交和Get提交的處理,默認是get提交
// doGet().doPost()底層也是調用service方法
// 處理Get請求
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException{
resp.getWriter().println("doGet()");
}
// 處理Post請求
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
resp.getWriter().println("doPost()");
}
}
~~~
PS:不僅要寫Servlet文件,還要在web.xml中添加配置信息,配置信息格式如下:
~~~
<servlet>
<servlet-name>Servlet4</servlet-name>
<servlet-class>com.pc.Servlet4</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet4</servlet-name>
<url-pattern>/Servlet4</url-pattern>
</servlet-mapping>
~~~
### 使用MyEclipse集成開發環境IDE來開發Web應用
PS:具體的配置步驟可以參考搜索引擎。
#### MyEclipse的開發目錄結構

### Servlet細節問題
#### 1、一個已經注冊的Servlet可以被多次映射
~~~
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<!-- servlet的注冊名 -->
<servlet-name>MyServlet1</servlet-name>
<!-- servlet類的全路徑(包名+類名) -->
<servlet-class>com.web1.servlet.MyServlet1</servlet-class>
</servlet>
<!-- 對一個已經注冊的servlet的映射 -->
<servlet-mapping>
<!-- servelt的注冊名 -->
<servlet-name>MyServlet1</servlet-name>
<!-- servlet的訪問路徑 -->
<url-pattern>/MyServlet1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet1</servlet-name>
<url-pattern>/abc</url-pattern>
</servlet-mapping>
~~~
#### 2、當映射一個Servlet時,可以多層映射
~~~
<url-pattern>/servlet/index.html</url-pattern>
~~~
#### 3、在Servlet使用通配符映射到URL
有兩種格式:
第一種格式??*.擴展名??比如?*.do??*.ss
第二種格式??以?/?開頭?同時以?/*?結尾??比如??/*???/news/*?
?
通配符案例:
????Servlet1?映射到?/abc/*?
????Servlet2?映射到?/*?
????Servlet3?映射到?/abc?
????Servlet4?映射到?*.do?
問題:
1、當請求URL為“/abc/a.html”,“/abc/*”和“/*”都匹配,哪個servlet響應
Servlet引擎將調用Servlet1。
2、當請求URL為“/abc”時,“/abc/*”和“/abc”都匹配,哪個servlet響應
Servlet引擎將調用Servlet3。
3、當請求URL為“/abc/a.do”時,“/abc/*”和“*.do”都匹配,哪個servlet響應
Servlet引擎將調用Servlet1。
4、當請求URL為“/a.do”時,“/*”和“*.do”都匹配,哪個servlet響應
Servlet引擎將調用Servlet2。
5、當請求URL為“/xxx/yyy/a.do”時,“/*”和“*.do”都匹配,哪個servlet響應
Servlet引擎將調用Servlet2。
?
在匹配的時候,要參考的標準:
????1、看誰的匹配度高,誰就被選擇
????2、*.do?的優先級最低
#### 4、servlet中的<load-on-startup>配置
? ? 當需要在網站啟動時,初始化一些資源時可以配置<load-on-startup>
~~~
<servlet>
<load-on-startup>1</load-on-startup>
</servlet>
~~~
PS:在servlet中如此配置就行,中間的數是整數,越小優先級越高。
配置好了之后,在網站啟動時就會調用該Servlet的init()方法,所以可以在該方法中進行需要的初始化步驟,比如定時刷新,建立內存表之類的等等。
### ServletConfig對象
? ??該對象主要用于讀取?servlet的配置信息.
案例:
~~~
<servlet>
<servlet-name>ServletConfigTest</servlet-name>
<servlet-class>com.web1.servlet.ServletConfigTest</servlet-class>
<!-- 這里可以給servlet配置信息,這里配置的信息,只能被該servlet 讀取 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
~~~
如何使用:在Servlet使用如下語句
~~~
String encoding = this.getServletConfig().getInitParameter("encoding");
~~~
補充說明:這種配置參數的方式,只能被某個Servlet獨立使用.如希望讓所有的Servlet都去讀取某個參數,這樣配置:
~~~
<!-- 如果這里配置參數,可被所有servlet讀取 -->
<context-param>
<param-name></param-name>
<param-value></param-value>
</context-param>
~~~
讀取所有的參數,可以使用如下方法:
~~~
Enumeration<String> names=this.getServletConfig().getInitParameterNames();
while(names.hasMoreElements()){
String name=names.nextElement();
System.out.println(name);
System.out.println(this.getServletConfig().getInitParameter(name));
}
~~~
### 注意事項:
1、Servlet類是單例模式的,所以要注意線程同步情況。
2、Servlet的service()方法,在每次響應時都會調用一次。
3、Servlet的init()初始化方法,destroy()銷毀方法只會被調用一次。
4、Servlet的service()方法,會根據客戶端的請求方法來決定調用對應的doXXX()方法。
5、不要重寫構造方法,因為所繼承的HttpServlet及其父類都已經對構造方法進行了某些初始化,當不了解這些系統自帶的初始化,然后盲目使用構造方法,可能導致Servlet無法創建實例。
6、不要重寫service方法(在繼承HttpServlet的情況下),因為其內部有判別客戶端請求方法的邏輯和一些其他邏輯。
7、必須重寫doPost()或者是doGet()方法中的一個。
8、當想用一種邏輯去處理Get和Post請求,可以采用委托機制,在doPost方法內加入this.doGet(request,?response);?或者在doGet方法中加入this.doPost(request,?response);
9、繼承HttpServlet開發Servlet是最常用的方法。
10、get提交和post提交的區別
????10.1、從安全的角度看,get?<?post,因為get會把提交的信息顯示到地址欄。
????10.2、從提交內容大小看,?get?<?post,?get一般不要大于2k,post理論無限制,但是在實際開發中,建議不要大于64k
????10.3、從速度看,get?>?post,因為get僅僅只是獲取數據而已
11、Servlet的映射的后綴名不一定代表它就真的是那格式的文件。
?
?
?
----------參考《韓順平.細說Servlet》
?