Servlet
1 主要內容
2. IDEA的使用
IDEA 全稱 IntelliJ IDEA,由JetBrains公司開發,是java編程語言開發的集成環境。在業界被公認為最
好的java開發工具,尤其在智能代碼助手、代碼自動提示、重構、J2EE支持、各類版本工具(git、svn
等)、JUnit、CVS整合、代碼分析、 創新的GUI設計等方面的功能可以說是超常的。
2.1. IDEA的特色功能
- 智能選取
- 豐富的導航模式
- 歷史記錄功能
- 編碼輔助
- 靈活的排版功能
- 代碼檢查
- 完美的自動代碼完成
- 版本控制的支持
2.2. IDEA的基本設置
使用IDEA時,可以對它進行一些簡單的設置,通過設置用戶的偏好設置,可提高使用者的體驗感。
2.3. IDEA常用快捷鍵
| Alt+Insert | 生成代碼(如get, set方法,構造函數等) |
| Alt+↑/ ↓ | 在方法間快速定位 |
| Alt+【F3】 | 查找相同文本,并高亮顯示 |
| Ctrl+B | 快速打開光標處的類或方法 |
| Ctrl+J | 自動代碼(main方法) |
| Ctrl+N | 查找類 |
| Ctrl+Y | 刪除行 |
| Ctrl+D | 復制行 |
| Ctrl+O | 重寫方法 |
| Ctrl+E | 最近打開的文件 |
| Ctrl+F | 查找文本 |
| Ctrl+R | 替換文本 |
| Ctrl+P | 方法參數提示 |
| Ctrl+/ | 單行注釋// |
| Ctrl+Shift+/ | 多行注釋/* */ |
| Ctrl+Shift+N | 查找文件 |
| Ctrl+Alt+L | 格式化代碼 |
| Ctrl+Shift+↑/ ↓ | 代碼向上/向下移動 |
| Shift+F6 | 重構-重命名 |
3. HTTP協議
HTTP 協議(Hypertext Transfer Protocol, 超文本傳輸協議),是一個客戶端請求和響應的標準協
議,這個協議詳細規定了瀏覽器和萬維網服務器之間互相通信的規則。用戶輸入地址和端口號之后就可
以從服務器上取得所需要的網頁信息。
通信規則規定了客戶端發送給服務器的內容格式,也規定了服務器發送給客戶端的內容格式。客戶端
發送給服務器的格式叫"請求協議";服務器發送給客戶端的格式叫"響應協議"。
在瀏覽器中 F12可查看
3.1. 瀏覽器中的書寫格式
服務器端資源需要通過瀏覽器進行,此時由瀏覽器將我們給出的請求解析為滿足 HTTP 協議的格式并
發出。我們發出的請求格式需要按照瀏覽器規定的格式來書寫,在瀏覽器中書寫格式如下:
當瀏覽器獲取到信息以后,按照特定格式解析并發送即可。接收到服務器端給出的響應時,也按照
HTTP 協議進行解析獲取到各個數據,最后按照特定格式展示給用戶
3.2. HTTP協議的特點
POST。每種方法規定了客戶與服務器聯系的類型不同。由于 HTTP 協議簡單,使得HTTP服務器的
程序規模小,因而通信速度很快。
后,即斷開連接。采用這種方式可以節省傳輸時間。
HTTP1.1 版本后支持可持續連接。通過這種連接,就有可能在建立一個 TCP 連接后,發送請求并得到
回應,然后發送更多的請求并得到更多的回應.通過把建立和釋放 TCP 連接的開銷分攤到多個請求
上,則對于每個請求而言,由于 TCP 而造成的相對開銷被大大地降低了。而且, 還可以發送流水
線請求,也就是說在發送請求 1 之后的回應到來之前就可以發送請求 2.也可以認為,一次連接發送
多個請求,由客戶機確認是否關閉連接,而服務器會認為這些請求分別來自不同的客戶端。
如果后續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送 的數據量增大。另一方
面,在服務器不需要先前信息時它的應答就較快。
3.3. HTTP之URL
HTTP(超文本傳輸協議)是一個基于請求與響應模式的、應用層的協議,常基于 TCP 的連接方式,
絕大多數的 Web 開發,都是構建在 HTTP 協議之上的 Web 應用。
HTTP URL (URL 是一種特殊類型的 URI,包含了用于查找某個資源的足夠的信息)的格式 如下:
http://host[:port]/[abc_path] http://IP(主機名/域名):端口/訪問的資源路徑- http 表示要通過 HTTP 協議來定位網絡資源;
- host 表示合法的 Internet 主機域名或 者 IP 地址;
- port 指定一個端口號,為空則使用缺省端口 80;
- abs_path 指定請求資源的 URI; 如果 URL 中沒有給出 abs_path,那么當它作為請求 URI 時,必
須以“/”的形式給出,通常 這個工作瀏覽器自動幫我們完成。
3.4. HTTP 請求
HTTP 請求由三部分組成,分別是:請求行、請求頭、請求正文。
通過chrome瀏覽器, F12 —> Network查看。
Get 請求(沒有請求體)
Post 請求
請求行以一個方法符號開頭,以空格分開,后面跟著請求的 URI 和協議的版本。
格式如下:Method Request-URI HTTP-Version CRLF
Method 表示請求方法;
Request-URI 是一個統一資源標識符;
HTTP-Version 表示請 求的 HTTP 協議版本;
CRLF 表示回車和換行;
3.5. HTTP 響應
在接收和解釋請求消息后,服務器返回一個 HTTP 響應消息。HTTP 響應也是由三個部分組成,分別
是:狀態行、消息報頭、響應正文。
3.6. 消息頭
HTTP 消息由客戶端到服務器的請求和服務器到客戶端的響應組成。請求消息和響應消息都是由開始
行(對于請求消息,開始行就是請求行,對于響應消息,開始行就是狀態行), 消息報頭(可選),空
行(只有 CRLF 的行),消息正文(可選)組成。
每一個報頭域都是由 名字+“:”+空格+值 組成,消息報頭域的名字是大小寫無關的。
請求頭
請求報頭允許客戶端向服務器端傳遞請求的附加信息以及客戶端自身的信息。
Referer:該請求頭指明請求從哪里來 。
如果是地址欄中輸入地址訪問的都沒有該請求頭 地址欄輸入地址,通過請求可以看到,此時多了
一個 Referer 的請求頭,并且后面的值 為該請求從哪里發出。比如:百度競價,只能從百度來的才
有效果,否則不算;通常用來做統計工作、 防盜鏈。
響應頭
響應報頭允許服務器傳遞不能放在狀態行中的附加響應信息,以及關于服務器的信息和 對 Request
URI 所標識的資源進行下一步訪問的信息。
Location:Location響應報頭域用于重定向接受者到一個新的位置。
- Location響應報頭域,常用在更換域名的時候。
- Refresh:自動跳轉(單位是秒),可以在頁面通過meta標簽實現,也可在后臺實現。
4. Tomcat服務器
4.1. 什么是Tomcat
Tomcat 是一個符合 JavaEE WEB 標準的最小的 WEB 容器,所有的 JSP 程序一定要有 WEB 容器的支
持才能運行,而且在給定的 WEB 容器里面都會支持事務處理操作。
Tomcat 是由 Apache 提供的(www.apache.org)提供的可以用安裝版和解壓版,安裝版可以在服務
中出現一個 Tomcat 的服務,免安裝沒有,開發中使用免安裝版。 Tomcat 簡單的說就是一個運行 Java
的網絡服務器,底層是 Socket 的一個程序,它也是 JSP 和 Servlet 的一個容器。 Tomcat 是 Apache 軟
件基金會(Apache Software Foundation)的 Jakarta 項目中的一個核心項目,由 Apache、Sun和其
他一些公司及個人共同開發而成。
由于有了 Sun 的參與和支持,最新的 Servlet 和 JSP 規范總是能在 Tomcat 中得到體現。因為
Tomcat 技術先進、性能穩定,而且免費,因而深受 Java 愛好者的喜愛并得到了部分軟件開發商的認
可,成為目前比較流行的 Web 應用服務器。
Tomcat 服務器是一個免費的開放源代碼的 Web 應用服務器,屬于輕量級應用服務器, 在中小型系
統和并發訪問用戶不是很多的場合下被普遍使用,是開發和調試 JSP 程序的首選。 對于一個初學者來
說,可以這樣認為,當在一臺機器上配置好 Apache 服務器,可利用它響應 HTML(標準通用標記語言
下的一個應用)頁面的訪問請求。實際上 Tomcat 部分是 Apache 服務器的擴展,但它是獨立運行的,
所以當你運行 tomcat 時,它實際上作為一個與 Apache 獨立的進程單獨運行的。
當配置正確時,Apache 為 HTML 頁面服務,而 Tomcat 實際上是在運行 JSP 頁面和 Servlet。另外,
Tomcat 和 IIS 等 Web 服務器一樣,具有處理 HTML 頁面的功能,另外它還是 一個 Servlet 和 JSP 容
器,獨立的 Servlet 容器是 Tomcat 的默認模式。不過,Tomcat 處理靜態 HTML 的能力不如 Apache
服務器。目前 Tomcat 最新版本為 9.0。
4.2. 安裝Tomcat
運行 Tomcat 需要 JDK 的支持【Tomcat 會通過 JAVA_HOME 找到所需要的 JDK】。 安裝就是解壓縮
過程。啟動 Tomcat,能訪問則算安裝好了
解壓Tomcat8的壓縮包
啟動 Tomcat (在 tomcat 的安裝目錄下的 bin 目錄 使用命令行啟動 tomcat)
startup.bat啟動,shutdown.bat關閉
服務器啟動成功
1. Tomcat默認占用端口8080。(注意端口沖突問題) 2. 如果需要使用服務器,啟動成功后,該啟動窗口不要關閉。打開瀏覽器,輸入http://localhost:8080/ 訪問
調用 shutdown 命令關閉Tomcat服務器
4.3. Tomcat目錄結構
置主機(Host) ;web.xml 文件配置與 web 應用(web 應用相當于一個 web站點);tomcat
user.xml 配置用戶名密碼和相關權限
4.4. IDEA配置Tomcat
如果下面出現紅色提醒,可以直接點擊Fix在Deployment去設置
5. Servlet的實現
Servlet 是 Server 與 Applet 的縮寫,是服務端小程序的意思。使用 Java 語言編寫的服務器端程序,
可以生成動態的 WEB 頁,Servlet 主要運行在服務器端,并由服務器調用執行, 是一種按照 Servlet 標
準來開發的類。 是 SUN 公司提供的一門用于開發動態 Web 資源的技術。(言外之意:要實現 web 開
發,需要實現 Servlet 標準)
Servlet 本質上也是 Java 類,但要遵循 Servlet 規范進行編寫,沒有 main()方法,它的創建、使用、
銷毀都由 Servlet 容器進行管理(如 Tomcat)。(言外之意:寫自己的類,不用寫 main 方法,別人自動
調用)
Servlet 是和 HTTP 協議是緊密聯系的,其可以處理 HTTP 協議相關的所有內容。這也是 Servlet 應用
廣泛的原因之一。
提供了 Servlet 功能的服務器,叫做 Servlet 容器,其常見容器有很多,如 Tomcat, Jetty, WebLogic
Server, WebSphere, JBoss 等等。
5.1. 創建Web項目
選擇 “File” —> “New” —> “Project”,同上
5.2. Servlet的實現
5.2.1. 新建類
創建普通 java類
遵循servlet標準(繼承 HttpServlet)
pom.xml中添加(https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/3.1.0)
<dependencies><!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency></dependencies>注解可以設置多個(name無用)
@WebServlet(name="Servlet01",value={"/ser01",'/ser001'}) @WebServlet(name="Servlet01",urlPatterns={"/ser01",'/ser001'})項目結構如下:
5.2.2 發布項目并啟動服務
到此,需要編寫和配置的地方已經完成,項目已經完整了,但是如果需要外界能夠訪問, 還需要將項
目發布到服務器上并運行服務器,配置Tomcat,在瀏覽器查看結果.
5.3. Servlet的工作流程
操作)
瀏覽器
5.4. Servlet的生命周期
Servlet沒有 main()方法,不能獨立運行,它的運行完全由 Servlet 引擎來控制和調度。 所謂生命周
期,指的是 servlet 容器何時創建 servlet 實例、何時調用其方法進行請求的處理、 何時并銷毀其實例的
整個過程。
- 實例和初始化時機
當請求到達容器時,容器查找該 servlet 對象是否存在,如果不存在,則會創建實例并進行初始
化。
- 就緒/調用/服務階段
有請求到達容器,容器調用 servlet 對象的 service()方法,處理請求的方法在整個生命周期中可以被
多次調用; HttpServlet 的 service()方法,會依據請求方式來調用 doGet()或者 doPost()方法。但
是, 這兩個 do 方法默認情況下,會拋出異常,需要子類去 override。
- 銷毀時機
當容器關閉時(應用程序停止時),會將程序中的 Servlet 實例進行銷毀。
上述的生命周期可以通過 Servlet 中的生命周期方法來觀察。在 Servlet 中有三個生命周 期方法,
不由用戶手動調用,而是在特定的時機有容器自動調用,觀察這三個生命周期方法 即可觀察到
Servlet 的生命周期。
init 方法,在 Servlet 實例創建之后執行(證明該 Servlet 有實例創建了)
service 方法,每次有請求到達某個 Servlet 方法時執行,用來處理請求(證明該Servlet 進行服務了)
destroy 方法,Servlet 實例銷毀時執行(證明該 Servlet 的實例被銷毀了)
/*** 創建Servlet* 1.創建普通 java類* 2.遵循servlet標準(繼承 HttpServlet)* 3.重寫service方法(當前Servlet 類被訪問時自動調用service方法)* 4.設置對外訪問的路徑 (設置@WebServlet("/路徑"))**/ @WebServlet("/ser02") public class Servlet02 extends HttpServlet {/*** Servlet被實例化后(初始化),service方法可以被多次調用* @param req* @param resp* @throws ServletException* @throws IOException*/@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("服務調用了...");}/*** 當資源被訪問時自動調用初始化方法* 調用時只執行一次*/@Overridepublic void init() throws ServletException {System.out.println("初始化");}/*** 當服務器關閉時自動調用銷毀方法* 服務器關閉時只執行一次*/@Overridepublic void destroy() {System.out.println("銷毀");//初始化,服務調用了...,服務調用了...,服務調用了...,銷毀} }Servlet 的生命周期,簡單的概括這就分為四步:servlet 類加載–>實例化–>服務–>銷毀。
HttpServlet
6. HttpServletRequest對象
HttpServletRequest 對象:主要作用是用來接收客戶端發送過來的請求信息,例如:請求的參數,發
送的頭信息等都屬于客戶端發來的信息,service()方法中形參接收的是 HttpServletRequest 接口的實例
化對象,表示該對象主要應用在 HTTP 協議上,該對象是由 Tomcat 封裝好傳遞過來。
HttpServletRequest 是 ServletRequest 的子接口,ServletRequest 只有一個子接口,就是
HttpServletRequest。既然只有一個子接口為什么不將兩個接口合并為一個?
從長遠上講:現在主要用的協議是 HTTP 協議,但以后可能出現更多新的協議。若以后想要支持這種
新協議,只需要直接繼承 ServletRequest 接口就行了。
在 HttpServletRequest 接口中,定義的方法很多,但都是圍繞接收客戶端參數的。但是怎么拿到該對
象呢?不需要,直接在 Service 方法中由容器傳入過來,而我們需要做的就是取出對象中的數據,進行
分析、處理。
6.1. 接收請求
6.1.1. 常用方法
方法
6.1.2. 獲取請求參數
方法
- getParameter(name)獲取指定名稱的參數,返回字符串
- getParameterValues(String name)獲取指定名稱參數的所有參數值,返回數組
6.1.3 實例
http://localhost:8080/sw/ser03?uname=za&hobby=bb
@WebServlet("/ser03") public class Servlet03 extends HttpServlet {/*** Servlet被實例化后(初始化),service方法可以被多次調用* @param request* @param resp* @throws ServletException* @throws IOException*/@Overrideprotected void service(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {// 獲取客戶端請求的完整URL (從http開始,到?前面結束)String url = request.getRequestURL().toString();System.out.println("獲取客戶端請求的完整URL:" + url);// 獲取客戶端請求的部分URL (從站點名開始,到?前面結束)String uri = request.getRequestURI();System.out.println("獲取客戶端請求的部分URI:" + uri);// 獲取請求行中的參數部分String queryString = request.getQueryString();System.out.println("獲取請求行中的參數部分:" + queryString);// 獲取客戶端的請求方式String method = request.getMethod();System.out.println("獲取客戶端的請求方式:" + method);// 獲取HTTP版本號String protocol = request.getProtocol();System.out.println("獲取HTTP版本號:" + protocol);// 獲取webapp名字 (站點名)String webapp = request.getContextPath();System.out.println("獲取webapp名字:" + webapp);// 獲取指定名稱的參數,返回字符串String uname = request.getParameter("uname");System.out.println("uname的參數值:" + uname);// 獲取指定名稱參數的所有參數值,返回數組String[] hobbys = request.getParameterValues("hobby");System.out.println("獲取指定名稱參數的所有參數值:" + Arrays.toString(hobbys));} }獲取客戶端請求的完整URL:http://localhost:8080/sw/ser03
獲取客戶端請求的部分URI:/sw/ser03
獲取請求行中的參數部分:uname=za&hobby=bb
獲取客戶端的請求方式:GET
獲取HTTP版本號:HTTP/1.1
獲取webapp名字:/sw
uname的參數值:za
獲取指定名稱參數的所有參數值:[bb]
6.2. 請求亂碼問題
由于現在的 request 屬于接收客戶端的參數,所以必然有其默認的語言編碼,主要是由于在解析過程
中默認使用的編碼方式為 ISO-8859-1(此編碼不支持中文),所以解析時一定會出現亂碼。要想解決這種
亂碼問題,需要設置 request 中的編碼方式,告訴服務器以何種方式來解析數據。或者在接收到亂碼數
據以后,再通過相應的編碼格式還原。
方式一:
request.setCharacterEncoding("UTF-8");這種方式只針對 POST 有效(必須在接收所有的數據之前設定)
方式二:
new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");借助了String 對象的方法,該種方式對任何請求有效,是通用的。
Tomcat8起,以后的GET方式請求是不會出現亂碼的。
6.3. 請求轉發
請求轉發,是一種服務器的行為,當客戶端請求到達后,服務器進行轉發,此時會將請求對象進行保
存,地址欄中的 URL 地址不會改變,得到響應后,服務器端再將響應發送給客戶端,從始至終只有一個
請求發出。
實現方式如下,達到多個資源協同響應的效果。
request.getRequestDispatcher(url).forward(request,response); request.getRequestDispatcher("req_attr.jsp").forward(request,resp);6.4. request作用域
通過該對象可以在一個請求中傳遞數據,作用范圍:在一次請求中有效,即服務器跳轉有效。
// 設置域對象內容 request.setAttribute(String name, String value); request.setAttribute("msg","登錄成功"); // 獲取域對象內容 request.getAttribute(String name); // 刪除域對象內容 request.removeAttribute(String name);request 域對象中的數據在一次請求中有效,則經過請求轉發,request 域中的數據依然存在,則在
請求轉發的過程中可以通過 request 來傳輸/共享數據。
//設置作用域數據request.setAttribute("msg","登錄成功");//請求轉發request.getRequestDispatcher("req_attr.jsp").forward(request,resp); <%--Created by IntelliJ IDEA.User: 龍Date: 2022/4/19Time: 15:01To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body><%=request.getAttribute("msg")%> </body> </html>7. HttpServletResponse對象
Web服務器收到客戶端的http請求,會針對每一次請求,分別創建一個用于代表請求的 request 對象
和代表響應的 response 對象。
request 和 response 對象代表請求和響應:獲取客戶端數據,需要通過 request 對象;向客戶端輸
出數據,需要通過 response 對象。
HttpServletResponse 的主要功能用于服務器對客戶端的請求進行響應,將 Web 服務器處理后的結
果返回給客戶端。service()方法中形參接收的是 HttpServletResponse 接口的實例化對象,這個對象中
封裝了向客戶端發送數據、發送響應頭,發送響應狀態碼的方法。
7.1. 響應數據
接收到客戶端請求后,可以通過 HttpServletResponse 對象直接進行響應,響應時需要獲取輸出流。
有兩種形式:
getWriter() 獲取字符流**(只能響應回字符)**
getOutputStream() 獲取字節流**(能響應一切數據)**
響應回的數據到客戶端被瀏覽器解析。
注意:兩者不能同時使用。
@WebServlet("/ser01") public class Servlet01 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//resp.setHeader("content-type","text/html;charset=UTF-8"); // html,加入不亂碼//resp.setContentType("text/html;charset=UTF-8");//也不亂碼//獲取字符流PrintWriter writer = resp.getWriter();writer.write("zs");//zswriter.write("張三");//亂碼writer.flush();writer.close();//字節流/*ServletOutputStream os = resp.getOutputStream();os.write("zs".getBytes());//zsos.write("張三".getBytes());//張三os.flush();os.close();*/} }7.2. 響應亂碼問題
在響應中,如果我們響應的內容中含有中文,則有可能出現亂碼。這是因為服務器響應的數據也會經
過網絡傳輸,服務器端有一種編碼方式,在客戶端也存在一種編碼方式,當兩端使用的編碼方式不同時
則出現亂碼。
getWriter()的字符亂碼
對于 getWriter()獲取到的字符流,響應中文必定出亂碼,由于服務器端在進行編碼時默認會使用 ISO-
8859-1 格式的編碼,該編碼方式并不支持中文。
要解決該種亂碼只能在服務器端告知服務器使用一種能夠支持中文的編碼格式,比如我們通常用
的"UTF-8"。
兩端指定編碼后,亂碼就解決了。一句話:保證發送端和接收端的編碼一致
// 設置服務端的編碼 response.setCharacterEncoding("UTF-8"); // 設置客戶端的響應類型及編碼 response.setHeader("content-type","text/html;charset=UTF-8"); // 得到字符輸出流 PrintWriter writer = response.getWriter(); writer.write("<h2>你好</h2>");以上兩端編碼的指定也可以使用一句替代,同時指定服務器和客戶端
response.setContentType("text/html;charset=UTF-8");7.3. 重定向
重定向是一種服務器指導,客戶端的行為。客戶端發出第一個請求,被服務器接收處理后,服務器會
進行響應,在響應的同時,服務器會給客戶端一個新的地址(下次請求的地址
response.sendRedirect(url);),當客戶端接收到響應后,會立刻、馬上、自動根據服務器給的新地址
發起第二個請求,服務器接收請求并作出響應,重定向完成。
從描述中可以看出重定向當中有兩個請求存在,并且屬于客戶端行為。
// 重定向跳轉到index.jsp response.sendRedirect("index.jsp");7.4. 請求轉發與重定向的區別
response 重定向 request請求轉發之間的區別 1.請求轉發是服務端行為,重定向是客戶端行為 2.請求轉發地址欄不發生改變,重定向會發生改變 3.請求轉發地址欄發送 1次請求,重定向會發送 2次請求 4.請求轉發的數據(requset)可以共享,重定向不共享數據 5.請求轉發的起始路徑是從當前項目開始的,所以不能跳轉到百度以及外網重定向的起始路徑是http://開始的,所以跳轉到百度以及外網8. Cookie對象
Cookie是瀏覽器提供的一種技術,通過服務器的程序能將一些只須保存在客戶端,或者在客戶端進行
處理的數據,放在本地的計算機上,不需要通過網絡傳輸,因而提高網頁處理的效率,并且能夠減少服
務器的負載,但是由于 Cookie 是服務器端保存在客戶端的信息, 所以其安全性也是很差的。例如常見
的記住密碼則可以通過 Cookie 來實現。
有一個專門操作Cookie的類 javax.servlet.http.Cookie。隨著服務器端的響應發送給客戶端,保存
在瀏覽器。當下次再訪問服務器時把Cookie再帶回服務器。
Cookie 的格式:鍵值對用“=”鏈接,多個鍵值對間通過“;”隔開。
8.1. Cookie的創建和發送
通過 new Cookie(“key”,“value”);來創建一個 Cookie 對象,要想將 Cookie 隨響應發送到客戶端,需
要先添加到 response 對象中,response.addCookie(cookie);此時該 cookie 對象則隨著響應發送至了
客戶端。在瀏覽器上可以看見。
// 創建Cookie對象Cookie cookie = new Cookie("uname","張三");// 發送Cookie對象resp.addCookie(cookie);右鍵檢查,Application,Cookies
8.2. Cookie的獲取
在服務器端只提供了一個 getCookies()的方法用來獲取客戶端回傳的所有 cookie 組成的一個數組,如
果需要獲取單個 cookie 則需要通過遍歷,getName()獲取 Cookie 的名稱,getValue()獲取 Cookie 的
值。
// 獲取Cookie數組Cookie[] cookies = req.getCookies();// 判斷數組是否為空if (cookies != null && cookies.length > 0){for(Cookie cookie:cookies){if("uname".equals(cookie.getName())){System.out.println(cookie.getValue());}}}8.3. Cookie設置到期時間
除了 Cookie 的名稱和內容外,我們還需要關心一個信息,到期時間,到期時間用來指定該 cookie 何
時失效。默認為當前瀏覽器關閉即失效。我們可以手動設定 cookie 的有效時間(通過到期時間計算),
通過 setMaxAge(int time);方法設定 cookie 的最大有效時間,以秒為單位。
到期時間的取值
-
負整數
若為負數,表示不存儲該 cookie。
cookie 的 maxAge 屬性的默認值就是-1,表示只在瀏覽器內存中存活,一旦關閉瀏覽器窗口,那
么 cookie 就會消失。
-
正整數
若大于 0 的整數,表示存儲的秒數。
表示 cookie 對象可存活指定的秒數。當生命大于 0 時,瀏覽器會把 Cookie 保存到硬盤上,就算
關閉瀏覽器,就算重啟客戶端電腦,cookie 也會存活相應的時間。
-
零
若為 0,表示刪除該 cookie。
cookie 生命等于 0 是一個特殊的值,它表示 cookie 被作廢!也就是說,如果原來瀏覽器已經保存
了這個 Cookie,那么可以通過 Cookie 的 setMaxAge(0)來刪除這個 Cookie。 無論是在瀏覽器內
存中,還是在客戶端硬盤上都會刪除這個 Cookie。
8.4. Cookie的注意點
Cookie保存在當前瀏覽器中。
在一般的站點中常常有記住用戶名這樣一個操作,該操作只是將信息保存在本機上,換電腦以后這
些信息就無效了。而且 cookie 還不能跨瀏覽器。
Cookie存中文問題
Cookie 中不能出現中文,如果有中文則通過 URLEncoder.encode()來進行編碼,獲取時通過
URLDecoder.decode()來進行解碼。
同名Cookie問題
如果服務器端發送重復的Cookie那么會覆蓋原有的Cookie。
瀏覽器存放Cookie的數量
不同的瀏覽器對Cookie也有限定,Cookie的存儲有是上限的。Cookie是存儲在客戶端(瀏覽器)
的,而且一般是由服務器端創建和設定。后期結合Session來實現回話跟蹤。
8.5. Cookie的路徑
Cookie的setPath設置cookie的路徑,這個路徑直接決定服務器的請求是否會從瀏覽器中加載某些
cookie。
**情景一:**當前服務器下任何項目的任意資源都可獲取Cookie對象
**情景二:**當前項目下的資源可獲取Cookie對象 (默認不設置Cookie的path)
**情景三:**指定項目下的資源可獲取Cookie對象
**情景四:**指定目錄下的資源可獲取Cookie對象
如果我們設置path,如果當前訪問的路徑包含了cookie的路徑(當前訪問路徑在cookie路徑基礎上要
比cookie的范圍小)cookie就會加載到request對象之中。
cookie的路徑指的是可以訪問該cookie的頂層目錄,該路徑的子路徑也可以訪問該cookie。
總結:當訪問的路徑包含了cookie的路徑時,則該請求將帶上該cookie;如果訪問路徑不包含 cookie路徑,則該請求不會攜帶該cookie。
9. HttpSession對象
HttpSession對象是 javax.servlet.http.HttpSession 的實例,該接口并不像 HttpServletRequest 或
HttpServletResponse 還存在一個父接口,該接口只是一個純粹的接口。這因為 session 本身就屬于
HTTP 協議的范疇。
對于服務器而言,每一個連接到它的客戶端都是一個 session,servlet 容器使用此接口創建 HTTP 客
戶端和 HTTP 服務器之間的會話。會話將保留指定的時間段,跨多個連接或來自用戶的頁面請求。一個
會話通常對應于一個用戶,該用戶可能多次訪問一個站點。可以通過此接口查看和操作有關某個會話的
信息,比如會話標識符、創建時間和最后一次訪問時間。在整個 session 中,最重要的就是屬性的操
作。
session 無論客戶端還是服務器端都可以感知到,若重新打開一個新的瀏覽器,則無法取得之前設置
的 session,因為每一個 session 只保存在當前的瀏覽器當中,并在相關的頁面取得。
Session 的作用就是為了標識一次會話,或者說確認一個用戶;并且在一次會話(一個用戶的多次請
求)期間共享數據。我們可以通過 request.getSession()方法,來獲取當前會話的 session 對象。
// 如果session對象存在,則獲取;如果session對象不存在,則創建 HttpSession session = request.getSession();9.1. 標識符 JSESSIONID
Session 既然是為了標識一次會話,那么此次會話就應該有一個唯一的標志,這個標志就是
sessionId。
每當一次請求到達服務器,如果開啟了會話(訪問了 session),服務器第一步會查看是否從客戶端
回傳一個名為 JSESSIONID 的 cookie,如果沒有則認為這是一次新的會話,會創建 一個新的 session 對
象,并用唯一的 sessionId 為此次會話做一個標志。如果有 JESSIONID 這 個cookie回傳,服務器則會根
據 JSESSIONID 這個值去查看是否含有id為JSESSION值的session 對象,如果沒有則認為是一個新的會
話,重新創建一個新的 session 對象,并標志此次會話; 如果找到了相應的 session 對象,則認為是之
前標志過的一次會話,返回該 session 對象,數據達到共享。
這里提到一個叫做 JSESSIONID 的 cookie,這是一個比較特殊的 cookie,當用戶請求服務器時,如果
訪問了 session,則服務器會創建一個名為 JSESSIONID,值為獲取到的 session(無論是獲取到的還是
新創建的)的 sessionId 的 cookie 對象,并添加到 response 對象中,響應給客戶端,有效時間為關閉
瀏覽器。
所以 Session 的底層依賴 Cookie 來實現。
瀏覽器和后臺其中有一個關了,就會開啟新會話
// 如果session對象存在,則獲取;如果session對象不存在,則創建HttpSession session = req.getSession();String id = session.getId();System.out.println(id);//JSESSIONID AA558BD0F793D5EC4DA53D4B3BDEF965}9.2. session域對象
Session 用來表示一次會話,在一次會話中數據是可以共享的,這時 session 作為域對象存在,可以
通過 setAttribute(name,value) 方法向域對象中添加數據,通過 getAttribute(name) 從域對象中獲取
數據,通過 removeAttribute(name) 從域對象中移除數據。
當瀏覽器訪問后臺時,默認攜帶jsessionID,只有前臺后臺的JsessionID存在并且一致時才能接著會話
// 獲取session對象 HttpSession session = request.getSession(); // 設置session域對象 session.setAttribute("uname","admin"); // 獲取指定名稱的session域對象 String uname = (String) request.getAttribute("uname"); // 移除指定名稱的session域對象 session.removeAttribute("uname"); //cook07// 如果session對象存在,則獲取;如果session對象不存在,則創建HttpSession session = req.getSession();// 設置session域對象session.setAttribute("uname","張三");//cook06// 如果session對象存在,則獲取;如果session對象不存在,則創建HttpSession session = req.getSession();String id = session.getId();System.out.println(id);//AA558BD0F793D5EC4DA53D4B3BDEF965// 獲取指定名稱的session域對象String uname = (String) session.getAttribute("uname");System.out.println(uname);數據存儲在 session 域對象中,當 session 對象不存在了,或者是兩個不同的 session 對象時,數據
也就不能共享了。這就不得不談到 session 的生命周期。
9.3. session對象的銷毀
9.3.1. 默認時間到期
當客戶端第一次請求 servlet 并且操作 session 時,session 對象生成,Tomcat 中 session 默認的存
活時間為 30min,即你不操作界面的時間,一旦有操作,session 會重新計時。
那么 session 的默認時間可以改么?答案是肯定的。
可以在 Tomcat 中的 conf 目錄下的 web.xml 文件中進行修改。
<!-- session 默認的最大不活動時間。單位:分鐘。 --> <session-config> <session-timeout>30</session-timeout> </session-config>9.3.2. 自己設定到期時間
當然除了以上的修改方式外,我們也可以在程序中自己設定 session 的生命周期,通過
session.setMaxInactiveInterval(int) 來設定 session 的最大不活動時間,單位為秒。
// 獲取session對象 HttpSession session = request.getSession(); // 設置session的最大不活動時間 session.setMaxInactiveInterval(15); // 15秒當然我們也可以通過 getMaxInactiveInterval() 方法來查看當前 Session 對象的最大不活動時間。
// 獲取session的最大不活動時間 int time = session.getMaxInactiveInterval();9.3.3. 立刻失效
或者我們也可以通過 session.invalidate() 方法讓 session 立刻失效
// 銷毀session對象 session.invalidate();9.3.4. 關閉瀏覽器
從前面的 JESSIONID 可知道,session 的底層依賴 cookie 實現,并且該 cookie 的有效時間為關閉瀏
覽器,從而 session 在瀏覽器關閉時也相當于失效了(因為沒有 JSESSION 再與之對應)。
9.3.5. 關閉服務器
當關閉服務器時,session 銷毀。
Session 失效則意味著此次會話結束,數據共享結束。
10. ServletContext對象
每一個 web 應用都有且僅有一個ServletContext 對象,又稱 Application 對象,從名稱中可知,該對
象是與應用程序相關的。在 WEB 容器啟動的時候,會為每一個 WEB 應用程序創建一個對應的
ServletContext 對象。
該對象有兩大作用,第一、作為域對象用來共享數據,此時數據在整個應用程序中共享; 第二、該對
象中保存了當前應用程序相關信息。例如可以通過 getServerInfo() 方法獲取當前服務器信息 ,
getRealPath(String path) 獲取資源的真實路徑等。
10.1. ServletContext對象的獲取
獲取 ServletContext 對象的途徑有很多。比如
//創建servletContext對象的方式//通過 request 對象獲取ServletContext servletContext = request.getServletContext();// 通過 session 對象獲取ServletContext servletContext1 = request.getSession().getServletContext();//通過 servletConfig 對象獲取,在 Servlet 標準中提供了 ServletConfig 方法ServletContext servletContext2 = getServletConfig().getServletContext();//直接獲取,Servlet 類中提供了直接獲取 ServletContext 對象的方法ServletContext servletContext3 = getServletContext();常用方法
// 獲取項目存放的真實路徑 String realPath = request.getServletContext().getRealPath("/"); // 獲取當前服務器的版本信息 String serverInfo = request.getServletContext().getServerInfo() // 獲取項目存放的真實路徑 System.out.println(servletContext.getRealPath("/")); // 獲取當前服務器的版本信息 System.out.println(servletContext3.getServerInfo());10.2. ServletContext域對象
ServletContext 也可當做域對象來使用,通過向 ServletContext 中存取數據,可以使得整個應用程序
共享某些數據。當然不建議存放過多數據,因為 ServletContext 中的數據一旦存儲進去沒有手動移除將
會一直保存。
// 獲取ServletContext對象 ServletContext servletContext = request.getServletContext(); // 設置域對象 servletContext.setAttribute("name","zhangsan"); // 獲取域對象 String name = (String) servletContext.getAttribute("name"); // 移除域對象 servletContext.removeAttribute("name")Servlet的三大域對象
request域對象
在一次請求中有效。請求轉發有效,重定向失效。
session域對象
在一次會話中有效。請求轉發和重定向都有效,session銷毀后失效。
servletContext域對象
在整個應用程序中有效。服務器關閉后失效。
總結
- 上一篇: 概率分布 ---- 均匀分布
- 下一篇: VMware虚拟机部署k8s集群