国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

這篇具有很好參考價(jià)值的文章主要介紹了B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

目錄
  • B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)
    • 每博一文案
    • 1. session 會(huì)話機(jī)制的概述
    • 2. 什么是 session 的會(huì)話
    • 3. session 的作用
    • 4. session 的實(shí)現(xiàn)原理解釋
    • 5. 補(bǔ)充: Cookie禁用了,session還能找到嗎 ?
    • 6. 總結(jié)一下到目前位置我們所了解的域?qū)ο螅?/li>
    • 7. oa 項(xiàng)目的優(yōu)化體驗(yàn):使用上 session 會(huì)話機(jī)制:
    • 8. 總結(jié):
    • 9. 最后:

每博一文案

你跑得快,22歲有個(gè)家,身邊全是贊嘆,你跑得慢,30歲還在路上追求夢(mèng)想。有的人為了車,房拼了一輩子,
有的人買輛摩托車走遍了大好江山。你想成為怎樣的人,過怎樣的生活,只要你不后悔就行。
并不是所有人都能在早上七點(diǎn)鐘起床的,也別拿一碗飯來衡量一個(gè)人的胃口的大小。
有的人喜歡狼吞虎咽,有的人喜歡細(xì)嚼慢咽,允許別人做,別人允許自己做自己。
一歲有一歲的味道,跟著自己的心就好。不是所有選擇都要做正確的選項(xiàng)的,只要你想,你可以選擇
你喜歡的選項(xiàng)。沿途的花會(huì)一直開,以后的路也是,祝你祝我。

1. session 會(huì)話機(jī)制的概述

在Web應(yīng)用程序中,我們經(jīng)常要跟蹤用戶身份。當(dāng)一個(gè)用戶登錄成功后,如果他繼續(xù)訪問其他頁面,Web程序如何才能識(shí)別出該用戶身份?

因?yàn)?strong>HTTP協(xié)議是一個(gè)無狀態(tài)協(xié)議,即Web應(yīng)用程序無法區(qū)分收到的兩個(gè)HTTP請(qǐng)求是否是同一個(gè)瀏覽器發(fā)出的。為了跟蹤用戶狀態(tài),服務(wù)器可以向?yàn)g覽器分配一個(gè)唯一ID,并以Cookie的形式發(fā)送到瀏覽器,瀏覽器在后續(xù)訪問時(shí)總是附帶此Cookie,這樣,服務(wù)器就可以識(shí)別用戶身份。

我們把這種基于唯一ID識(shí)別用戶身份的機(jī)制稱為Session。每個(gè)用戶第一次訪問服務(wù)器后,會(huì)自動(dòng)獲得一個(gè)Session ID。如果用戶在一段時(shí)間內(nèi)沒有訪問服務(wù)器,那么Session會(huì)自動(dòng)失效,下次即使帶著上次分配的Session ID訪問,服務(wù)器也認(rèn)為這是一個(gè)新用戶,會(huì)分配新的Session ID。

2. 什么是 session 的會(huì)話

會(huì)話對(duì)應(yīng)的英語單詞:session

當(dāng)用戶打開瀏覽器,進(jìn)行一系列操作,然后最終將瀏覽器關(guān)閉,這個(gè)整個(gè)過程叫做:一次會(huì)話。會(huì)話在服務(wù)器端也有一個(gè)對(duì)應(yīng)的java對(duì)象,這個(gè)java對(duì)象叫做:session

什么是一次請(qǐng)求:用戶在瀏覽器上點(diǎn)擊了一下,然后到頁面停下來,可以粗略認(rèn)為是一次請(qǐng)求。請(qǐng)求對(duì)應(yīng)的服務(wù)器端的java對(duì)象是:request。 這里提前透露一點(diǎn)后面的內(nèi)容: session 對(duì)象是用服務(wù)器端生成的,所以這里是通過 request 請(qǐng)求的方式向服務(wù)器獲取到一個(gè) session 會(huì)話對(duì)象

  • 一個(gè)會(huì)話當(dāng)中包含多次請(qǐng)求(一次會(huì)話對(duì)應(yīng)N次請(qǐng)求。)

這里我們可以打印顯示我們的 session 地址信息

package com.RainbowSea.session;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;
import java.io.PrintWriter;


@WebServlet("/session")
public class TestSessionServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        HttpSession session = request.getSession();

        response.setContentType("text/html;charSet=UTF-8");
        PrintWriter out = response.getWriter();

        out.println(" session對(duì)象:  " + session);

    }
}

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

從 session 對(duì)象當(dāng)中存在于: org.apache.catalina.session.StandardSession 的位置。

在Java的servlet 的規(guī)范當(dāng)中,session 對(duì)應(yīng)的類名為: HttpSession(jarkata.servlett.http.HttpSession) 。
B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

注意:

sessioin 機(jī)制屬于 B/S結(jié)構(gòu)的一部分。如果使用php語言開發(fā)WEB項(xiàng)目,同樣也是有session這種機(jī)制的。session機(jī)制實(shí)際上是一個(gè)規(guī)范。然后不同的語言對(duì)這種會(huì)話機(jī)制都有實(shí)現(xiàn)。

獲取 sessoin 的對(duì)象方法:

// 注意: sessio 是存儲(chǔ)在服務(wù)器端的,所以我們這里使用的是 request 請(qǐng)求的方式,向服務(wù)器請(qǐng)求獲取到 session 對(duì)象 

// 該訪問獲取到 session 對(duì)象,如果服務(wù)器端沒有 session 對(duì)象會(huì)自動(dòng)創(chuàng)建出  session 對(duì)象
 HttpSession session = request.getSession();
        
// 獲取到 session 對(duì)象,(參數(shù)為 false )表示:如果服務(wù)器當(dāng)中沒有 session 是不會(huì)自動(dòng)創(chuàng)建的。
HttpSession session1 = request.getSession(false);

3. session 的作用

session對(duì)象最主要的作用是:保存會(huì)話狀態(tài)。(用戶登錄成功了,這是一種登錄成功的狀態(tài),你怎么把登錄成功的狀態(tài)一直保存下來呢?使用session對(duì)象可以保留會(huì)話狀態(tài)。)

那我們?yōu)槭裁葱枰猻ession 對(duì)象來保存會(huì)話狀態(tài)呢?

因?yàn)镠TTP協(xié)議是一種無狀態(tài)協(xié)議。

什么是無狀態(tài):請(qǐng)求的時(shí)候,B和S是連接的,但是請(qǐng)求結(jié)束之后,連接就斷了。為什么要這么做?HTTP協(xié)議為什么要設(shè)計(jì)成這樣?因?yàn)檫@樣的無狀態(tài)協(xié)議,可以降低服務(wù)器的壓力。請(qǐng)求的瞬間是連接的,請(qǐng)求結(jié)束之后,連接斷開,這樣服務(wù)器壓力小。

只要B和S斷開了,那么關(guān)閉瀏覽器這個(gè)動(dòng)作,服務(wù)器知道嗎?

因?yàn)?HTTP 協(xié)議是無狀態(tài)的連接的,所以當(dāng)我們關(guān)閉了 瀏覽器的時(shí)候,我們的服務(wù)器端是無法接收到瀏覽器被關(guān)閉的一個(gè)信息的。所以:我們的服務(wù)器自然也就無法知道瀏覽器關(guān)閉了。

一個(gè)會(huì)話對(duì)應(yīng)一個(gè) sessoin 對(duì)象,一個(gè) session 對(duì)應(yīng)上一個(gè) ID也就是 (JSESSIONID) 。

比如:張三打開一個(gè)瀏覽器 A,李四打開一個(gè)瀏覽器B,訪問服務(wù)器之后,在服務(wù)端會(huì)生成:

  • 張三專屬的session對(duì)象,同時(shí)會(huì)標(biāo)記上一個(gè) 對(duì)應(yīng)的 ID 信息
  • 李四專屬的session對(duì)象 ,同時(shí)會(huì)標(biāo)記上一個(gè)對(duì)應(yīng)的 ID 信息。
  • 注意了:這兩者之間的 ID信息是不一樣的。

