JavaWeb-Session

1. Session簡(jiǎn)單介紹

在WEB開(kāi)發(fā)中,服務(wù)器可以為每個(gè)瀏覽器用戶創(chuàng)建一個(gè)會(huì)話對(duì)象 ( session對(duì)象),注意:一個(gè)瀏覽器用戶獨(dú)占一個(gè)session對(duì)象(默認(rèn)情況下)。 因此,在需要保存用戶數(shù)據(jù)時(shí),服務(wù)器程序可以把用戶數(shù)據(jù)寫到瀏覽器用戶獨(dú)占的session中,當(dāng)用戶使用瀏覽器訪問(wèn)該web應(yīng)用的其它servlet時(shí),其它servlet可以從用戶的session中取出該用戶的數(shù)據(jù),為用戶服務(wù),從而實(shí)現(xiàn)數(shù)據(jù)在多個(gè)頁(yè)面中的共享。

2. Session和Cookie的主要區(qū)別

  • Cookie是把用戶的數(shù)據(jù)寫到用戶的瀏覽器。
  • Session技術(shù)把用戶的數(shù)據(jù)寫到用戶獨(dú)占的session中,tomcat服務(wù)器內(nèi)存中。
  • Session對(duì)象由服務(wù)器(Tomcat)創(chuàng)建,開(kāi)發(fā)人員可以調(diào)用request對(duì)象的getSession()方法得到session對(duì)象

3. session機(jī)制演示圖

image.png
image.png

服務(wù)器通過(guò)request對(duì)象的getSession方法創(chuàng)建出session對(duì)象后,會(huì)把session的id號(hào),以cookie的形式回寫給客戶機(jī),這樣,只要客戶機(jī)的瀏覽器不關(guān),再去訪問(wèn)服務(wù)器時(shí),都會(huì)帶著session的id號(hào)去,服務(wù)器發(fā)現(xiàn)客戶機(jī)瀏覽器帶session id過(guò)來(lái)了,就會(huì)使用內(nèi)存中與之對(duì)應(yīng)的session為之服務(wù)。

前臺(tái)頁(yè)面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="session.do">第一次訪問(wèn)session.do</a>
<a href="sessiontest.do">第二次訪問(wèn)sessiontest.do</a>
</body>
</html>

第一次訪問(wèn)

package com.lty.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

@WebServlet(name = "SessionServlet" ,urlPatterns = "/session.do")
public class SessionServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 每一個(gè)session對(duì)象都存在著唯一的ID
        HttpSession httpSession = request.getSession();
        httpSession.setAttribute("user","zhangsan");
        System.out.println(httpSession.getId());

        // Tomcat服務(wù)器默默做的一件事
//        Cookie cookie = new Cookie("JSESSIONID",httpSession.getId());
//        response.addCookie(cookie);
    }
}

第二次訪問(wèn)

package com.lty.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet(name = "SessionTestServlet",urlPatterns = "/sessiontest.do")
public class SessionTestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 獲取第一次服務(wù)器創(chuàng)建給用戶的Session
        HttpSession httpSession = request.getSession();
        String username = (String)httpSession.getAttribute("user");
        System.out.println(username);
        System.out.println( httpSession.getId());
    }
}
image.png

4. Session cookie

session通過(guò)SessionID來(lái)區(qū)分不同的客戶,session是以cookie為基礎(chǔ)的,系統(tǒng)會(huì)創(chuàng)造一個(gè)名為JSESSIONID的輸出cookie ,這稱之為session cookie,以區(qū)別persistent cookies(也就是我們通常所說(shuō)cookie),session cookie是存儲(chǔ)于瀏覽器內(nèi)存中的,并不是寫到硬盤上的, session cookie針對(duì)某一次會(huì)話而言,會(huì)話結(jié)束session cookie也就隨著消失了,而persistent cookie只是存在于客戶端硬盤上的一段文本。

關(guān)閉瀏覽器,只會(huì)使瀏覽器端內(nèi)存里的session cookie消失,但不會(huì)使保存在服務(wù)器端的session對(duì)象消失,同樣也不會(huì)使已經(jīng)保存到硬盤上的持久化cookie消失。

持久化Session cookie
關(guān)閉瀏覽器,一小時(shí)之內(nèi)打開(kāi)瀏覽器,session仍然有效(通過(guò)使用cookie類的setMaxAge(秒)方法設(shè)置持久化的時(shí)效)

package com.lty.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

@WebServlet(name = "TestServlet",urlPatterns = "/test")
public class TestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession httpSession = request.getSession();
        Cookie cookie = new Cookie("JSESSIONID",httpSession.getId());
        cookie.setMaxAge(60*60);// 關(guān)閉瀏覽器,一小時(shí)之內(nèi)打開(kāi)瀏覽器,session仍然有效
    }
}

5. HttpSession的生命周期

