Servlet 是運行在服務端的Java小程序,是sun公司提供一套規范(接口),用來處理客戶端請求、響應給瀏覽器的動態資源。但servlet的實質就是java代碼,通過java的API,動態的向客戶端輸出內容。
servlet規范:包含三個技術點,它們是 servlet技術;filter(過濾器)技術;listener(監聽器)技術。
Servlet快速入門
實現步驟:
- 創建類實現Servlet接口
- 覆蓋尚未實現的方法---service方法
- 在web.xml進行servlet的配置
但在實際開發中,我們不會直接去實現Servlet接口,因為那樣需要覆蓋的方法太多, 我們一般創建類繼承HttpServlet。
實現步驟:
- 創建類繼承HttpServlet類
- 覆蓋doGet和doPost
- 在web.xml中進行servlet的配置
畫圖描述整個訪問過程:
下面來看看Servlet長什么樣子
代碼演示:
public class AServlet extends HttpServlet { }
發現HttpServlet在IDEA中不能導包,百度了一下,IntelliJ IDEA 沒有導入 servlet-api.jar 這個jar包,需要你手動導入支持。具體導包過程如下:
點擊右上方那個藍色按鈕(project structure 項目結構)——>點擊Libraries——>點擊上面的加號——>點擊Java
然后再彈出框中找到Tomcat安裝路徑下的lib文件夾中的Servlet.api這個文件,添加就好了。
在Intellij idea中快速重寫HttpServlet
鼠標左擊以確定代碼插入的位置,使用快捷鍵CTRL+O,會彈出窗口讓選擇某個方法,我們選擇覆蓋doGet和doPost方法,然后輸出一句話。

package servletDemo; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * Created by Administrator on 2017/7/21. */
public class AServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("My First Servlet"); } }
配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<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_1.xsd" version="3.1">
<servlet>
<servlet-name>AServlet</servlet-name>
<servlet-class>servletDemo.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>
</servlet-mapping>
</web-app>
運行報錯:Tomcat啟動服務報錯:Unknown version string [3.1]. Default version will be used.解決方式參考這里
然后運行,在瀏覽器輸入:http://localhost:8080/AServlet,界面出現:
My First Servlet
到此,我們的第一個Servlet就成功了。
Servlet的API(生命周期)
Servlet接口中的方法

package servlet.demo; import javax.servlet.*; import java.io.IOException; /** * Created by yang on 2017/7/23. */
public class SecondServlet implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
- init(ServletConfig config):servlet對象創建的時候執行,ServletConfig 代表的是該servlet對象的配置信息
- service(ServletRequest request,ServletResponse response):每次請求都會執行
ServletRequest :代表請求,ServletRequest 內部封裝的是 http請求的信息
ServletResponse :代表響應,封裝的是響應的信息
- destroy():servlet銷毀的時候執行
- getServletInfo: 獲得servlet的信息(版本,作者,版權..),沒什么用.
- getServletConfig:返回servletConfig對象.
HttpServlet類的方法