代碼舉例:

package com.RainbowSea.serssion;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/test/session")
public class TestSessionServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        // request 和 session 都是在服務(wù)端的java對(duì)象,都在JVM當(dāng)中
        // request對(duì)象代表一次請(qǐng)求,(一次請(qǐng)求對(duì)應(yīng)一個(gè)request對(duì)象,再次請(qǐng)求就會(huì)對(duì)應(yīng)兩個(gè)不同的request對(duì)象)
        // session對(duì)象代表一次會(huì)話,(一次會(huì)話對(duì)應(yīng)一個(gè)session 對(duì)象)
        // 獲取session,如何服務(wù)器當(dāng)中沒有 session 對(duì)象就會(huì)自動(dòng)創(chuàng)建一個(gè),
        HttpSession session = request.getSession();
        // 獲取到服務(wù)器端的 session ,如果沒有不會(huì)自動(dòng)創(chuàng)建 session 對(duì)象
        //HttpSession session1 = request.getSession(false);

        //session.setAttribute(); 將數(shù)據(jù)存儲(chǔ)到 session 會(huì)話當(dāng)中。
        //session.getAttribute() 將數(shù)據(jù)從 session 會(huì)話當(dāng)中取出




        // 將session 對(duì)象響應(yīng)到瀏覽器端
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println("會(huì)話對(duì)象:" + session);



    }
}

結(jié)果:

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

什么表示一個(gè)會(huì)話

粗略的可以認(rèn)為一個(gè):當(dāng)我們打開一個(gè)瀏覽器訪問一個(gè)A服務(wù)器的時(shí)候,如果這個(gè)瀏覽器不關(guān)閉的情況下,該瀏覽器發(fā)送的請(qǐng)求都是向 A服務(wù)器,那么哪個(gè)瀏覽器發(fā)送對(duì)于這個(gè)A服務(wù)器發(fā)送的所有的請(qǐng)求都可以理解為是一個(gè) session 會(huì)話。

我們也可以再精細(xì)一點(diǎn)的再說一下:就是我們?cè)诰〇|網(wǎng)站,A用戶登錄以后,在京東網(wǎng)站當(dāng)中的,進(jìn)行查詢商品,購買商品,添加商品購物車,等等,都是屬于該 A用戶專屬的一個(gè) session 的會(huì)話,當(dāng)我們?cè)僭诰〇|網(wǎng)站當(dāng)中,B用戶登錄以后,在京東網(wǎng)站當(dāng)中的,進(jìn)行查詢商品,購買商品,添加商品購物車,等等這些是 B用戶請(qǐng)求操作的都是專屬于一個(gè) session 會(huì)話。

為什么不使用request對(duì)象保存會(huì)話狀態(tài)?為什么不使用ServletContext對(duì)象保存會(huì)話狀態(tài)?

  • request.setAttribute()存數(shù)據(jù),request.getAttribute()取數(shù)據(jù),ServletContext也有這個(gè)方法。request是請(qǐng)求域。ServletContext是應(yīng)用域。
  • request是一次請(qǐng)求一個(gè)對(duì)象。
  • ServletContext對(duì)象是服務(wù)器啟動(dòng)的時(shí)候創(chuàng)建,服務(wù)器關(guān)閉的時(shí)候銷毀,這個(gè)ServletContext對(duì)象只有一個(gè)。
  • ServletContext對(duì)象的域太大。
  • request請(qǐng)求域(HttpServletRequest)、session會(huì)話域(HttpSession)、application應(yīng)用域(ServletContext)
  • 三個(gè)域之間的作用域的大小關(guān)系:request (請(qǐng)求域)< session(會(huì)話域) < application(應(yīng)用域) 。

4. session 的實(shí)現(xiàn)原理解釋

HttpSession session = request.getSession();

這行代碼很神奇。張三訪問的時(shí)候獲取的 session 對(duì)象就是張三專屬的。李四訪問的時(shí)候獲取的 session 對(duì)象就是李四專屬的。

這是如何做到的呢?我們可以舉一個(gè)有關(guān)于我們實(shí)際生活當(dāng)中的一個(gè)例子:

比如: 我們張三,李四都是在同一個(gè)大學(xué)的班級(jí)當(dāng)中,張三和李四上的都是同一個(gè)籃球課(體育課),當(dāng)他們上課的時(shí)候

,他們的體育老師帶來了(一筐籃球)(就是 session ),讓同學(xué)們自行挑選好自己的籃球,用于上籃球課。這時(shí)候我們的張三認(rèn)真的挑選到了一個(gè)籃球,并且試了試手感,感覺十分的不錯(cuò)。心里就有了一點(diǎn)小心思:就是想要,自己每次上籃球課的時(shí)候,都可以找到,并拿到這個(gè)手感不錯(cuò)的籃球。怎么實(shí)現(xiàn)這個(gè)想法呢?于是,張三同學(xué)就在,這個(gè)他手中的(手感不錯(cuò))籃球上做了一個(gè)標(biāo)記(SESSIONID=xxxxxx)。這個(gè)標(biāo)記只有張三自己知道是干什么的,其他同學(xué)都不知道。這樣當(dāng)下次以后的每一節(jié)籃球課,張三都可以根據(jù)自己所作的這個(gè)標(biāo)記,從眾多籃球當(dāng)中,找到這個(gè),自己標(biāo)記到的籃球了。

這個(gè)例子當(dāng)中的: 一筐籃球就可以比作是 : 服務(wù)器的當(dāng)中的 session 會(huì)話對(duì)象,而其中的 張三自己在籃球上作的標(biāo)記就可以比作是: SESSIONID=xxxxxx 是 session 對(duì)象的 ID 了。

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

session 生成的過程:

一個(gè) session 會(huì)話對(duì)象 對(duì)應(yīng)一個(gè) JSESSIONID=xxxxxx (就是一個(gè)標(biāo)記 session 會(huì)話對(duì)象的 ID (類似于一個(gè)人的身份證信息)是唯一的)。

服務(wù)器當(dāng)中是有一個(gè)類似于 Map 的一個(gè) session 列表。該 session 列表當(dāng)中存在兩樣?xùn)|西: key 對(duì)應(yīng)的是 JSESSIONID=xxxxxx (也就是 session 的ID的標(biāo)記) ,而 value 對(duì)應(yīng)的則是 session 對(duì)象。

key (session 的 ID) value ( session 對(duì)象)
JSESSIONID=123 session1
JSESSIONID=456 session2

當(dāng)用戶第一次請(qǐng)求服務(wù)器的時(shí)候,服務(wù)器會(huì)為該用戶生成一個(gè) session 會(huì)話對(duì)象,同時(shí)服務(wù)器會(huì)將該 session 對(duì)應(yīng) JSESSIONID=123,也就是: sessionID 發(fā)送給客戶端??蛻舳藭?huì)接收到服務(wù)器發(fā)送過來的 JSESSIONID ,并存儲(chǔ)到 客戶端的緩存(Cookie) 當(dāng)中。同時(shí)需要注意的是: JSESSIONID=xxxxxx 這個(gè)是以Cookie的形式保存在瀏覽器的內(nèi)存中的。瀏覽器只要關(guān)閉。這個(gè)cookie就沒有了。(當(dāng)然這是默認(rèn)的情況下,你是可以自定義設(shè)置的。關(guān)于 Cookie 的內(nèi)容這里就不會(huì)說明了。)

舉例:具體代碼詳細(xì)如下:

package com.RainbowSea.session;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;
import java.io.PrintWriter;


@WebServlet("/session")
public class TestSessionServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        HttpSession session = request.getSession();

        // 
        response.setContentType("text/html;charSet=UTF-8");
        PrintWriter out = response.getWriter();


        //
        out.println(" session對(duì)象:  " + session);

    }
}

