【JavaWeb-Servlet】筆記(3)--- 多個Servlet之間實現資料共享的四種方案: ServletContext / Cookie / HttpSession / HttpServletRequest
前言:
多個Servlet之間資料共享實現方案:
1.資料共享:OneServlet工作完畢後,將產生資料交給TwoServlet來使用,這就叫做資料共享。
2.Servlet 規範中提供四種資料共享方案,通過一下四個介面/類來實現:
【ServletContext 介面】
【Cookie 類】
【HttpSession 介面】
【HttpServletRequest 介面】
ServletContext 介面:
1.介紹:
1)來自於Servlet規範中的一個介面,Tomcat負責提供這個介面實現類。
2)如果兩個Servlet來自於同一個網站,就可以通過彼此之間網站的 ServletContext
3)開發人員習慣於將 ServletContext 物件稱為【全域性作用域物件】。
2.工作原理:
每一個網站都存在一個全域性作用域物件,這個全域性作用域物件相當於一個 Map ,在這個網站中 OneServlet 可以將一個數據存入到全域性作用域物件中,這樣當前網站中其他 Servlet 此時都可以從全域性作用域物件得到這個資料進行使用。
3、工作原理圖:
4.全域性作用域物件生命週期:
【全域性作用域物件生命週期貫穿網站整個執行期間】
1)在Http伺服器啟動過程中,自動為當前網站在記憶體中建立一個全域性作用域物件。
2)在Http伺服器執行期間時,一個網站只有一個全域性作用域物件。
3)在Http伺服器執行期間,全域性作用域物件一直處於存活狀態。
4)在Http伺服器準備關閉時,負責將當前網站中全域性作用域物件進行銷燬處理。
5、舉個栗子:
程式碼:
package com.burnyouth.controller; import jakarta.servlet.*; import jakarta.servlet.http.*; import java.io.IOException; public class OneServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //通過請求物件向Tomcat索要當前網站的全域性作用域物件 ServletContext application = request.getServletContext(); //將資料新增到全域性作用域物件中,作為共享資料 application.setAttribute("key", 100); } }
package com.burnyouth.controller;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class TwoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//通過請求物件向Tomcat索要當前網站的全域性作用域物件
ServletContext application = request.getServletContext();
//從全域性作用域物件得到指定關鍵字對應的值
Integer integer = (Integer) application.getAttribute("key");
System.out.println(integer);
}
}
Cookie:
1.介紹:
1)Cookie 是來自於 Servlet 規範中的一個工具類,存在於 Tomcat 提供的 servlet-api.jar 中。
2)如果兩個 Servlet 來自於同一個網站,並且為同一個瀏覽器/使用者提供服務,此時可以藉助於 Cookie 物件進行資料共享。
3)Cookie存放當前使用者的私人資料,在共享資料過程中提高服務質量。
4) 在現實生活場景中,Cookie相當於使用者在服務端得到【會員卡】。
2.原理:
使用者通過瀏覽器第一次向 MyWeb 網站傳送請求申請,OneServlet 在執行期間建立一個 Cookie 儲存當前使用者相關資料,OneServlet工作完畢後,將 Cookie 寫入到【響應頭】交還給當前瀏覽器。瀏覽器收到響應包之後,會將 cookie 儲存在瀏覽器的快取中一段時間。在這段時間內,使用者通過【同一個瀏覽器】再次向【myWeb網站】傳送請求申請 TwoServlet 時。瀏覽器需要無條件的將 myWeb 網站之前推送過來的 Cookie,寫入到請求頭髮送過去,此時TwoServlet在執行時,就可以通過讀取請求頭中的 cookie 資訊,得到 OneServlet 提供的共享資料了。
3、工作原理圖:
4、程式碼實現:
xml 檔案:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<servlet>
<servlet-name>OneServlet</servlet-name>
<servlet-class>com.burnyouth.controller.OneServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>TwoServlet</servlet-name>
<servlet-class>com.burnyouth.controller.TwoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OneServlet</servlet-name>
<url-pattern>/one</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>TwoServlet</servlet-name>
<url-pattern>/two</url-pattern>
</servlet-mapping>
</web-app>
index.html 檔案(開卡充值頁面):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<font style="color: red;font-size: 50px">新會員申請辦卡</font>
<hr>
<form action="/myWeb/one">
<table border="1px">
<tr>
<td>使用者名稱</td>
<td><input type="text" name="userName"></td>
</tr>
<tr>
<td>預存金額</td>
<td><input type="text" name="money"></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="申請辦卡">
<input type="reset" value="清空">
</td>
</tr>
</table>
</form>
</body>
</html>
index_2.html 檔案(點餐劃卡消費頁面):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<font style="color: red;font-size: 40px">點餐頁面</font>
<hr>
<form action="/myWeb/two">
食物型別:
<input type="radio" name="food" value="澱粉腸">澱粉腸(1元)
<input type="radio" name="food" value="小餅">小餅(1元)
<input type="radio" name="food" value="烤冷麵">烤冷麵(3元)
<input type="submit" value="劃卡消費">
</form>
</body>
</html>
OneServlet.java 檔案(實現開卡充值功能):
package com.burnyouth.controller;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class OneServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName, money;
//呼叫請求物件讀取【請求頭】引數資訊
userName = request.getParameter("userName");
money = request.getParameter("money");
//開卡
Cookie cookie1 = new Cookie("userName",userName);
Cookie cookie2 = new Cookie("money", money);
//髮卡,將Cookie寫入響應頭交給瀏覽器
response.addCookie(cookie1);
response.addCookie(cookie2);
//通知瀏覽器將【點餐頁面】內容寫入到響應體交給瀏覽器
request.getRequestDispatcher("/index_2.html").forward(request,response);
}
}
TwoServlet.java 檔案(實現劃卡消費功能):
package com.burnyouth.controller;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
public class TwoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int dianfenchang_money = 1;
int xiaobing_money = 1;
int kaolengmian_money = 3;
int money = 0;
int spending = 0,balance = 0;
String food,userName = null;
Cookie cards[] = null;
Cookie newCookie = null;
//切記,在得到輸出流之前一定要設定正確的響應頭的content-type屬性
//response.setContentType("text/html;charset:utf-8");
PrintWriter out = response.getWriter();
//讀取請求頭引數資訊,得到使用者點餐食物型別
food = request.getParameter("food");
//讀取請求中的Cookie
cards = request.getCookies();
//刷卡消費
for (Cookie card:cards) {
String key = card.getName();
String value = card.getValue();
if ("userName".equals(key)) {
userName = value;
} else if ("money".equals(key)) {
money = Integer.valueOf(value);
if ("澱粉腸".equals(food)) {
if (dianfenchang_money > money) {
out.print("使用者:"+userName+"餘額不足,請充值!");
}else {
balance = money - dianfenchang_money;
newCookie = new Cookie("money",balance+"");
spending = dianfenchang_money;
}
} else if ("小餅".equals(food)) {
if (xiaobing_money > money) {
out.print("使用者:" + userName + "餘額不足,請充值!");
} else {
balance = money - xiaobing_money;
newCookie = new Cookie("money",balance+"");
spending = xiaobing_money;
}
} else if ("烤冷麵".equals(food)) {
if (kaolengmian_money > money) {
out.print("使用者:" + userName + "餘額不足,請充值!");
} else {
balance = money-kaolengmian_money;
newCookie = new Cookie("money",balance+"");
spending = kaolengmian_money;
}
}
}
}
//將使用者的會員卡返還給使用者
response.addCookie(newCookie);
//將消費記錄寫入到響應體中
out.print("使用者:"+userName+",消費:"+spending+",餘額:"+balance);
}
}
5、Cookie銷燬時機:
1)預設情況下,Cookie物件存放在瀏覽器的快取中。因此只要瀏覽器關閉,Cookie物件就被銷燬掉。
2)在手動設定情況下,可以要求瀏覽器將接收的 Cookie 存放在客戶端計算機上硬碟上,同時需要指定 Cookie 在硬碟上存活時間。在存活時間範圍內,關閉瀏覽器關閉客戶端計算機,關閉伺服器,都不會導致 Cookie 被銷燬。在存活時間到達時,Cookie 自動從硬碟上被刪除。
//指定cookie在硬碟中存活時間,要在cookie物件建立之後
cookie.setMaxAge(60); //cookie在硬碟上存活1分鐘
//指定cookie在硬碟中存活時間,把cookie寫入到響應頭之前
HttpSession 介面:
1.介紹:
1)HttpSession 介面是來自於 Servlet 規範下的一個介面,其實現類由Http伺服器提供。Tomcat 提供的實現類存在於 servlet-api.jar 中。
2)如果兩個Servlet來自於同一個網站,並且為同一個瀏覽器/使用者提供服務,此時就可以藉助於HttpSession物件來進行資料共享。
3)開發人員習慣於將HttpSession介面修飾物件稱為【會話作用域物件】。
2.HttpSession 與 Cookie 的區別:
1)儲存位置:
Cookie:存放在客戶端計算機(瀏覽器記憶體/硬碟)
HttpSession:存放在服務端計算機記憶體
2)儲存的資料型別:
Cookie 物件儲存共享資料型別只能是 【String】
HttpSession 物件可以儲存任意型別的共享資料 【Object】
3)儲存資料數量:
一個 Cookie 物件只能儲存一個共享資料
HttpSession 使用 map 集合儲存共享資料,所以可以儲存任意數量共享資料。
4)參照物:
Cookie 相當於客戶在服務端的【會員卡】。
HttpSession 相當於客戶在服務端的【私人保險櫃】。
3.HttpSession 工作原理圖:
4、程式碼實現:
xml 檔案:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<servlet>
<servlet-name>OneServlet</servlet-name>
<servlet-class>com.burnyouth.controller.OneServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>TwoServlet</servlet-name>
<servlet-class>com.burnyouth.controller.TwoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OneServlet</servlet-name>
<url-pattern>/one</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>TwoServlet</servlet-name>
<url-pattern>/two</url-pattern>
</servlet-mapping>
</web-app>
index.html 檔案(操作購物車頁面):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1px">
<tr>
<td>商品名稱</td>
<td>單價</td>
<td>供應商</td>
<td>操作</td>
</tr>
<tr>
<td>肥皂</td>
<td>5</td>
<td>印度</td>
<td><a href="/myWeb/one?goodsName=肥皂">放入購物車</a> </td>
</tr>
<tr>
<td>圓珠筆</td>
<td>1</td>
<td>廣源文體商店</td>
<td><a href="/myWeb/one?goodsName=圓珠筆">放入購物車</a> </td>
</tr>
<tr>
<td>水杯</td>
<td>1000</td>
<td>上海迪士尼樂園</td>
<td><a href="/myWeb/one?goodsName=水杯">放入購物車</a> </td>
</tr>
<tr align="center">
<td colspan="4">
<a href="/myWeb/two">檢視購物車</a>
</td>
</tr>
</table>
</body>
</html>
OneServlet.java 檔案(實現將商品放入購物車功能):
package com.burnyouth.controller;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class OneServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String goodsName;
//呼叫請求物件,獲取請求頭引數(得到商品名稱)
goodsName = request.getParameter("goodsName");
//呼叫請求物件,向Tomcat索要當前使用者在伺服器的私人保險櫃
HttpSession session = request.getSession();
//將使用者選購商品新增到當前使用者的私人保險櫃中
Integer goodsNum = (Integer) session.getAttribute(goodsName);
if (goodsNum == null) {
session.setAttribute(goodsName, 1);
} else {
session.setAttribute(goodsName,goodsNum+1);
}
}
}
TwoServlet.java 檔案(實現檢視購物車功能):
package com.burnyouth.controller;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
public class TwoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//呼叫請求物件,向Tomcat索要當前使用者的私人保險櫃
HttpSession session = request.getSession();
//將session中的所有key讀取出來,存放到一個列舉物件中
Enumeration goodsNames = session.getAttributeNames();
while (goodsNames.hasMoreElements()) {
String goodsName = (String) goodsNames.nextElement();
int goodsNum = (int) session.getAttribute(goodsName);
System.out.println("商品名稱:"+goodsName+",商品數量:"+goodsNum);
}
}
}
5、Http 伺服器如何將使用者與 HttpSession 關聯起來的?
6、getSession( ) 與 getSession(false):
1)getSession( ):
如果當前使用者在服務端已經擁有了自己的私人儲物櫃,要求tomcat將這個私人儲物櫃進行返回;如果當前使用者在服務端尚未擁有自己的私人儲物櫃,要求tocmat為當前使用者建立一個全新的私人儲物櫃。
2)getSession(false):
如果當前使用者在服務端已經擁有了自己的私人儲物櫃,要求tomcat將這個私人儲物櫃進行返回;如果當前使用者在服務端尚未擁有自己的私人儲物櫃,此時Tomcat將返回null。
7、HttpSession銷燬時機:
1)使用者與 HttpSession 關聯時使用的 Cookie 只能存放在瀏覽器快取中。
2)在瀏覽器關閉時,意味著使用者與他的 HttpSession 關係被切斷。
3)由於 Tomcat 無法檢測瀏覽器何時關閉,因此在瀏覽器關閉時並不會導致Tomcat將瀏覽器關聯的 HttpSession 進行銷燬。
4)為了解決這個問題,Tomcat為每一個HttpSession物件設定【空閒時間】,這個空閒時間預設為30分鐘,如果當前 HttpSession 物件空閒時間達到30分鐘。此時Tomcat認為使用者已經放棄了自己的HttpSession,此時Tomcat就會銷燬掉這個HttpSession。
8、如何手動設定 HttpSession 空閒時間:
當前網站/web/WEB-INF/web.xml:
<session-config>
<session-timeout>5</session-timeout> <!--當前網站中每一個session最大空閒時間5分鐘-->
</session-config>
HttpServletRequest 介面實現資料共享:duo
1.介紹:
1) 在同一個網站中,如果兩個Servlet之間通過【請求轉發】方式進行呼叫,彼此之間共享同一個請求協議包。而一個請求協議包只對應一個請求物件,因此servlet之間共享同一個請求物件,此時可以利用這個請求物件在兩個Servlet之間實現資料共享。
2) 在請求物件實現Servlet之間資料共享功能時,開發人員將請求物件稱為【請求作用域物件】。
2.程式碼實現:
【OneServlet 通過請求轉發申請呼叫 TwoServlet 時,需要給 TwoServlet 提供共享資料】
程式碼:
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_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>OneServlet</servlet-name>
<servlet-class>com.bjpowernode.controller.OneServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>TwoServlet</servlet-name>
<servlet-class>com.bjpowernode.controller.TwoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OneServlet</servlet-name>
<url-pattern>/one</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>TwoServlet</servlet-name>
<url-pattern>/two</url-pattern>
</servlet-mapping>
</web-app>
OneServlet.java:
package com.burnyouth.controller;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class OneServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.將資料新增到請求作用域物件,作為共享資料
request.setAttribute("key1", "hello World");
//2.代替瀏覽器,向Tomcat索要TwoServlet來完成剩餘任務
request.getRequestDispatcher("/two").forward(request, response);
}
}
TwoServlet.java:
package com.burnyouth.controller;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class TwoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 從同一個請求作用域物件得到OneServlet寫入到共享資料
String value =(String)request.getAttribute("key1");
System.out.println("TwoServlet得到共享資料 "+value);
}
}