- Servlet知識結構圖
Servlet是JavaWeb服務器端的程序,一般一個Servlet處理一種特定的請求。Servlet編寫好后,需要指定其所處理的請求的請求路徑,也可以認為Servlet是一種虛擬資源,可被客戶端請求
@WebServlet("/test") public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Writer writer = response.getWriter(); writer.append("Hello Java Web !"); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
Servlet接口被定義用來處理客戶端發來的請求,又針對HTTP協議提供了子類HttpServlet處理HTTP請求。也就是說Servlet在頂層設計上可以處理各種協議的請求,只不過目前僅僅應用在HTTP請求上
由於HTTP協議中請求方式主要有get和post,HttpServlet中就定義了doGet()和doPost()分別處理這兩種方式的請求。不過一般的業務邏輯使用get或者post都可以,而且處理方式一樣,所以一般都在一個方法中調用另一個方法,比如在doPost()中調用doGet()
- servlet工作原理
- 虛擬路徑
web 3.0版本之后,可以使用@WebServlet注解指定Servlet的虛擬路徑,比如@WebServlet("/test"),注意必須以斜線開頭。項目啟動時會掃描所有的@WebServlet注解並管理起來,可以為Servlet指定多個虛擬路徑,比如@WebServlet({ "/test", "/test1", "/test2" })
虛擬路徑支持通配符,比如 /user/* 、*.do ,但是不能是/user* 、/*.do等
特別的,使用單個 / 可以匹配所有請求
- Servlet對象的創建時機
Servlet對象默認會在第一次被請求時創建,也可以通過配置讓服務器啟動時就創建Servlet對象
@WebServlet(urlPatterns = "/test", loadOnStartup = 1) public class TestServlet extends HttpServlet { @Override public void init() throws ServletException { System.out.println("Servlet進行初始化"); }
當指定loadOnStartup時Servlet對象就會在服務器啟動時創建,取值為自然數,而且值越小優先級越高
- request請求對象
HttpServletRequest request是請求對象,內部封裝了客戶端請求的各種信息,主要有請求路徑、請求參數、請求頭、cookie等
request的方法 |
說明 |
getRequestURI() |
獲得請求路徑及其后面的查詢字符串(不包括主機和端口) |
getParameter(name) |
獲得以鍵值對形式提交的請求參數的值 |
getHeader(name) |
獲得請求頭信息 |
getPart(name) |
獲得上傳的文件 |
getCookies() |
獲得隨請求上傳的cookie信息 |
- response響應對象
HttpServletResponse response是響應對象,專門用來生成響應
response的方法 |
說明 |
setContentType(type) |
設置響應類型 |
getWriter() |
獲得Writer以便生成文本響應 |
getOutputStream() |
以便生成字節響應,比如文件下載等 |
sendRedirect(location) |
直接生成重定向響應 |
addCookie(cookie) |
在響應中添加cookie以便發送給客戶端 |
- <form>表單中請求路徑的寫法
一定要明白<form>表單是顯示在客戶端瀏覽器上的,也就是說<form>表單是客戶端的東西,不屬於服務器(雖然是從服務器獲得的)
相對路徑(不以斜線開頭的路徑)
相對路徑是相對於當前瀏覽器地址欄路徑來說的,即在地址欄父路徑的基礎上拼接相對路徑,比如地址欄中路徑為http://localhost:8080/webDemo/register.html ,那么<form action="register" 中的相對路徑register就表示http://localhost:8080/webDemo/register ,他們的父路徑相同
絕對路徑(以斜線開頭的路徑)
絕對路徑開頭的斜線表示根路徑,關鍵要明白根路徑的含義
對於<form action="/webDemo/register",根路徑表示服務器地址,即http://localhost:8080/ ,所以后面需要跟上項目名稱webDemo
當然,如果直接<form action="http://localhost:8080/webDemo/register" 寫全路徑也可以
- 轉發和重定向
轉發我們已經熟悉了,可以達到重用request中現有數據的效果
重定向,即response.sendRedirect("/userDemo/login.jsp") ,生成的響應信息為
HTTP/1.1 302 Found Location: /userDemo/login.jsp |
瀏覽器收到這個響應后就會重新訪問Location指定的URL,所以URL是在客戶端生效,所以斜線后面需要加上項目名稱
重定向時會再次發送新的請求,這樣一共就有2個請求,對服務器來說,第一個request里面的數據就不能再用了
重定向還有個效果就是會修改瀏覽器地址欄的URL
一般情況下,如果需要使用當前request中的數據就使用轉發,如果想修改地址欄URL就使用重定向
如果既想使用當前request數據,又想修改地址欄URL,可以使用URL重寫技術,也就是把request中的數據取出來拼接到URL后面,這樣重定向時瀏覽器再次請求時就會以請求參數的方式攜帶這些數據
- cookie
cookie技術可以把一些鍵值對數據存放到客戶端電腦上,方便實現一些功能效果
cookie生效分為兩個過程
1 服務器收到請求后,可以創建cookie信息,然后把cookie以響應頭的方式發生給瀏覽器,瀏覽器收到響應后,就會把響應頭中cookie信息保存到本地文件中
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Cookie cookie = new Cookie("email", "a@xxx.com"); cookie.setMaxAge(60 * 60 * 24 * 7);//設置最大存活時間,單位秒 response.addCookie(cookie); }
maxAge設置cookie在客戶端存活時間,單位秒,默認以及設置負值表示存活到瀏覽器關閉,0表示立即刪除
響應信息
HTTP/1.1 200 OK Set-Cookie: email="a@xxx.com"; Version=1; Max-Age=604800; Expires=Wed, 27-Sep-2017 07:01:02 GMT |
2 瀏覽器再次發送請求時,就會把本地文件中存儲的cookie信息放入請求頭中發送回服務器,服務器就可以取出請求頭中的cookie做一些事情
請求信息
GET /webDemo/processCookie HTTP/1.1 Cookie: email="a@xxx.com" |
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { System.out.println(cookie.getName() + " : " + cookie.getValue()); } } }
可見,對於cookie來說,客戶端只是暫存的地方,主要由服務器創建和使用
cookie一般用來實現記住用戶名、自動登錄、記住用戶網站風格設置等
- session
session表示會話,表示客戶端和服務器的一次“連接”,即從用戶打開瀏覽器訪問網站開始,到用戶關閉瀏覽器為止,就是一個session,期間所有對該網站的訪問都屬於同一個session
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); HttpSession session = request.getSession(); session.setAttribute("name", name); }
session在Servlet中表現為HttpSession的對象,session對象不應該手動創建,某用戶第一次調用request.getSession()時,服務器會創建出session對象,之后再次調用時,就會返回同一個session對象
session對象主要是作為web域對象來使用的,應該存放那些在多個請求之間都有效的數據,比如用戶登錄成功后把user對象存放到session中,這樣后面再請求時,servlet就可以從session中取出user的數據直接使用
session中還有一個比較重要的是sessionId,每個會話都會對應一個session對象,每個session對象都會擁有一個唯一sessionId,這個sessionId就是用來區分不同用戶會話的
session的實現借助了cookie技術,當創建session對象后,服務器會把session對象保存到一個map中,並且會把sessionId以cookie的形式發送到客戶端,這樣后面的請求都會攜帶這個sessionId cookie,服務器就會根據cookie里面的sessionId到map中去到對應的session對象
創建session時的響應信息
HTTP/1.1 200 OK Set-Cookie: JSESSIONID=74D7E93D031B34EDE9FD0D8EC652140D; Path=/webDemo/; HttpOnly |
以后再請求時的請求信息
GET /webDemo/session HTTP/1.1 Cookie: JSESSIONID=74D7E93D031B34EDE9FD0D8EC652140D; email="a@xxx.com" |
默認session對象的最大空閑時間是30分鍾,也就是說用戶如果30分鍾內沒有再次訪問網站,服務器就會銷毀該用戶對應的session對象,如果30分鍾后再次訪問時,服務器會創建新的session,新的sessionId cookie也會覆蓋原來的cookie
- ServletContext
ServletContext是Servlet的上下文對象,即管理着Servlet所處的環境,其實代表整個web項目
getContextPath() |
返回項目名稱(項目的虛擬路徑),比如 /webDemo |
getMimeType("a.txt") |
根據后綴名確定文件的MIME類型,比如text/plain |
getResourceAsStream("/el.jsp") |
返回項目內部資源的讀取流 |
getRealPath("/el.jsp") |
獲取項目內部資源文件的真實全路徑,比如D:\apache-tomcat-8.0.36\wtpwebapps\webDemo\el.jsp |
另外ServletContext還作為web域對象,存儲那些生命周期在服務器工作期間都有效的數據。但盡量不要把數據存放到該域對象中,因為如果用戶量很多同時訪問里面的數據時就會嚴重降低服務器性能
- Servlet的線程安全問題
每個Servlet只會創建一個對象,servlet對象可以同時處理多個請求,理論上Servlet的數據字段存在線程安全問題,但是進行線程同步會大大降低處理效率,所以為了避免線程安全問題並且不降低處理效率,就不能也不應該在Servlet內定義數據字段(其他非數據字段時可以的,比如service類型的字段)