如下是我們的瀏覽器(客戶端) 向服務(wù)器 第一次 發(fā)送請(qǐng)求(response) 的效果圖:如下:

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

第二次,我們的瀏覽器(客戶端)向服務(wù)器發(fā)送 第二次請(qǐng)求(response) ,因?yàn)槲覀優(yōu)g覽器(客戶端)第一次請(qǐng)求的時(shí)候,已經(jīng)將服務(wù)器響應(yīng)過來的 JSESSIONID 存儲(chǔ)到了,自己客戶端的 Cookie 當(dāng)中去了。所以,當(dāng)我們的客戶端再次向上一個(gè)服務(wù)器發(fā)送請(qǐng)求的時(shí)候,這是同屬于同一個(gè)會(huì)話的,所以我們的客戶端將第一次請(qǐng)求的時(shí)候,獲取到的 JSESSIONID 發(fā)送給 服務(wù)器,服務(wù)器根據(jù) JSESSIONID 查找session對(duì)象。 返回給客戶端,所以兩者之間的 session 對(duì)象的地址是一樣的,因?yàn)槭峭瑢儆谕粋€(gè)會(huì)話的。測(cè)試效果如下:

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

注意:我們的瀏覽器是遵循 HTTP 協(xié)議的,而 HTTP 協(xié)議是 無狀態(tài)的,導(dǎo)致我們的服務(wù)器無法知道瀏覽器關(guān)閉了,所以我們的 會(huì)話銷毀存在一種(延遲銷毀的機(jī)制:簡(jiǎn)單的說就是,當(dāng)一個(gè) session 會(huì)話,在一定的時(shí)間段內(nèi)沒有,任何的請(qǐng)求發(fā)發(fā)送了,服務(wù)器就會(huì)認(rèn)為該 sessoin 沒有用了,會(huì)自動(dòng)銷毀該 session 會(huì)話對(duì)象了),當(dāng)我們關(guān)閉瀏覽器,內(nèi)存消失,Cookie 消失,Cookie 消失了,那存在其中的 JSESSIONID (也就是 sessionID ) 自然也就消失了。而 JSESSIONID 消失了,我們的客戶端也就無法根據(jù)該 JSESSIONID 獲取到,訪問到 對(duì)應(yīng)的 session 對(duì)象了,當(dāng)?shù)竭_(dá)一定的時(shí)間段后,還是沒有任何客戶端訪問該 Session 會(huì)話,服務(wù)器就會(huì)自動(dòng)銷毀該 session 會(huì)話對(duì)象了。

關(guān)閉瀏覽器,重新發(fā)送請(qǐng)求,測(cè)試效果如下圖所示:

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

session對(duì)象的銷毀:

session 對(duì)象是什么時(shí)候銷毀:

瀏覽器關(guān)閉的時(shí)候,服務(wù)器是不知道的,服務(wù)器無法監(jiān)測(cè)到瀏覽器關(guān)閉了(HTTP協(xié)議是無狀態(tài)協(xié)議),所以 session 的銷毀要依靠 session 超時(shí)機(jī)制,

但也有一種可能,系統(tǒng)提供了 “安全退出”,用戶可以點(diǎn)擊這個(gè)按鈕,這樣服務(wù)器就知道你退出了,然后服務(wù)器會(huì)自動(dòng)銷毀 session 對(duì)象。

  • 第一種: 手動(dòng)銷毀
// 銷毀 session 對(duì)象的
session.invalidate(); 
  • 第二種:自動(dòng)銷毀(超時(shí)銷毀)

為什么關(guān)閉瀏覽器,會(huì)話結(jié)束?

關(guān)閉瀏覽器之后,瀏覽器中保存的 JSESSIONID (也就是 session 的ID)消失,下次重新打開瀏覽器之后,

瀏覽器緩存中沒有這個(gè) session的ID,自然找不到 服務(wù)器中對(duì)應(yīng)的 session 對(duì)象,session 對(duì)象找不到,等同于會(huì)話結(jié)束。(超時(shí)銷毀,當(dāng)一個(gè) session 一段時(shí)間內(nèi)沒有,被訪問了,就會(huì)自動(dòng)被服務(wù)器銷毀,這里我們的 JSESSIONID 都沒有了,我們就無法找到對(duì)應(yīng) session 的對(duì)象,無法找到 session 對(duì)象,就更無法訪問了。)

session 超時(shí)銷毀機(jī)制的設(shè)置的時(shí)間點(diǎn),默認(rèn)是 Tomcat apache-tomcat-10.0.12\conf\web.xml的 web.xml 配置當(dāng)中,默認(rèn)配置為了 30 分鐘

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

<!-- ==================== Default Session Configuration ================= -->
<!-- You can set the default session timeout (in minutes) for all newly   -->
<!-- created sessions by modifying the value below.                       -->
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-sJQQVVaF-1682775113687)(E:\博客\javaWed博客庫\image-20230424221802452.png)]

當(dāng)然,這個(gè) session 超時(shí)銷毀的時(shí)間點(diǎn),我們也是可以設(shè)置的。

我們可以根據(jù)自己的需要設(shè)置,比如:如果是一個(gè)銀行的安全信息的話,可以設(shè)置為 1~5 分鐘。如果是一個(gè)長(zhǎng)久使用的話可以設(shè)置為 24 小時(shí),7天等等。根據(jù)實(shí)際業(yè)務(wù)需要靈活的設(shè)置。

重點(diǎn):如下是 session 的生成,銷毀的原理圖示:

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

5. 補(bǔ)充: Cookie禁用了,session還能找到嗎 ?

cookie禁用是什么意思?服務(wù)器正常發(fā)送cookie給瀏覽器,但是瀏覽器不要了。拒收了。并不是服務(wù)器不發(fā)了。

如下是: Google Chrome 瀏覽器禁用 Cookie 的設(shè)置:
B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

當(dāng)我們禁用了瀏覽器的 Cookie 設(shè)置,再次訪問我們的 Servlet 服務(wù)器的效果如下:

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

下面這個(gè)是 Firefox火狐瀏覽器的禁用 Cookie 的設(shè)置。

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

結(jié)論:當(dāng)瀏覽器禁用了Cookie 緩存功能,服務(wù)器正常發(fā)送cookie信息(包括了 JSESSIONID 信息)給瀏覽器,但是瀏覽器不要了。拒收了,并不是服務(wù)器不發(fā)了。所以導(dǎo)致的結(jié)果就是:客戶端不會(huì)發(fā)送給服務(wù)器 JSESSIONID信息了,找不到了,每一次請(qǐng)求都會(huì)獲取到新的session對(duì)象。

問題:cookie禁用了,session機(jī)制還能實(shí)現(xiàn)嗎?

可以,需要使用 URL 重寫機(jī)制。

如下:演示:當(dāng)我們?cè)L問服務(wù)器時(shí),通過瀏覽器的 檢查功能中的 ——> 網(wǎng)絡(luò)(NetWork) 當(dāng)中的第一次請(qǐng)求服務(wù)器,服務(wù)器響應(yīng)給客戶端的 JSESSIONID 的信息會(huì)顯示在其中的:response headers (請(qǐng)求頭當(dāng)中 )。

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

將其中的 jsessionid=19D1C99560DCBF84839FA43D58F56E16 拼接到我們?cè)L問的 URL當(dāng)中,中間使用 ; 分號(hào)隔開。如下:需要注意的是,將其中的 JSESSIONID 寫成小寫的: jsessionid

http://127.0.0.1:8080/servlet14/session;jsessionid=F247C2C5CBE489F45383D116224F071B

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

原理:是雖然我們?yōu)g覽器沒有保存住服務(wù)器響應(yīng)過來的JSESSIONID信息,但是我們手動(dòng)將其中的SESSIOND給記住了,并通過地址欄的方式,get的方式發(fā)送給了服務(wù)器,服務(wù)器就會(huì)幫我們?nèi)ession列表當(dāng)中找到該對(duì)過的JSESSIONID的
session對(duì)象,而不是新建esssion對(duì)象了。