問(wèn)題:用戶開(kāi)一個(gè)瀏覽器訪問(wèn)一個(gè)網(wǎng)站,服務(wù)器是不是針對(duì)這次會(huì)話創(chuàng)建一個(gè)session?
答:不是的。session的創(chuàng)建時(shí)機(jī)是在程序中第一次去執(zhí)行request.getSession();這個(gè)代碼,服務(wù)器才會(huì)為你創(chuàng)建session。
問(wèn)題:關(guān)閉瀏覽器,會(huì)話結(jié)束,session是不是就銷毀了呢?
答:不是的。session是30分鐘(默認(rèn)30分鐘)沒(méi)人用了才會(huì)死,服務(wù)器會(huì)自動(dòng)摧毀session。

session何時(shí)會(huì)銷毀
(1)調(diào)用invalidate()方法,該方法使HttpSession立即失效

package com.lty.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

@WebServlet(name = "TestServlet",urlPatterns = "/test")
public class TestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession httpSession = request.getSession();
        httpSession.invalidate();
    }
}

(2)服務(wù)器卸載了當(dāng)前WEB應(yīng)用
(3)超出session過(guò)期時(shí)間

package com.lty.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

@WebServlet(name = "TestServlet",urlPatterns = "/test")
public class TestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession httpSession = request.getSession();
        httpSession.setMaxInactiveInterval(10);// 單位: 秒
    }
}

web.xml文件中也可以修改session的過(guò)期時(shí)間(全局的,所有的session的過(guò)期時(shí)間,若想單獨(dú)設(shè)置還是需要像上面那樣進(jìn)行單獨(dú)session設(shè)置),單位:分鐘

<?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">
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
</web-app>

6. session小練習(xí)(利用session完成用戶登錄)

java實(shí)體類對(duì)象 User.java

package com.lty.bean;

public class User {
    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

DB java類(利用list集合來(lái)模擬向數(shù)據(jù)庫(kù)中查詢用戶信息的操作過(guò)程)

package com.lty.bean;

import java.util.ArrayList;
import java.util.List;

public class DB {
    public static List<User> list = new ArrayList<User>();

    static{
        list.add(new User("aaa","123"));
        list.add(new User("bbb","123"));
        list.add(new User("ccc","123"));
    }
    public static List<User> getAll(){
        return list;
    }
}

主頁(yè)面index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  歡迎你:${user.username}
  <a href="login.jsp">登錄</a>
  <a href="LogoutServlet">退出登錄</a>
  <br>

  <a href="SessionDemo1">購(gòu)買</a>
  <br>
  </body>
</html>

登錄頁(yè)面 login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="LoginServlet" method="post">
    用戶名:<input type="text" name="username">
    密碼:<input type="password" name="password">
    <input type="submit" value="登錄">
</form>
</body>
</html>

購(gòu)買頁(yè)面 SessionDemo1.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
歡迎你:${user.username}
</body>
</html>

后臺(tái)servlet

package com.lty.servlet;

import com.lty.bean.DB;
import com.lty.bean.User;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

@WebServlet(name = "LoginServlet" , urlPatterns = "/LoginServlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");

        PrintWriter out = response.getWriter();
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        List<User> list = DB.getAll();
        for(User user : list){
            // 用戶登錄成功
            if(user.getUsername().equals(username) && user.getPassword().equals(password)){
                request.getSession().setAttribute("user",user);
                response.sendRedirect("index.jsp");
                return;
            }
        }

        out.print("用戶名或密碼不正確?。?!");
    }

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

    }
}
package com.lty.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "LogoutServlet" , urlPatterns = "/LogoutServlet")
public class LogoutServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 立即徹底銷毀當(dāng)前session對(duì)象
        request.getSession().invalidate();

        response.sendRedirect("index.jsp");
    }
}
package com.lty.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "SessionDemo1" , urlPatterns = "/SessionDemo1")
public class SessionDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher("SessionDemo1.jsp").forward(request,response);
    }
}

7. 使用Session實(shí)現(xiàn)驗(yàn)證碼

Session的典型案例:一次性驗(yàn)證碼
java工具類 GenerateCode.java(將隨機(jī)生成的由四個(gè)字符組成的字符串用圖片進(jìn)行渲染)

