1. 程式人生 > 其它 >【JavaWeb-Servlet】筆記(3)--- 多個Servlet之間實現資料共享的四種方案: ServletContext / Cookie / HttpSession / HttpServletRequest

【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);
    }
}