URL重寫機(jī)制會(huì)提高開發(fā)者的成本。開發(fā)人員在編寫任何請(qǐng)求路徑的時(shí)候,后面都要添加一個(gè)sessionid,給開發(fā)帶來了很大的難度,很大的成本。所以大部分的網(wǎng)站都是這樣設(shè)計(jì)的:你要是禁用cookie,你就別用了。

怎么理解這個(gè): 你要是禁用了 Cookie 緩存機(jī)制,你就別用了。就是說,如果你把 Cookie 禁用了一些網(wǎng)站你可能打不開來,或者說無法顯示全部?jī)?nèi)容信息。當(dāng)你開始這個(gè)設(shè)置 禁用Cookie 都會(huì)有一些提示的信息給到你的。比如:

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

。如下當(dāng)我們把 Firefox火狐瀏覽器的禁用 Cookie 打開,訪問

  • 京東網(wǎng)站:https://www.jd.com/

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

  • 訪問淘寶:https://www.taobao.com/

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

  • 訪問唯品會(huì):https://www.vip.com/

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

  • 訪問12306 網(wǎng)站:https://www.12306.cn/index/

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

6. 總結(jié)一下到目前位置我們所了解的域?qū)ο螅?/h2>
  • request(對(duì)應(yīng)的類名:HttpServletRequest)請(qǐng)求域(請(qǐng)求級(jí)別的)
  • session(對(duì)應(yīng)的類名:HttpSession)會(huì)話域(用戶級(jí)別的)
  • application(對(duì)應(yīng)的類名:ServletContext)應(yīng)用域(項(xiàng)目級(jí)別的,所有用戶共享的。)
  • 這三個(gè)域?qū)ο蟮拇笮£P(guān)系:request < session < application
  • 他們?nèi)齻€(gè)域?qū)ο蠖加幸韵氯齻€(gè)公共的方法:
    • setAttribute(向域當(dāng)中綁定數(shù)據(jù))
    • getAttribute(從域當(dāng)中獲取數(shù)據(jù))
    • removeAttribute(刪除域當(dāng)中的數(shù)據(jù))
  • 使用原則:盡量使用小的域。

7. oa 項(xiàng)目的優(yōu)化體驗(yàn):使用上 session 會(huì)話機(jī)制:

閱讀如下內(nèi)容,大家可以先移步至: Servlet注解的使用,簡(jiǎn)化配置 以及,使用模板方法設(shè)計(jì)模式優(yōu)化oa項(xiàng)目_ChinaRainbowSea的博客-CSDN博客看看有助于閱讀理解。

session掌握之后,我們?cè)趺唇鉀Qoa項(xiàng)目中的登錄問題:就是我們的登錄頁面是一個(gè)擺設(shè),當(dāng)用戶沒有登錄的情況下,可以直接通過在地址欄上輸入 URL 可以訪問到對(duì)應(yīng)的資源信息。

這里我們可以使用: session 會(huì)話機(jī)制,讓登錄起作用:就是如果用戶直接通過在地址欄上輸入 URL 可以訪問到對(duì)應(yīng)的資源信息的時(shí)候,判斷用戶是否登錄過,如果登錄過,則可以直接訪問。如果沒有登錄過就跳轉(zhuǎn)到登錄頁面,進(jìn)行一個(gè)正確的登錄成功的操作,才可以訪問。同時(shí)設(shè)置一個(gè)安全退出系統(tǒng),銷毀 session 對(duì)象的按鈕設(shè)置。

登錄成功之后,可以將用戶的登錄信息存儲(chǔ)到session當(dāng)中。也就是說session中如果有用戶的信息就代表用戶登錄成功了。session中沒有用戶信息,表示用戶沒有登錄過。則跳轉(zhuǎn)到登錄頁面。

優(yōu)化源碼如下:

首先是登錄頁面的優(yōu)化:當(dāng)用戶登錄成功,將用戶的登錄信息存儲(chǔ)到session當(dāng)中(這里我們存儲(chǔ)到用戶的用戶名信息。)

核心優(yōu)化代碼:

// 登錄成功與否
if (success) {

   // 成功,跳轉(zhuǎn)到用戶列表頁面
   // 這里使用重定向(沒有資源的共享):重定向需要加/項(xiàng)目名 +

   // 獲取session 對(duì)象(這里的要求是: 必須獲取到 session ,沒有session 也要新建一個(gè) session 對(duì)象)
   // 注意:我們下面的這個(gè)會(huì)話是不能刪除的,因?yàn)樯厦嫖覀冸m然通過 welcome Servlet 進(jìn)行了一個(gè)會(huì)話
   // 但是 welcome 當(dāng)中是當(dāng)我們cookie 當(dāng)中存在并且用戶名和密碼正確的時(shí)候才會(huì)進(jìn)行一個(gè) session 的
   HttpSession session = request.getSession();  // 服務(wù)器當(dāng)中沒有 session 會(huì)話域自動(dòng)創(chuàng)建
   session.setAttribute("username", username);  // 將用戶名存儲(chǔ)到 session 會(huì)話域當(dāng)中


   response.sendRedirect(request.getContextPath() + "/dept/list");
   } else {
     // 失敗,跳轉(zhuǎn)到失敗頁面
     response.sendRedirect(request.getContextPath() + "/error.jsp");
   }

全部的代碼:

package com.RainbowSea.servlet;

import com.RainbowSea.DBUtil.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;


@WebServlet({"/user/login", "/user/exit"})
public class UserServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        // 獲取到瀏覽器地址欄上的URL路徑
        String servletPath = request.getServletPath();

        if ("/user/login".equals(servletPath)) {
            doLogin(request, response);
        } else if ("/user/exit".equals(servletPath)) {
            doExit(request, response);
        }


    }

    private void doExit(HttpServletRequest request, HttpServletResponse response) throws IOException {
    }

    protected void doLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        // 一個(gè)用戶登錄驗(yàn)證的方式:驗(yàn)證用戶名和密碼是否正確
        // 獲取用戶名和密碼
        // 前端提交是數(shù)據(jù)是:username=111&password=fads
        // 注意:post 提交的數(shù)據(jù)是在請(qǐng)求體當(dāng)中,而get提交的數(shù)據(jù)是在請(qǐng)求行當(dāng)中

        boolean success = false;  // 標(biāo)識(shí)登錄成功

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        String exempt = request.getParameter("exempt");

        // 連接數(shù)據(jù)庫驗(yàn)證用戶名和密碼
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            // 1. 獲取連接,注冊(cè)驅(qū)動(dòng)
            connection = DBUtil.getConnection();

            // 2. 獲取操作數(shù)據(jù)對(duì)象,預(yù)編譯sql語句, ? 占位符不要加,“”,'' 單雙引號(hào),成了字符串了,無法識(shí)別成占位符了。
            String sql = "select username,password from t_user where username = ? and password = ?";
            preparedStatement = connection.prepareStatement(sql);

            // 3. 填充占位符,真正執(zhí)行sql語句
            preparedStatement.setString(1, username);
            preparedStatement.setString(2, password);

            resultSet = preparedStatement.executeQuery();

            // 4. 處理查詢結(jié)果集
            // 只有一條結(jié)果集
            if (resultSet.next()) {
                // 登錄成功
                success = true;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            // 5. 關(guān)閉資源,最后使用的最先關(guān)閉,
            DBUtil.close(connection, preparedStatement, resultSet);
        }

        // 登錄成功與否
        if (success) {
            
            // 成功,跳轉(zhuǎn)到用戶列表頁面
            // 這里使用重定向(沒有資源的共享):重定向需要加/項(xiàng)目名 +

            // 獲取session 對(duì)象(這里的要求是: 必須獲取到 session ,沒有session 也要新建一個(gè) session 對(duì)象)
            // 注意:我們下面的這個(gè)會(huì)話是不能刪除的,因?yàn)樯厦嫖覀冸m然通過 welcome Servlet 進(jìn)行了一個(gè)會(huì)話
            // 但是 welcome 當(dāng)中是當(dāng)我們cookie 當(dāng)中存在并且用戶名和密碼正確的時(shí)候才會(huì)進(jìn)行一個(gè) session 的
            HttpSession session = request.getSession();  // 服務(wù)器當(dāng)中沒有 session 會(huì)話域自動(dòng)創(chuàng)建
            session.setAttribute("username", username);  // 將用戶名存儲(chǔ)到 session 會(huì)話域當(dāng)中


            response.sendRedirect(request.getContextPath() + "/dept/list");
        } else {
            // 失敗,跳轉(zhuǎn)到失敗頁面
            response.sendRedirect(request.getContextPath() + "/error.jsp");
        }


    }
}