package com.lty.util;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class GenerateCode {

    // 設(shè)置驗(yàn)證碼圖片的寬度,高度,驗(yàn)證碼的個(gè)數(shù)
    private int width = 152;
    private int height = 40;

    // 驗(yàn)證碼字體的高度
    private int fontHeight = 38;

    // 驗(yàn)證碼中的單個(gè)字符基線。即:驗(yàn)證碼中的單個(gè)字符位于驗(yàn)證碼圖形左上角的(codeX,codeY)位置處
    private int codeX = 25;
    private int codeY = 36;

    public BufferedImage Generate(String code){

        // 定義一個(gè)類型為 BufferedImage.TYPE_INT_BGR 類型的圖像緩存
        BufferedImage buffImg = null;
        buffImg = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);

        // 在 buffImg 中創(chuàng)建一個(gè) Graphics2D 圖像
        Graphics2D graphics = null;
        graphics = buffImg.createGraphics();

        // 設(shè)置一個(gè)顏色,使 Graphics2D 對(duì)象的后續(xù)圖形使用這個(gè)顏色
        graphics.setColor(Color.WHITE);

        // 填充一個(gè)指定的矩形:x - 要填充矩形的 x 坐標(biāo); y - 要填充矩形的 y 坐標(biāo); width - 要填充矩形的寬度; height - 要填充矩形的高度
        graphics.fillRect(0,0,width,height);

        // 創(chuàng)建一個(gè) Font 對(duì)象:name - 字體名稱; style - Font 的樣式常量; size - Font 的點(diǎn)大小
        Font font = null;
        font = new Font("",Font.BOLD,fontHeight);
        // 使 Graphics2D 對(duì)象的后續(xù)圖形使用此字體
        graphics.setFont(font);
        graphics.setColor(Color.BLACK);

        // 繪制指定矩形的邊框,繪制出的矩形將比構(gòu)件寬一個(gè)也高一個(gè)像素
        graphics.drawRect(0,0,width - 1,height - 1);

        // 隨機(jī)產(chǎn)生 15 條干擾線,使圖像中的驗(yàn)證碼不易被其它程序探測(cè)到
        Random random = null;
        random = new Random();
        graphics.setColor(Color.GREEN);
        for(int i = 0; i < 30; i++){
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int x1 = random.nextInt(20);
            int y1 = random.nextInt(20);
            graphics.drawLine(x,y,x + x1,y + y1);
        }

        graphics.setColor(Color.BLACK);
        for(int i = 0;i < code.length();i++){

            // 用隨機(jī)產(chǎn)生的顏色將驗(yàn)證碼繪制到圖像中
            graphics.drawString(String.valueOf(code.charAt(i)),(i + 1)* codeX,codeY);
        }

        return buffImg;
    }
}

測(cè)試生成驗(yàn)證碼圖片的java類(將生成的驗(yàn)證碼圖片保存到電腦磁盤中)

package com.lty.util;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        GenerateCode generateCode = new GenerateCode();
        BufferedImage bufferedImage = generateCode.Generate("lisi");

        // 把圖片保存到磁盤
        FileOutputStream fileOutputStream = new FileOutputStream("d:/abc.jpg");
        ImageIO.write(bufferedImage,"jpeg",fileOutputStream);
        System.out.println("成功");

    }
}

登錄頁(yè)面 login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script>
        window.onload = function () {
            var img = document.getElementById('code');
            img.onclick = function () {
                var d = new Date();
                // alert(d.getTime());
                // 為了讓瀏覽器感覺(jué)到每一次請(qǐng)求的地址不一樣(不會(huì)使用之前緩存的圖片),每一次都會(huì)發(fā)出新的請(qǐng)求,使服務(wù)器生成新的驗(yàn)證碼
                img.src = "ValidateColorServlet?time=" + d.getTime();
            }
        }
    </script>
</head>
<body>
<form action="LoginServlet" method="post">
    username:<input type="text" name="username">
    驗(yàn)證碼:<input type="text" name="check">
    <img src="ValidateColorServlet" id="code">
    <input type="submit" value="登錄">
</form>
</body>
</html>

后臺(tái)servlet 隨機(jī)生成四位驗(yàn)證碼

package com.lty.servlet;

import com.lty.util.GenerateCode;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet(name = "ValidateColorServlet" , urlPatterns = "/ValidateColorServlet")
public class ValidateColorServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        System.out.println("ValidateColorServlet");
        //回應(yīng)一張圖片的全部字節(jié) --- 圖片由一堆字節(jié)構(gòu)成 瀏覽器進(jìn)行解析 顯示成圖片
        //這張圖片是一個(gè)驗(yàn)證碼圖片
        //1.在內(nèi)存中生成這張圖片
        //1.1圖片上的文字如何生成?
        //隨機(jī)生成一個(gè)4個(gè)字符的字符串(a-z,0-9組成)
        char [] codeSequence = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789".toCharArray();
        String code = "";
        for(int i = 0; i < 4; i++){
            Random random = new Random();
            int index = random.nextInt(codeSequence.length);
            char c = codeSequence[index];
            code += c;
        }

        System.out.println(code);

        request.getSession().setAttribute("code",code);

        GenerateCode generateCode = new GenerateCode();
        BufferedImage bufferedImage = generateCode.Generate(code);

        // 向客戶端瀏覽器進(jìn)行輸出
        ServletOutputStream outputStream = response.getOutputStream();
        ImageIO.write(bufferedImage,"jpeg",outputStream);
    }
}

校驗(yàn)用戶輸入的驗(yàn)證碼與隨機(jī)生成的驗(yàn)證碼的一致性

package com.lty.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "LoginServlet" , urlPatterns = "/LoginServlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String checkcode = request.getParameter("check");// 用戶輸入的驗(yàn)證碼
        String genCode = (String) request.getSession().getAttribute("code");// 當(dāng)時(shí)隨機(jī)生成的驗(yàn)證碼
        if(checkcode.equalsIgnoreCase(genCode)){
            response.getWriter().println("驗(yàn)證碼正確");
        }else{
            response.getWriter().println("驗(yàn)證碼不正確");
        }

    }

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

    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容