目錄
一、什麼是Servlet
Servlet是Java Servlet的簡稱。Java Servlet 是運行在web服務器上的應用程序,簡單來說,其實它就是一個類,能夠被web服務器解析的一類。
總的來說,servlet的功能主要就是幹兩件事:
- 接收客戶端的請求;
- 響應服務器的響應
servlet遵循的是網絡協議中的 http協議 ;
剛開始可以這麼理解servlet的作用 :
二、使用IDEA創建一個servlet程序全過程圖解:
首先,在官網下載一個Tomcat:
解壓後,進入裏面的bin目錄,找到對應的啓動文件:
windows下的啓動文件是startup.bat
linux下的啓動文件爲startup.sh:
啓動一下,保證可以運行(不會閃退):
如果閃退的話,可能是你沒有配JAVA_HOME環境變量(網上有步驟),或者下的Tomcat的版本有問題也可能導致閃退。
然後就可以在IDEA下手動創建一個Servlet程序:
首先,創建一個空的maven項目
然後步驟就是正常創建項目的步驟...
然後在pom文件中將打包設置爲war包
接下來補全目錄結構:web項目的目錄結構爲:在main下面創建一個webapp,在webapp下面創建目錄WEB-INF,在WEB-INF中創建一個web.xml文件:
在補一下web.xml文件中的內容(直接在Tomcat安裝目錄裏的WEB-INF裏面的web.xml文件中將下面部分的內容複製過來在最後補一個</webapp>就行了,如下圖):
或者直接複製這個:
<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_4_0.xsd"
version="4.0"
metadata-complete="true">
<!--配置網站信息-->
</web-app>
web.xml是servlet的配置文件,Servlate裏面的全局參數,監聽器,過濾器都是在這裏面,所以非常重要,怎麼用後面再說!!!
然後再pom文件中導入Servlet需要的jar包:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
然後在:Run -> Edit Configurations--> 點左上角的 + -->然後在下拉框找到Tomcat server --> 選擇Local(表示本地) --> 然後name裏面自己填一個名字,在Application server裏面找到自己下載的Tomcat,這時右下角如果有一個紅色感嘆號的警告,點fix,選擇 xxxWar,然後點擊應用,並確定,這樣我們的Tomcat就算是配好了,具體過程如下圖:
確定之後:
然後點apply 然後OK。到這裏我們就可以創建Servlet項目了。
這時候在我們自己的包下創建一個servlet:
這個時候如果 左下角那個對號點不了,就重新導一下maven項目,如下圖:
創建好了之後,web.xml中會報錯,如下:
現在,要在web.xml中寫上:
關於映射路徑:
作用:在運行servlet的時候,首先它就會來web.xml文件中找對應的映射路徑,找到了纔可以運行
寫法:
- 精確匹配:/xxx
- /hello ——> http://localhost:8080/hello
- /fei/hello ——> http://localhost:8080/fei/hello
- 模糊匹配
- /* 任意路徑
- *,html 前面必須是任意路徑,但是後面必須以指定後綴名結束
- 最後:要注意不能即出現精確匹配又出現模糊匹配(例如:/hello/* 就是一種錯誤寫法【前面是精確匹配,後面是模糊匹配】)
- 也不能只寫一個 / ,因爲在Tomcat的web.xml中的缺省路徑就是一個 / ,如果在當前的wen.xml中找不到對應的動態資源文件,就會使Tomcat中的缺省路徑介入程序。
優先級比較:
- 精確匹配的優先級高於模糊匹配,在模糊匹配中,任意路徑的優先級高於以指定後綴結尾的路徑
再來看看新建的這個servlet的類,裏面默認覆寫兩個方法:
- doGet(requset, response) 表示 以get方式提交信息
- doPost(requset, response) 表示已post方式提交信息
一般情況下,我們常用doGet(), 在doPost中直接調用doGet就可以了。
簡單的使用案例:第一個servlet
點擊運行之後,由於我們這裏沒有配主頁,進來之後再瀏覽器會報錯(404 ),不過對於練習使用案例來說並不影響什麼。
這時候在地址欄輸入剛剛在web.xml中配置的:
回車之後就有東西了:
那麼要在瀏覽器輸入中文,要先設置編碼爲utf-8:
其實上面的setContentType中的ContentType就是http協議請求頭中的東西,我們可以在剛剛那個界面按F12(我用的瀏覽器是按F12,別的不清楚)就可以看到http 請求頭 / 響應頭 中的詳細信息:
從上面的方法我們可以看出,servlet好像和我們之前寫的程序不太一樣,它裏面main方法,但是也可以執行,那麼servlet到底是怎麼執行的呢???
三、servlet的執行流程:
3.1 引入概念 容器
什麼是容器:
從上面的步驟來看,我們會發現servlet和我們平時寫的程序不太一樣,因爲它沒有main方法,也可以執行,但是在以前不是說main方法是程序執行的入口嗎,那爲啥servlet就可以例外了呢;因爲servlet程序受控於另外一個java應用,這個應用就是容器,servlet程序就是在這個叫容器的東西里面運行的。在剛開始我們說的要下載的Tomcat,就是常見的容器中的一種,常見的還有 Jetty。
容器可以用來幹嘛:
容器是用來管理和運行servlet的
- 通信支持:利用容器提供的方法,能夠輕鬆讓servlet與web服務器對話,無需自己建立ServerSocket,監聽接口,吃昂見流等操作。容器知道自己與web服務器之間的協議,所有Servlet不必擔心Web服務器Web服務器(如 Apache,Nginx)與自己的Web之間的API,只需要考慮實現業務即可。
- 生命週期管理:容器控制着Servlet的生死。它會負責加載類,實例化,和初始化Servlet,調用Servlet的方法,並使Servlet實例能夠被垃圾回收。有了容器的控制,開發者就不需要考慮過多的資源管理。
- 多線程支持:容器會自動的爲它接收到的每一個Servlet請求創建一個新的java線程。針對客戶端請求,如果Servlet已經運行了完全相應的HTTP服務方法,該線程就會結束。這些並不意味着開發者不用考慮線程安全問題,它同樣會遇到同步問題。不過,由於服務器來創建和管理多線程來處理多個請求,開發者同樣會省去不少的工作。
- 聲明方式實現安全:利用容器,可以使用XML部署描述文件來配置安全性(Servlet3,0開始可以使用註解方式來描述),而不必將其硬編碼寫到Servlet或其他類中。
- JSP支持:容器可以將JSP代碼翻譯成Java代碼。
3.2 Servlet的執行流程:
- 在瀏覽器地址欄輸入:http://localhost:8080/hello ( 以 /hello 爲例 ),接下來,它會在網站配置web.xml中找到是否存在一個映射 url-pattern:/hello
- 如果找到,找對應的Servlet名稱:HelloServlet,在配置信息中找是否存在一個同名的Servlet
- 通過反射獲取到HelloServlet.class類對象
- 反射機制獲取到裏面的無參構造/成員方法/ ---->由Tomcat解析裏面的內容
- 使用HTTPServletResponse響應給用戶內容
- 如果第二步中在web.xml中沒有找到對應的映射路徑,就在webapp下尋找靜態資源,如果還沒有找到,就報404錯誤。
四、http協議:
4.1 常見的請求頭:
Accept | 瀏覽器接受的數據類型 |
Accept-Charset | 瀏覽器接受數據編碼格式 |
Accept-Encoding | 瀏覽器接受的數據壓縮格式 |
Accept-Language | 瀏覽器接受的語言 |
Host | 請求發出的主機和端口(必須) |
If-Modified-Since | 瀏覽器緩存的最後修改時間 |
Referer | 當前請求來自於哪裏 (防止非法鏈接) |
User-Agent | 當前用戶的瀏覽器類型 |
Cookie | 瀏覽器保存的cookie數據(會話管理) |
Connection |
瀏覽器和服務器的連接狀態。 close:關閉。keep-alive:保持連接 |
Date | 請求發出的時間 |
4.2常見的響應頭:
Location | 重定向的地址。結合302狀態使用完成重定向的效果 |
Server | 服務器的類型 |
Content-Encoding | 服務器發送給瀏覽器的數據壓縮格式 |
Content-Length | 服務器發送給瀏覽器的數據長度 |
Content-Language | 服務器支持的語言 |
Content-Type | 服務器發送給瀏覽器的數據類型和數據編碼格式 |
Last-Modified | 服務器資源的最後修改時間 |
Refresh | 定時刷新或者每隔n秒天真資源 |
Content-Disposition | 以下載方式打開資源 |
Set-Cookie | 服務器發送給瀏覽器的cookie數據 |
Expires(-1) |
通知瀏覽器不使用緩存 |
Connection (close/Keep-Alive) |
連接狀態 |
Date | 響應發出時間 |
4.3 通過servlet獲取http請求信息:
4.3.1 獲取請求行的信息
請求行:請求行由3部分組成
- 請求方法:get/post/...
- 資源的uri
- uri 和 url不一樣 ,url 是 uri 的子集
- uri是映射路徑 :/myFirstServlet
- url是統一資源定位符:http://localhost:8080/myFirstServlet
- 協議及版本
- http的版本:
- http1.0 只能請求一次
- http1.1 可以反覆請求
代碼獲取:
運行結果:
4.3.2 獲取請求頭基本信息
運行結果:
4.3.3 獲取表單參數的值
首先,寫一個簡單的html的form表單如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<h5>get提交方式</h5>
<form action="/RequsetDemo" method="get">
用戶名:<input type="text" name="userName"> <br/>
密 碼:<input type="password" name="password"> <br/>
性別:
<input type="radio" name="gender" value="男">男
<input type="radio" name="gender" value="女">女 <br>
愛好:
<input type="checkbox" name="hobby" value="zuqiu">zuqiu
<input type="checkbox" name="hobby" value="piqiu">piqiu
<input type="checkbox" name="hobby" value="pingpang">pingpang
<input type="checkbox" name="hobby" value="paobu">paobu
<input type="checkbox" name="hobby" value="papo">papo <br>
<input type="submit" value="提交">
</form>
<hr/>
<h5>post提交方式</h5>
<form action="/RequsetDemo" method="post">
用戶名:<input type="text" name="userName"> <br/>
密 碼:<input type="password" name="password"> <br/>
性別:
<input type="radio" name="gender" value="男">男
<input type="radio" name="gender" value="女">女 <br>
愛好:
<input type="checkbox" name="hobby" value="zuqiu">zuqiu
<input type="checkbox" name="hobby" value="piqiu">piqiu
<input type="checkbox" name="hobby" value="pingpang">pingpang
<input type="checkbox" name="hobby" value="paobu">paobu
<input type="checkbox" name="hobby" value="papo">papo <br>
<input type="submit" value="提交">
</form>
</body>
</html>
運行結果爲:
get 和 post 方式提交的數據,其獲取方法完全不一樣,獲取參數的方式如下:
- 獲取通過get方式提交的參數:
-
調用 getQueryString()方法獲取(Tomcat8.0以上的版本不用解決亂碼問題,在內部已經對編碼問題解決了)
-
- 獲取通過post方式提交的參數:
-
通過InputStream流讀取參數(post方式需要解決亂碼問題)
-
也有一種通用的獲取參數的方式:
-
requset.getParameter(String name) 返回 String value
- requset . getParameterNames() 返回 Enurmation / Iterator 迭代器
使用案例:
get方式:
運行結果:
post方式:
運行結果:
通用方式獲取:
運行結果:
4.3.4 非法鏈接
非法鏈接指的是
- 直接訪問下載地址的情況 referer = null;
- referer 請求頭中不包含廣告頁面 : referer.contains("adv.html"); 其中adv.html是廣告頁面
運行結果:
現在在webapp目錄下用HTML寫一個簡單的廣告頁面adv.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>adv</title>
</head>
<body>
廣告鏈接...
<a href="/GetReferer">跳轉到資源地址</a>
</body>
</html>
然後再來試試獲取referer
運行結果:
4.4 通過servlet獲取http響應信息
4.4.1 重定向
實現方式1:
- 設置響應狀態碼:response.setStatus(302);
- 設置響應頭:response.setHeader("location"," * .html");
實現方式2:
- response.sendRedirect("/ *. html") ;
運行結果:
4.4.2 定時刷新
- response.setHeader("refresh", “1”) ; // 表示每隔一秒刷新一次
- response.setHeader("refresh", “3;*.html”) ; // 表示格3秒跳轉到指定html頁面
4.4.3 設置響應類型
這個在上面已經用過了,比如:來在瀏覽器輸出中文的時候不會亂碼
response.setHeader("content-type", "text/html;charset=utf-8"); ==》簡寫方式: response.setContentType("text/html;charset=utf-8");
運行結果:
4.4.4 以下載的格式打開
response.setHeader("Content-Disposition", "attachment;filename="+file.getName());
public class DownLoadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
// 1、創建一個File對象
File file = new File("D:\\圖片\\1.jpg"); //這個是要下載的文件
// 2、設置響應頭
response.setHeader("Content-disposition", "attachment;filename="+file.getName());
// 3、創建一個字節流輸入對象
InputStream in = new FileInputStream(file);
// 4、獲取字節輸出流對象
OutputStream out = response.getOutputStream();
// 5、定義一個緩衝數組
byte[] buff = new byte[1024];
// 6、邊讀邊寫
int len = 0;
while ((len=in.read(buff)) != -1)
{
out.write(buff, 0, len);
}
// 7、關閉資源
in.close();
out.close();
}
}
運行結果: 下載文件