其次是當(dāng)用戶想要直接通過 URL訪問的時(shí)候,判斷用戶是否登錄成功過,登錄成功過可以訪問,沒有登錄成功過無法訪問:

思路是:

我們通過 session 會(huì)話機(jī)制,判斷用戶是否登錄過,如果用戶沒有登錄就想要訪問 到其信息,不可以,因?yàn)槲覀冞@里判斷了一次是否登錄過,只有登錄入過了,才會(huì)將中登錄到用戶名為 “username” 的信息存儲(chǔ)到 session 會(huì)話當(dāng)中,如果沒有的話是查詢不到的,返回的是 null。需要注意的一點(diǎn)就是,我們的jsp 當(dāng)中的內(nèi)置對(duì)象,是會(huì)自動(dòng)創(chuàng)建一個(gè) session 會(huì)話對(duì)象的(所以就會(huì)導(dǎo)致,就算我們沒有登錄成功 ,session 對(duì)象也是不為空的,因?yàn)镴SP創(chuàng)建了 session 對(duì)象,我們可以通過JSP 指令禁止 JSP 生成 session 內(nèi)置對(duì)象 <%@page session = false %>,需要所有會(huì)被訪問,生成的 Jsp 文件都需要設(shè)置該指令。這里 所謂的禁用了就是,對(duì)應(yīng)的訪問生成的 xxx_jsp.java) 當(dāng)中不會(huì)翻譯生成其中內(nèi)置的 session 對(duì)象),但是因?yàn)檫@里我們進(jìn)行了一個(gè) 雙重的判斷機(jī)制。

if(session != null && session.getAttribute("username") != null)
// 雙重的判斷,一個(gè)是 session 會(huì)話域要存在,其次是 會(huì)話域當(dāng)中存儲(chǔ)了名為 "username" 的信息,可以用戶登錄的信息可以從 session 找到,如果找不到 ,返回 null ,找到不為 null 。這樣就解決了 JSP 內(nèi)置session 對(duì)象的沒有登錄 session 不為 null 的影響了。

需要注意一點(diǎn)的就是:這里我們要使用HttpSession session = request.getSession(false)

HttpSession session = request.getSession(false);  // 獲取到服務(wù)器當(dāng)中的session ,沒有不會(huì)創(chuàng)建的,
// session 是用戶登錄成功才創(chuàng)建的,其他情況不要?jiǎng)?chuàng)建 session 會(huì)話對(duì)象。

核心代碼:


// 可以使用模糊查詢 @WebServlet("/dept/*")
@WebServlet({"/dept/list", "/dept/detail", "/dept/delete", "/dept/save", "/dept/modify"})
public class DeptServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        String servletPath = request.getServletPath();  // 獲取到瀏覽器當(dāng)中的uri

        // 獲取session 這個(gè) session 是不不需要新建的
        // 只是獲取當(dāng)前session ,獲取不到這返回null,
        HttpSession session = request.getSession(false);  // 獲取到服務(wù)器當(dāng)中的session ,沒有不會(huì)創(chuàng)建的


        /**
         * 說明這里我們通過 session 會(huì)話機(jī)制,判斷用戶是否登錄過,如果用戶沒有登錄就想要訪問
         * 到其信息,不可以,因?yàn)槲覀冞@里判斷了一次是否登錄過,只有登錄入過了,才會(huì)將中登錄到
         * 用戶名為 “username” 的信息存儲(chǔ)到 session 會(huì)話當(dāng)中,如果沒有的話是查詢不到的,返回的是 null
         * 需要注意的一點(diǎn)就是,我們的jsp 當(dāng)中的內(nèi)置對(duì)象,是會(huì)自動(dòng)創(chuàng)建一個(gè) session 會(huì)話對(duì)象的,但是
         * 因?yàn)檫@里我們進(jìn)行了一個(gè) 雙重的判斷機(jī)制。注意:需要先將對(duì)應(yīng)的 xx_jsp.java 生成才行。同時(shí)
         * 使用 <%@page session = false %> 指令的話,需要所有會(huì)被訪問,生成的 Jsp 文件都需要設(shè)置。
         *
         *   jakarta.servlet.http.HttpSession session = null;
         *   session = pageContext.getSession();
         */
        if(session != null && session.getAttribute("username") != null) {
            // 雙重的判斷,一個(gè)是 session 會(huì)話域要存在,其次是 會(huì)話域當(dāng)中存儲(chǔ)了名為 "username" 的信息
            if ("/dept/list".equals(servletPath)) {
                doList(request, response);
            } else if ("/dept/detail".equals(servletPath)) {
                doDetail(request, response);
            } else if ("/dept/delete".equals(servletPath)) {
                doElete(request,response);
            } else if("/dept/save".equals(servletPath)) {
                doSave(request,response);
            } else if("/dept/modify".equals(servletPath)) {
                doModify(request,response);
            }
        } else {
            response.sendRedirect(request.getContextPath());  // 訪問的web 站點(diǎn)的根即可,自動(dòng)找到的是名為 index.jsp
        }

    }
}

最后就是:用戶點(diǎn)擊安全退出系統(tǒng),銷毀 session 對(duì)象的實(shí)現(xiàn)了。

當(dāng)我們點(diǎn)擊 安全退出,手動(dòng)將 session 會(huì)話對(duì)象銷毀了。就需要重新登錄了。只有重新登錄,建立新的登錄成功的 session 會(huì)話信息,才能再次通過URL訪問。

核心代碼如下:

session.invalidate();  // 銷毀 session 對(duì)象。
/**
* 用戶手動(dòng)點(diǎn)擊安全退出,銷毀 session 對(duì)象
* @param request
 * @param response
* @throws IOException
*/
private void doExit(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 獲取到客戶端發(fā)送過來的 sessoin
        HttpSession session = request.getSession();

        if (session != null) {
            // 手動(dòng)銷毀 session 對(duì)象
            // 注意:會(huì)話銷毀的了,自然需要重寫登錄了,沒有登錄過,無法進(jìn)行一個(gè)路徑的訪問的
            session.invalidate();
            
            // 跳轉(zhuǎn)會(huì)登錄的頁面
            response.sendRedirect(request.getContextPath());  // 項(xiàng)目名路徑默認(rèn)就是訪問的index.html 的歡迎頁面
        }
    }

全部具體代碼:

package com.RainbowSea.servlet;

import com.RainbowSea.DBUtil.DBUtil;
import com.RainbowSea.bean.Dept;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