package servlet.demo; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * Created by yang on 2017/7/23. */
public class ServletDemo03 extends HttpServlet{ @Override public void init(ServletConfig config) throws ServletException { super.init(config); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doGet(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } @Override public void destroy() { super.destroy(); } }
- init()
- doGet(HttpServletRequest request,HttpServletResponse response)
- doPost(HttpServletRequest request,HttpServletResponse response)
- destroy()
Servlet的生命周期
Servlet何時創建?默認第一次訪問servlet時創建該對象
Servlet何時銷毀?服務器關閉servlet就銷毀了
每次訪問必然執行的方法?service(ServletRequest req, ServletResponse res)方法
問題:對XXXServlet進行了10次訪問,init(),destory(),service(),doGet(),doPost() 一共執行力多少次?request對象創建幾個?response創建幾個?
答案:init(),1次;destory(),服務器沒有關閉, 不執行;service(),10次;request對象創建10個;response創建10個
Servlet的配置
基本配置
其中url-pattern的配置方式:
- 完全匹配 訪問的資源與配置的資源完全相同才能訪問到
- 目錄匹配 格式:/虛擬的目錄../* ,*代表任意
- 擴展名匹配 格式:*.擴展名
注意:1、關於路徑,配置的路徑匹配范圍越大優先級越低;2、目錄匹配與擴展名匹配不要混用,比如: /aaa/bbb/*.abcd(這是錯誤的)
ServletConfig對象
ServletConfig封裝了servlet在web.xml中的配置.
比如web.xml參數配置如下:
<init-param>
<param-name>name</param-name>
<param-value>tom</param-value>
</init-param>
方法:
//獲得servlet的name(獲得配置文件中<servlet-name>元素的內容) String servletName =getServletConfig().getServletName(); //獲取init-param中的所有參數(返回所有<param-name> ) Enumeration<String> en = getServletConfig().getInitParameterNames(); while(en.hasMoreElements()){ String key = en.nextElement(); //根據鍵獲取值(根據<init-param>中的<param-name>獲得</param-value>
String value = getServletConfig().getInitParameter(key);) res.getWriter().print(key+"==>"+value+"<br/>"); }
服務器啟動實例化Servlet配置
Servlet何時創建:默認第一次訪問時創建。為什么是默認?當在servlet的配置時,加上一個配置 <load-on-startup> ,servlet對象在服務器啟動時就創建。
<servlet>
<servlet-name>abc</servlet-name>
<servlet-class>com.itheima.servlet.QuickStratServlet</servlet-class>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql:///mydb</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>abc</servlet-name>
<url-pattern>/quickStratServlet</url-pattern>
</servlet-mapping>
1、load-on-startup元素標記容器是否在啟動的時候就加載這個servlet(實例化並調用其init()方法)。
2、它的值必須是一個整數,表示servlet應該被載入的順序
3、當值為0或者大於0時,表示容器在應用啟動時就加載並初始化這個servlet;
4、當值小於0或者沒有指定時,則表示容器在該servlet被選擇時才會去加載。
5、正數的值越小,該servlet的優先級越高,應用啟動時就越先加載。
6、當值相同時,容器就會自己選擇順序來加載。
所以,<load-on-startup>x</load-on-startup>,中x的取值1,2,3,4,5代表的是優先級,而非啟動延遲時間。欲知更多請參考這里
缺省Servlet
可以將url-pattern配置一個/,代表該servlet是缺省的servlet。什么是缺省的servlet?當你訪問資源地址所有的servlet都不匹配時 , 缺省的servlet負責處理。其實,web應用中所有的資源的響應都是servlet負責,包括靜態資源。
歡迎頁面
ServletContext對象
ServletContext代表的是一個web應用的環境(上下文)對象,ServletContext對象內部封裝是該web應用的信息,ServletContext對象一個web應用只有一個。那么一個web應用有幾個servlet對象?很多個。
ServletContext對象的生命周期
創建:該web應用被加載(服務器啟動或發布web應用(前提,服務器為啟動狀態))
銷毀:web應用被卸載(服務器關閉,移除該web應用)
獲得ServletContext對象
1、ServletContext servletContext = config.getServletContext();
2、ServletContext servletContext = this.getServletContext();
ServletContext的作用
1、獲得web應用全局的初始化參數,方法:
getInitParameterNames(); ==> 獲得所有鍵 getInitParameter(key); ==> 根據鍵獲得對應的值
比如:web.xml中配置初始化參數
<!--配置全局的初始化參數-->
<context-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</context-param>
則可以通過context對象獲得參數
ServletContext context= getServletContext(); String initValue= context.getInitParameter("driver"); resp.getWriter().print(initValue);//com.mysql.jdbc.Driver
2、獲得web應用中任何資源的絕對路徑,此功能很重要。方法:
getRealPath ==> 通過相對路徑獲得絕對路徑 getResourceAsStream ==> 根據相對路徑獲得指定資源流
context.getRealPath(相對於該web應用的相對地址);
ServletContext sc = getServletContext(); //getResourceAsStream ==> 填寫相對路徑即可, 相對的是webRoot下
InputStream is = sc.getResourceAsStream("/WEB-INF/students.xml"); System.out.println(is);//java.io.ByteArrayInputStream@2d83e895
String path = sc.getRealPath("/WEB-INF/students.xml"); System.out.println(path);
//F:\編程語言\Java\Project\Tools\apache-tomcat-7.0.52\webapps\Day07-servlet\WEB-INF\students.xml
Set set = sc.getResourcePaths("/"); for(Object obj : set){ System.out.println(obj); } // /index.jsp // /WEB-INF/ // /MyHtml.html // /META-INF/
String path2= sc.getResource("/WEB-INF/students.xml").getPath(); System.out.println(path2); // /localhost/Day07-servlet/WEB-INF/students.xml
//獲得lib目錄下的資源
getServletContext().getRealPath("/WEB-INF/lib/students.xml"); //獲得src下的資源==> 獲得classes目錄下的資源
getServletContext().getRealPath("/WEB-INF/classes/students.xml"); //獲得cn.itcast.servlet.servlet_context包下的資源
getServletContext().getRealPath("/WEB-INF/classes/cn/itcast/servlet/servlet_context/students.xml"); //--------------------------------------------------------------------------- //如果獲得的是包下的,那么使用上面的方式太麻煩了.可以使用以下方式: //一:使用getClass().getResourceAsStream方法,相對路徑分為兩種情況 //1: 加"/" ==> 相對的是classes目錄 //2: 不加"/" ==>相對的是本類當前目錄
InputStream is = this.getClass().getResourceAsStream("students.xml"); System.out.println(is);
//二:使用this.getClass().getClassLoader().getResourceAsStream("");獲得 //只有一個相對路徑 ==> 就是相對於 classes目錄
InputStream is2 = this.getClass().getClassLoader().getResourceAsStream("students.xml"); System.out.println(is2); //注意:
//1、使用類和類加載器加載資源文件時,jvm運行期間只加載一次.一旦加載完畢后,就會存放在虛擬機內存中,直到虛擬機關閉,所以文件路徑更改,也還是之前的路徑,可以使用下面的代碼可以解決這個問題.
String path = this.getClass().getClassLoader().getResource("students.xml").getPath(); File file = new File(path.substring(1, path.length())); System.out.println(path); //getClassLoader()原本是用來加載.class文件的, 所以緩存設計的很小.不要用他加載一些別較大的資源.
3、ServletContext是一個域對象,此功能很重要。
什么是域對象?什么是域?存儲數據的區域就是域對象。
ServletContext域對象的作用范圍是整個web應用(所有的web資源都可以隨意向 servletcontext域中存取數據,數據可以共享)
域對象的通用的方法
放入鍵值對 setAttribute(key,value)
通過鍵取值 getAttribute(key)
通過鍵刪除 removeAttribute(key)
遍歷所有鍵 getAttributeNames()
//通過servletContext設置值
sc.setAttribute("bag", "Calvin Klein"); sc.setAttribute("car", "BMW"); sc.setAttribute("passport", "HAWAII"); //通過servletContext取值
String bag = (String) sc.getAttribute("bag"); //不喜歡,扔掉(刪除)
sc.removeAttribute("bag"); //遍歷
Enumeration<String> en = sc.getAttributeNames(); while(en.hasMoreElements()){ String key = en.nextElement(); Object value = sc.getAttribute(key); System.out.println(key +"==>"+value); }