// 可以使用模糊查詢 @WebServlet("/dept/*")
@WebServlet({"/dept/list", "/dept/detail", "/dept/delete", "/dept/save", "/dept/modify"})
public class DeptServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        String servletPath = request.getServletPath();  // 獲取到瀏覽器當(dāng)中的uri

        // 獲取session 這個(gè) session 是不不需要新建的
        // 只是獲取當(dāng)前session ,獲取不到這返回null,
        HttpSession session = request.getSession(false);  // 獲取到服務(wù)器當(dāng)中的session ,沒有不會(huì)創(chuàng)建的


        /**
         * 說明這里我們通過 session 會(huì)話機(jī)制,判斷用戶是否登錄過,如果用戶沒有登錄就想要訪問
         * 到其信息,不可以,因?yàn)槲覀冞@里判斷了一次是否登錄過,只有登錄入過了,才會(huì)將中登錄到
         * 用戶名為 “username” 的信息存儲(chǔ)到 session 會(huì)話當(dāng)中,如果沒有的話是查詢不到的,返回的是 null
         * 需要注意的一點(diǎn)就是,我們的jsp 當(dāng)中的內(nèi)置對(duì)象,是會(huì)自動(dòng)創(chuàng)建一個(gè) session 會(huì)話對(duì)象的,但是
         * 因?yàn)檫@里我們進(jìn)行了一個(gè) 雙重的判斷機(jī)制。注意:需要先將對(duì)應(yīng)的 xx_jsp.java 生成才行。同時(shí)
         * 使用 <%@page session = false %> 指令的話,需要所有會(huì)被訪問,生成的 Jsp 文件都需要設(shè)置。
         *
         *   jakarta.servlet.http.HttpSession session = null;
         *   session = pageContext.getSession();
         */
        if(session != null && session.getAttribute("username") != null) {
            // 雙重的判斷,一個(gè)是 session 會(huì)話域要存在,其次是 會(huì)話域當(dāng)中存儲(chǔ)了名為 "username" 的信息
            if ("/dept/list".equals(servletPath)) {
                doList(request, response);
            } else if ("/dept/detail".equals(servletPath)) {
                doDetail(request, response);
            } else if ("/dept/delete".equals(servletPath)) {
                doElete(request,response);
            } else if("/dept/save".equals(servletPath)) {
                doSave(request,response);
            } else if("/dept/modify".equals(servletPath)) {
                doModify(request,response);
            }
        } else {
            response.sendRedirect(request.getContextPath());  // 訪問的web 站點(diǎn)的根即可,自動(dòng)找到的是名為 index.jsp
        }

    }


    /**
     * 修改部門信息
     *
     * @param request
     * @param response
     */
    private void doModify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        request.setCharacterEncoding("UTF-8");  // 設(shè)置獲取的的信息的編碼集
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        // 影響數(shù)據(jù)庫的行數(shù)
        int count = 0;


        String deptno = request.getParameter("deptno");
        String dname = request.getParameter("dname");
        String loc = request.getParameter("loc");


        try {
            // 1. 注冊(cè)驅(qū)動(dòng),連接數(shù)據(jù)庫
            connection = DBUtil.getConnection();

            // 2. 獲取到操作數(shù)據(jù)庫的對(duì)象,預(yù)編譯sql語句,sql測(cè)試
            String sql = "update dept set dname = ?,loc = ? where depton = ?";
            preparedStatement = connection.prepareStatement(sql);

            // 3. 填充占位符,真正執(zhí)行sql語句
            // 從下標(biāo) 1開始
            preparedStatement.setString(1, dname);
            preparedStatement.setString(2, loc);
            preparedStatement.setString(3, deptno);

            count = preparedStatement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            // 4. 釋放資源,最后使用的優(yōu)先被釋放
            DBUtil.close(connection, preparedStatement, null);
        }

        if (count == 1) {
            // 更新成功
            // 跳轉(zhuǎn)到部門列表頁面(部門列表表面是通過java程序動(dòng)態(tài)生成的,所以還需要再次執(zhí)行另一個(gè)Servlet)
            // 轉(zhuǎn)發(fā)是服務(wù)器內(nèi)部的操作,“/” 不要加項(xiàng)目名
            // request.getRequestDispatcher("/dept/list/").forward(request,response);

            // 優(yōu)化使用重定向,自發(fā)前端(需要指明項(xiàng)目名)
            response.sendRedirect(request.getContextPath() + "/dept/list");

        }
    }


    /**
     * 保存部門信息
     *
     * @param request
     * @param response
     */
    private void doSave(HttpServletRequest request, HttpServletResponse response) throws IOException {

        request.setCharacterEncoding("UTF-8");

        // 獲取到前端的數(shù)據(jù),建議 name 使用復(fù)制
        String deptno = request.getParameter("deptno");
        String dname = request.getParameter("dname");
        String loc = request.getParameter("loc");

        // 連接數(shù)據(jù)庫,添加數(shù)據(jù)
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        // 影響數(shù)據(jù)庫的行數(shù)
        int count = 0;

        try {
            // 1. 注冊(cè)驅(qū)動(dòng),連接數(shù)據(jù)庫
            connection = DBUtil.getConnection();

            // 2. 獲取操作數(shù)據(jù)庫對(duì)象,預(yù)編譯sql語句,Sql測(cè)試
            String sql = "insert into dept(depton,dname,loc) values(?,?,?)";
            preparedStatement = connection.prepareStatement(sql);

            // 3. 填充占位符, 真正執(zhí)行sql語句,
            // 注意: 占位符的填充是從 1 開始的,基本上數(shù)據(jù)庫相關(guān)的起始下標(biāo)索引都是從 1下標(biāo)開始的
            preparedStatement.setString(1, deptno);
            preparedStatement.setString(2, dname);
            preparedStatement.setString(3, loc);

            // 返回影響數(shù)據(jù)庫的行數(shù)
            count = preparedStatement.executeUpdate();

            // 5.釋放資源
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            DBUtil.close(connection, preparedStatement, null);
        }

        // 保存成功,返回部門列表頁面
        if (count == 1) {
            // 這里應(yīng)該使用,重定向
            // 這里用的轉(zhuǎn)發(fā),是服務(wù)器內(nèi)部的,不要加項(xiàng)目名
            //request.getRequestDispatcher("/dept/list/").forward(request, response);

            // 重定向
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }
    }


    /**
     * 通過部門刪除部門
     *
     * @param request
     * @param response
     */
    private void doElete(HttpServletRequest request, HttpServletResponse response) throws IOException {

        request.setCharacterEncoding("UTF-8");  // 設(shè)置獲取的的信息的編碼集
        // 獲取到發(fā)送數(shù)據(jù)
        String deptno = request.getParameter("deptno");

         /*
        根據(jù)部門編號(hào)刪除信息,
        刪除成功,跳轉(zhuǎn)回原來的部門列表頁面
        刪除失敗,跳轉(zhuǎn)刪除失敗的頁面
         */

        Connection connection = null;
        PreparedStatement preparedStatement = null;

        // 記錄刪除數(shù)據(jù)庫的行數(shù)
        int count = 0;


        // 連接數(shù)據(jù)庫進(jìn)行刪除操作

        try {
            // 1.注冊(cè)驅(qū)動(dòng),連接數(shù)據(jù)庫
            connection = DBUtil.getConnection();

            // 開啟事務(wù)(取消自動(dòng)提交機(jī)制),實(shí)現(xiàn)可回滾
            connection.setAutoCommit(false);

            // 2. 預(yù)編譯sql語句,sql測(cè)試
            String sql = "delete from dept where depton = ?"; // ? 占位符
            preparedStatement = connection.prepareStatement(sql);

            // 3. 填充占位符,真正的執(zhí)行sql語句
            preparedStatement.setString(1, deptno);
            // 返回影響數(shù)據(jù)庫的行數(shù)
            count = preparedStatement.executeUpdate();
            connection.commit();  // 手動(dòng)提交數(shù)據(jù)
        } catch (SQLException e) {
            // 遇到異?;貪L
            if (connection != null) {
                try {
                    // 事務(wù)的回滾
                    connection.rollback();
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
            }
            throw new RuntimeException(e);
        } finally {
            // 4. 釋放資源
            // 因?yàn)檫@里是刪除數(shù)據(jù),沒有查詢操作,所以 沒有 ResultSet 可以傳null
            DBUtil.close(connection, preparedStatement, null);
        }

        if (count == 1) {
            // 刪除成功
            // 仍然跳轉(zhuǎn)到部門列表頁面
            // 部門列表頁面的顯示需要執(zhí)行另外一個(gè)Servlet,怎么辦,可以使用跳轉(zhuǎn),不過這里最后是使用重定向
            // 注意:轉(zhuǎn)發(fā)是在服務(wù)器間的,所以不要加“項(xiàng)目名” 而是 / + web.xml 映射的路徑即可
            //request.getRequestDispatcher("/dept/list/").forward(request,response);

            // 優(yōu)化:使用重定向機(jī)制 注意: 重定向是自發(fā)到前端的地址欄上的,前端所以需要指明項(xiàng)目名
            // 注意: request.getContextPath() 返回的根路徑是,包含了 "/" 的
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }
    }


    /**
     * 通過部門編號(hào),查詢部門的詳情
     *
     * @param request
     * @param response
     */
    private void doDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");  // 設(shè)置獲取的的信息的編碼集

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        // 獲取到部門編號(hào)
        String dno = request.getParameter("dno");
        Dept dept = new Dept();

        // 獲取到部門編號(hào),獲取部門信息,將部門信息收集好,然后跳轉(zhuǎn)到JSP做頁面展示


        try {
            // 2. 連接數(shù)據(jù)庫,根據(jù)部門編號(hào)查詢數(shù)據(jù)庫
            // 1.注冊(cè)驅(qū)動(dòng),連接數(shù)據(jù)庫
            connection = DBUtil.getConnection();

            // 2. 預(yù)編譯SQL語句,sql要測(cè)試
            String sql = "select dname,loc from dept where depton = ?";  // ? 占位符
            preparedStatement = connection.prepareStatement(sql);

            // 3. 填充占位符,真正執(zhí)行sql語句
            preparedStatement.setString(1, dno);
            resultSet = preparedStatement.executeQuery();

            // 4. 處理查詢結(jié)果集
            while (resultSet.next()) {
                String dname = resultSet.getString("dname");
                String loc = resultSet.getString("loc");

                // 封裝對(duì)象(建議使用咖啡豆,因?yàn)橹挥幸粋€(gè)對(duì)象)
                dept.setDeptno(dno);
                dept.setDname(dname);
                dept.setLoc(loc);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            // 5. 釋放資源
            DBUtil.close(connection, preparedStatement, resultSet);
        }

        // 這個(gè)咖啡豆只有一個(gè),所以不需要袋子,只需要將這個(gè)咖啡豆放到request請(qǐng)求域當(dāng)中,
        // 用于對(duì)應(yīng)的 jsp顯示
        request.setAttribute("dept", dept);
        //String sign = request.getParameter("f");

        /*if("m".equals(sign)) {

            // 轉(zhuǎn)發(fā):多個(gè)請(qǐng)求為一個(gè)請(qǐng)求(地址欄不會(huì)發(fā)生改變)
            // 注意: 該路徑默認(rèn)是從 web 開始找的 / 表示 web
            // 轉(zhuǎn)發(fā)到修改頁面
            request.getRequestDispatcher("/edit.jsp").forward(request,response);
        } else if("d".equals(sign)) {
            // 跳轉(zhuǎn)到詳情頁面
            request.getRequestDispatcher("/detail.jsp").forward(request,response);
        }*/

        // 或者優(yōu)化
        // 注意 無論是轉(zhuǎn)發(fā)還是重定向都是從 “/” 開始的
        // request.getParameter()拿到的是 f=edit,還是f=detail 就是跳轉(zhuǎn)到的哪個(gè)頁面
        //<a href="<%=request.getContextPath()%>/dept/detail?f=edit&dno=<%=dept.getDeptno()%>">修改</a>
        //<a href="<%=request.getContextPath()%>/dept/detail?f=detail&dno=<%=dept.getDeptno()%>">詳情</a>
        String forward = "/" + request.getParameter("f") + ".jsp";
        request.getRequestDispatcher(forward).forward(request, response);
    }


    /**
     * 連接數(shù)據(jù)庫,查詢所有的部門信息,將部門信息收集好,然后跳轉(zhuǎn)到JSP頁面展示
     *
     * @param request
     * @param response
     */
    private void doList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");  // 設(shè)置獲取的的信息的編碼集
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        // 創(chuàng)建一個(gè)集合List 存儲(chǔ)查詢到的信息
        List<Dept> depts = new ArrayList<Dept>();


        try {
            // 連接數(shù)據(jù)庫,查詢所有部門:
            // 1. 注冊(cè)驅(qū)動(dòng),獲取連接
            connection = DBUtil.getConnection();
            // 2. 獲取操作數(shù)據(jù)庫對(duì)象,預(yù)編譯sql語句
            String sql = "select depton as det,dname,loc from dept"; // 在mysql中測(cè)試一下是否正確
            preparedStatement = connection.prepareStatement(sql);

            // 3. 執(zhí)行sql語句
            resultSet = preparedStatement.executeQuery();

            // 4. 處理查詢結(jié)果集
            while (resultSet.next()) {
                String det = resultSet.getString("det");  // 有別名要使用別名
                String dname = resultSet.getString("dname");
                String loc = resultSet.getString("loc");

                Dept dept = new Dept(det, dname, loc);

                // 將部門對(duì)象放到List集合當(dāng)中
                depts.add(dept);

            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {

            // 5. 關(guān)閉資源
            DBUtil.close(connection, preparedStatement, resultSet);
        }


        // 查詢到數(shù)據(jù),將數(shù)據(jù)提交給 list.jsp 顯示數(shù)據(jù)
        // 將集合存儲(chǔ)的數(shù)據(jù)放到請(qǐng)求域當(dāng)中,用于其他Servlet 使用 jsp 也是Servelt
        request.setAttribute("depList", depts);

        // 轉(zhuǎn)發(fā)(注意不要重定向),重定向無法共用 request 請(qǐng)求域當(dāng)中的數(shù)據(jù)
        // 轉(zhuǎn)發(fā)路徑,/ 默認(rèn)是從 web 目錄開始找的
        request.getRequestDispatcher("/list.jsp").forward(request, response);
    }
}

用戶界面的優(yōu)化:顯示 登錄的用戶名:(該用戶名信息,從 存儲(chǔ)到 session 會(huì)話對(duì)象當(dāng)中,獲取到的。)

核心代碼如下:

需要注意的點(diǎn)就是:這里我們使用的是 JSP 內(nèi)置的 session 對(duì)象,所以在這個(gè) JSP頁面當(dāng),你不可以把 session 禁用了。

不要設(shè)置這個(gè)禁用 session 的指令: <%@page session = false %>

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

優(yōu)化演示:

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

8. 總結(jié):

  1. session 會(huì)話用戶場(chǎng)景:在Web應(yīng)用程序中,我們經(jīng)常要跟蹤用戶身份。當(dāng)一個(gè)用戶登錄成功后,如果他繼續(xù)訪問其他頁面,Web程序如何才能識(shí)別出該用戶身份?
  2. session對(duì)象最主要的作用是:保存會(huì)話狀態(tài)。
  3. 為什么要保存會(huì)話狀態(tài):因?yàn)镠TTP協(xié)議是一種無狀態(tài)協(xié)議。
    • 無狀態(tài):
      • 優(yōu)點(diǎn):這樣服務(wù)器壓力小。
      • 缺點(diǎn):服務(wù)器無法知道客戶端的狀態(tài)(是關(guān)閉的狀態(tài),還是開啟的狀態(tài))
  4. 一個(gè) session 會(huì)話當(dāng)中包含多次請(qǐng)求(一次會(huì)話對(duì)應(yīng)N次請(qǐng)求。)
  5. session 對(duì)象是用服務(wù)器端生成的,所以這里是通過 request 請(qǐng)求的方式向服務(wù)器獲取到一個(gè) session 會(huì)話對(duì)象
  6. session 的生成,銷毀,傳遞的原理機(jī)制:

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)

  1. 簡(jiǎn)單的來說吧 ,session 就是一個(gè)標(biāo)記,通過標(biāo)記 JSESSIONID 獲取到同一個(gè) session 對(duì)象,保證你對(duì)應(yīng)的操作是同一個(gè)用戶。
  2. Cookie禁用了,session還能找到嗎 ? 可以,使用 URL重寫機(jī)制。
  3. 實(shí)現(xiàn)用戶登錄,通過 session 會(huì)話機(jī)制(保存用戶登錄信息),實(shí)現(xiàn)用戶登錄成功,可以通過 URL 直接訪問資源,沒有登錄/登錄失敗,則無法直接通過 URL 訪問資源。

9. 最后:

限于自身水平,其中存在的錯(cuò)誤,希望大家給予指教,韓信點(diǎn)兵——多多益善,謝謝大家,江湖再見,后悔有期

B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)文章來源地址http://www.zghlxwxcb.cn/news/detail-429298.html

到了這里,關(guān)于B/S結(jié)構(gòu)系統(tǒng)的會(huì)話機(jī)制(session)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • web學(xué)習(xí)--Cookie與Session會(huì)話技術(shù)

    1.概念:客戶端會(huì)話技術(shù),將數(shù)據(jù)保存在客戶端 使用步驟: 1,創(chuàng)建Cookie對(duì)象,綁定數(shù)據(jù) 2.發(fā)送Cookie對(duì)象 3.獲取Cookie,拿到數(shù)據(jù) WebServlet(\\\"/Demo1\\\") public class CookidDemo1 extends HttpServlet { ? ? @Override ? ? protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException

    2024年02月13日
    瀏覽(22)
  • 微信小程序獲取文件session會(huì)話無效

    微信小程序獲取圖片文件時(shí)session會(huì)話失效,可以將圖片文件地址請(qǐng)求修改為post請(qǐng)求,返回文件流以base64編碼輸出。 具體請(qǐng)求方式如下:

    2024年02月15日
    瀏覽(20)
  • JAVAWeb10-Web 開發(fā)會(huì)話技術(shù)-Session-02

    JAVAWeb10-Web 開發(fā)會(huì)話技術(shù)-Session-02

    ● 思考兩個(gè)問題—拋磚引玉 不同的用戶登錄網(wǎng)站后,不管該用戶瀏覽該網(wǎng)站的哪個(gè)頁面,都可顯示登錄人的名字,還可以隨時(shí)去查看自己的購物車中的商品, 是如何實(shí)現(xiàn)的? 也就是說,一個(gè)用戶在瀏覽網(wǎng)站不同頁面時(shí),服務(wù)器是如何知道是張三在瀏覽這個(gè)頁面,還是李四在瀏

    2024年02月01日
    瀏覽(22)
  • Django基礎(chǔ)7——用戶認(rèn)證系統(tǒng)、Session管理、CSRF安全防護(hù)機(jī)制

    Django基礎(chǔ)7——用戶認(rèn)證系統(tǒng)、Session管理、CSRF安全防護(hù)機(jī)制

    Django內(nèi)置一個(gè)用戶認(rèn)證系統(tǒng),使用auth模塊實(shí)現(xiàn)。 auth模塊提供了登錄、注冊(cè)、效驗(yàn)、修改密碼、注銷、驗(yàn)證用戶是否登錄等功能。 Django默認(rèn)創(chuàng)建的數(shù)據(jù)庫表。 表名 作用 auth_user 用戶表 auth_user_groups 用戶所屬組的表 auth_user_user_permissions 用戶權(quán)限表 auth_group 用戶組表 auth_group_

    2024年02月11日
    瀏覽(17)
  • 會(huì)話跟蹤技術(shù)學(xué)習(xí)筆記(Cookie+Session)+ HTTP學(xué)習(xí)筆記

    會(huì)話跟蹤技術(shù)學(xué)習(xí)筆記(Cookie+Session)+ HTTP學(xué)習(xí)筆記

    1.1 Cookie 1. Cookie:是一種客戶端會(huì)話技術(shù),數(shù)據(jù)會(huì)被保存在客戶端,Cookie會(huì)攜帶數(shù)據(jù)訪問服務(wù)器,用以完成一次會(huì)話內(nèi)多次請(qǐng)求間的數(shù)據(jù)共享 2. 過程:瀏覽器(客戶端)先向服務(wù)端發(fā)送請(qǐng)求,服務(wù)端會(huì)發(fā)送一個(gè)Cookie給客戶端,在此后同一次會(huì)話中,每次客戶端都會(huì)將Cookie發(fā)送

    2024年02月10日
    瀏覽(26)
  • Servlet【 ServletAPI中的會(huì)話管理Cookie與Session】

    Servlet【 ServletAPI中的會(huì)話管理Cookie與Session】

    HTTP 協(xié)議自身是屬于 “無狀態(tài)” 協(xié)議. “無狀態(tài)” 的含義指的是: 默認(rèn)情況下 HTTP 協(xié)議的客戶端和服務(wù)器之間的這次通信, 和下次通信之間沒有直接的聯(lián)系.但是實(shí)際開發(fā)中, 我們很多時(shí)候是需要知道請(qǐng)求之間的關(guān)聯(lián)關(guān)系的. 例如登陸網(wǎng)站成功后, 第二次訪問的時(shí)候服務(wù)器就能知

    2024年02月09日
    瀏覽(60)
  • 如何在個(gè)人web項(xiàng)目中使用會(huì)話技術(shù)(cookie&session)?

    如何在個(gè)人web項(xiàng)目中使用會(huì)話技術(shù)(cookie&session)?

    編譯軟件:IntelliJ IDEA 2019.2.4 x64 操作系統(tǒng):win10 x64 位 家庭版 服務(wù)器軟件:apache-tomcat-8.5.27 翻開百度百科關(guān)于“ 會(huì)話 ”的詞條,它是這樣描述:“ 在計(jì)算機(jī)術(shù)語中,會(huì)話是指一個(gè)終端用戶與交互系統(tǒng)進(jìn)行通訊的過程,比如從輸入賬戶密碼進(jìn)入操作系統(tǒng)到退出操作系統(tǒng)就是一

    2023年04月22日
    瀏覽(32)
  • 如何讓你的會(huì)話更安全,淺析Session與Cookie

    如何讓你的會(huì)話更安全,淺析Session與Cookie

    ????????在我們面試的時(shí)候,面試官問及 XSS 漏洞的時(shí)候,我們常常會(huì)說比如劫持 Cookie,問及防御方法的時(shí)候,又常常會(huì)說設(shè)置 httponly ,本篇文章將從代碼層面簡(jiǎn)單的普及 Session 和 Cookie 的生成過程,及防御的方法,希望看到這篇文章后,下一次遇到面試官的時(shí)候,你能夠

    2024年02月22日
    瀏覽(21)
  • 【python】flask基于cookie和session來實(shí)現(xiàn)會(huì)話控制

    【python】flask基于cookie和session來實(shí)現(xiàn)會(huì)話控制

    ?? 歡迎大家來到景天科技苑?? ???? 養(yǎng)成好習(xí)慣,先贊后看哦~???? ?? 作者簡(jiǎn)介:景天科技苑 ??《頭銜》:大廠架構(gòu)師,華為云開發(fā)者社區(qū)專家博主,阿里云開發(fā)者社區(qū)專家博主,CSDN新星創(chuàng)作者,掘金優(yōu)秀博主,51CTO博客專家等。 ??《博客》:Python全棧,前后端開

    2024年03月24日
    瀏覽(24)
  • 【Python】Web學(xué)習(xí)筆記_flask(6)——會(huì)話&session對(duì)象

    【Python】Web學(xué)習(xí)筆記_flask(6)——會(huì)話&session對(duì)象

    處理利用cookie來判斷用戶登錄外,也可以使用session來判斷用戶是否登錄 html代碼和cookie對(duì)象的設(shè)置相同 ? ?

    2024年02月12日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包