JavaWeb学习(4)(四大域、HttpSession原理(面试)、SessionAPI、Session实现验证码功能)

news2024/12/12 14:02:55

目录

一、web四大域。

(1)基本介绍。

(2)RequestScope。(请求域)

(3)SessionScope。(会话域)

(4)ApplicationScope。(应用域)

(5)PageScope。(页面域)

二、HttpSession原理。

(1)Session的基本介绍。

(2)会话是什么?

1、会话的基本介绍。

2、会话的生命周期。

(3)HttpSession接口API。

1、HttpSession域对象功能。

2、HttpSession特有方法与属性。

(4)HttpSession底层原理。

1、Session的最基本特征。

2、Session底层图解。

3、Session底层解释。

4、Session自动失效与手动失效。

三、使用Session实现验证码与注销功能。

(1)前端jsp:表单项-验证码的代码。

(2)生成验证码的Servlet类。

(3)运行效果图。

(4)最终验证码的实现步骤。

1、第一次请求与响应。

2、第二次请求与响应。

3、第三次请求与响应。

4、LoginServlet类代码。


一、web四大域。

(1)基本介绍。
  • 在JavaWeb开发中,"四大域"是指四种不同的作用域(scope),它们用于存储和管理用户会话中的数据

(2)RequestScope。(请求域)

  • 作用域限定在"一次请求"中。即一个Servlet处理一个客户端请求的过程中。

  • 其数据存储在HttpServl
    etRequest对象中。
  • 常用于存储一次请求中需要的数据,比如表单提交的数据。
  • 使用次数:较多。

(3)SessionScope。(会话域)
  • 作用域限定在"一个用户会话"中。即从用户打开浏览器到关闭浏览器的整个过程中。

  • 数据存储在HttpSession对象中。
  • 常用于存储用户登录状态、用户偏好设置等需要跨多个请求保持的数据
  • 使用次数:多。

(4)ApplicationScope。(应用域)
  • 作用域限定在"整个Web应用程序"中。即所有用户共享

  • 数据存储在ServletContext对象ServletContext中。
  • 常用于存储全局信息。(比如配置信息、应用级别的计数器等)
  • 使用次数:较少。

(5)PageScope。(页面域)

  • 作用域限定在"JSP页面的生命周期"内。即从JSP页面被请求到页面渲染完成的过程中。

  • 数据存储在JSP页面的隐式对象pageContext中。
  • 常用于存储JSP页面内的数据,比如JSP标签和脚本片段之间的数据共享。
  • 使用次数:较少。

二、HttpSession原理。

(1)Session的基本介绍。
  • 在JavaWeb开发中,Session通常指的是HttpSession接口
  • HttpSession是Java Servlet API提供的一个接口。
  • HttpSession的对象代表了客户端与服务器端之间的一个会话。用于在客户端和服务器端之间保持状态,即跟踪用户的会话
(2)会话是什么?
1、会话的基本介绍。
  • 在Web开发中,会话(Session)是指服务器与客户端之间的一次连续的交互过程,它允许服务器跟踪和存储用户的状态信息。

  • 客户端打开浏览器,访问服务器,表示会话开始。只要浏览器不关闭,本次会话一直存在。而且这次的会话的所有请求,全部共享一个Session域。(request域对象,只在用一次请求有效,作用域小
  • 当客户端关闭浏览器,表示会话的结束。

  • 每一个客户端都有自己的会话。(Session)

2、会话的生命周期。
  • 会话有开始和结束。
  • 通常:从用户第一次与服务器交互时创建,直到用户关闭浏览器。
  • 其它情况:话超时服务器配置的最大会话时间限制。

(3)HttpSession接口API。
  • 查阅javaEE接口文档。


1、HttpSession域对象功能。
  • 如下都是Session的重要方法。
  • 其中有几个四大域对象都有的方法。其它的是Session域对象特有的特性与方法。


2、HttpSession特有方法与属性。
  • SessionID:Session的唯一标识。
  • setMaxInactiveInterval(int):最大间隔时间意思就是该Session从上一次使用到下一次使用的间隔。

  • invalidate():让当前Session失效!用户的退出登录(注销)功能实现就是让当前Session域失效!
  • 注销类"LogOutServlet"代码如下。
package com.fs.web;

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

/**
 * @Title: LoginService
 * @Author HeYouLong
 * @Package com.fs.web
 * @Date 2024/11/25 下午9:16
 * @description: 退出登录处理
 */
@WebServlet("/logout")
public class LogOutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //让session失效
        req.getSession().invalidate();
        //重定向到登录界面
        resp.sendRedirect("/login.jsp");
    }
}
(4)HttpSession底层原理。
1、Session的最基本特征。
  • 创建于服务器,保存于服务器
  • 每一个用户都有自己的Session对象。(Session不是共享的)
  • 底层依赖于——Cookie实现。
2、Session底层图解。
  • 服务器为每一个客户端创建Session对象时,都会生成唯一的SessionID。
  • 响应给客户端时,将SessionID存储在Cookie中。注意SessionID是加密的。Cookie之后的每一次请求会自动的将SessionID发送给服务器。
  • 服务器拿到SessionID进行解析并寻找对应的Session对象。




3、Session底层解释。
  • Session底层是依赖Cookie的!
  • 注意Session无法跨浏览器的。

  • 当我首次去银行时,因为还没有账号,所以需要开一个账号,我获得的是银行卡,而银行这边的数据库中留下了我的账号,我的钱是保存在银行的账号中,而我带走的是我的卡号。
  • 当我再次去银行时,只需要带上我的卡,而无需再次开一个账号了。只要带上我的卡,那么我在银行操作的一定是我的账号!

  • 首次使用Session时,服务器端要创建Session对象Session是保存在服务器端,而给客户端的是SessionID(一个cookie中保存SessionID)。客户端带走的是SessionID,而数据是保存在Session对象中。
  • 客户端再次访问服务器时,在请求中会带上SessionID。而服务器会通过SessionID找到对应的Session对象,而无需再创建新的Session对象。


4、Session自动失效与手动失效。
  • 开发人员可以通过调用Session对象的的invalidate()方法来手动使Session失效。这通常在用户注销或退出登录时使用。


  • Session对象会有一个默认的超时时间,如果用户在这段时间内没有任何操作,Session将会自动失效
  • 当服务器重启或重启应用时,所有的Session对象都会被销毁,导致所有用户的Session失效。或者关闭浏览器通常也会导致Session失效。

三、使用Session实现验证码与注销功能。

(1)前端jsp:表单项-验证码的代码。
  • 注意生成验证码图片的功能是通过代码完成。(访问指定的"/XXXServlet")
  • 注意:css样式使用的是bootstrap提供的样式与组件。通过<link>标签在线引入。
<div class="form-inline">
        <label for="vcode">验证码:</label>
        <input type="text" name="verifycode" class="form-control" id="verifycode" placeholder="请输入验证码" style="width: 120px;"/>
        <a href="javascript:refreshCode()"><img src="/checkCode" title="看不清点击刷新" id="vcode"/></a>
        </div>
  • 刷新验证码时,触发点击事件,调用方法refreshCode()。代码如下。
<script type="text/javascript">
        //js定义函数
        function refreshCode(){
            //不做下面处理,就会走浏览器缓存, url没有变化, 导致使用上一次缓存内容,不会刷新验证码
            //选择器 #id名——>获取到img标签
            //使用attr()设置属性"src"值。
            //加一个时间戳, 每次都不一样, 浏览器发现参数不一样, 误以为是新请求,不走缓存,就会刷新
            $("#vcode").attr("src","/checkCode?"+new Date().getTime());
        }
    </script>
(2)生成验证码的Servlet类。
package com.fs.web;

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

/**
 * 验证码
 */
@WebServlet("/checkCode")
public class CheckCodeServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		
		//服务器通知浏览器不要缓存
		response.setHeader("pragma","no-cache");
		response.setHeader("cache-control","no-cache");
		response.setHeader("expires","0");
		
		//在内存中创建一个长80,宽30的图片,默认黑色背景
		//参数一:长
		//参数二:宽
		//参数三:颜色
		int width = 80;
		int height = 30;
		BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		
		//获取画笔
		Graphics g = image.getGraphics();
		//设置画笔颜色为灰色
		g.setColor(Color.GRAY);
		//填充图片
		g.fillRect(0,0, width,height);
		
		//产生4个随机验证码,12Ey
		String checkCode = getCheckCode();

		//将验证码放入HttpSession中。
        //这里很重要,因为登录请求时,需要拿取服务器生成的验证码与用户输入的验证码进行校验!
		request.getSession().setAttribute("CHECKCODE_SERVER",checkCode);
		
		//设置画笔颜色为黄色
		g.setColor(Color.YELLOW);
		//设置字体的小大
		g.setFont(new Font("黑体",Font.BOLD,24));
		//向图片上写入验证码
		g.drawString(checkCode,15,25);
		
		//将内存中的图片输出到浏览器
		//参数一:图片对象
		//参数二:图片的格式,如PNG,JPG,GIF
		//参数三:图片输出到哪里去
		ImageIO.write(image,"PNG",response.getOutputStream());
	}
	/**
	 * 产生4位随机字符串 
	 */
	private String getCheckCode() {
		String base = "0123456789ABCDEFGabcdefg";
		int size = base.length();
		Random r = new Random();
		StringBuffer sb = new StringBuffer();
		for(int i=1;i<=4;i++){
			//产生0到size-1的随机值
			int index = r.nextInt(size);
			//在base字符串中获取下标为index的字符
			char c = base.charAt(index);
			//将c放入到StringBuffer中去
			sb.append(c);
		}
		return sb.toString();
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request,response);
	}
}



(3)运行效果图。


(4)最终验证码的实现步骤。
1、第一次请求与响应。
  • 第一次请求:客户端请求login.jsp(登录页面)。
  • 服务器第一次响应。在客户端显示login.jsp(登录页面)。

2、第二次请求与响应。
  • 第二次请求"XXXServlet":请求客户端登录界面中的随机验证码图片。

  • 服务器第二次响应。并将生成的随机验证码存储在Session域中。
  • 为什么验证码不存储在Cookie中?不安全、无意义。因为Cookie暴露在客户端,用户可以查看和修改!

  • 随后在登录界面的验证码位置显示生成的验证码图片。


3、第三次请求与响应。
  • 第三次请求:用户在客户端填写(用户名、密码、验证码等)后,点击提交"登录"按钮。也就是登录请求。("/LoginServlet")
  • 服务器处理请求。首先判断验证码是否正确!!

  • 如何校验用户输入的验证码与服务器响应的验证码一致?
  • 在第二次请求与响应中,服务器将生成的随机验证码存储在Session中。因为验证码每生成一次就不能让用户去更改,所以存储在服务器(域对象),而不是存储在客户端
  • 使用Session技术!而不使用Request域。是因为不是同一次请求,拿不到数据。
  • 通过会话(Session)技术可以实现该功能。

  • 第三次请求服务器拿到用户提交的验证码与Session域获取到的验证码进行比对即可。
  • 通过HttpServletRequest对象的getSession()方法获取到HttpSession对象。
  • 再通过HttpSession对象的getAttribute("键名")得到对应的键值(验证码)即可。

4、LoginServlet类代码。
  • 其中涉及到"记住我"功能的实现。(使用Cookie技术)
package com.fs.web;

import com.fs.entity.LoginInfo;
import com.fs.service.LoginService;
import com.fs.service.impl.LoginServiceImpl;

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

/**
 * @Title: LoginService
 * @Author HeYouLong
 * @Package com.fs.web
 * @Date 2024/11/25 下午9:16
 * @description: 登录处理
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.设置post请求编码, 响应编码
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        //进行验证码验证
        //获取用户输入的验证码
        String verifycode = req.getParameter("verifycode");
        //获取服务器发来的验证码。与session存的验证码比对
        HttpSession session = req.getSession();
        String codeServer = (String) session.getAttribute("CHECKCODE_SERVER");
        if (codeServer.equals(verifycode)) {
            //2.获取请求参数
            String username = req.getParameter("user");
            String password = req.getParameter("password");

            //3.调用业务层LoginService的登录方法
            LoginService loginService = new LoginServiceImpl();
            LoginInfo loginInfo = loginService.login(username, password);
            //4.根据返回结果跳转到不同的资源
            if (loginInfo != null) { //登录成功
                //判断是否勾选记住我
                String rem = req.getParameter("rem");
                if (Objects.nonNull(rem)) {
                    //设置Cookie
                    Cookie cookie1 = new Cookie("user", username);
                    Cookie cookie2 = new Cookie("password", password);
                    //设置存活时间(单位:秒)
                    //7天
                    cookie1.setMaxAge(60 * 60 * 24 * 7);
                    cookie2.setMaxAge(60 * 60 * 24 * 7);
                    //设置path为/  项目下任何资源可以访问
                    cookie1.setPath("/");
                    cookie2.setPath("/");
                    //发送Cookie
                    resp.addCookie(cookie1);
                    resp.addCookie(cookie2);
                }
                //跳转之前把LoginInfo对象保存到session域中
                session.setAttribute("loginUser",loginInfo);
                //重定向到index.html页面
                resp.sendRedirect("/index.jsp");
            } else { //登录失败
                //转发到登录页面
                req.setAttribute("error", "账号或密码错误!");
                req.getRequestDispatcher("/login.jsp").forward(req, resp);
            }

        } else { //验证码错误
            req.setAttribute("error", "验证码输入错误!");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        }

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2258274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用人话讲计算机:Python篇!(十二)正则运算+re模块

目录 一、正则表达式 &#xff08;1&#xff09;什么是正则表达式 &#xff08;2&#xff09;它的结构及使用 示例&#xff1a; 1.字符 . &#xff08;←这里有个小点哦&#xff09; 2.字符 | 3.字符 [ ] 4.字符^ 5.字符\d &#xff08;3&#xff09;补充&#xff…

力扣打卡12:复原IP地址

链接&#xff1a;93. 复原 IP 地址 - 力扣&#xff08;LeetCode&#xff09; 这道题需要对字符串进行操作&#xff0c;我选择了三层循环&#xff0c;其实还可以递归。 我在循环时进行了剪枝&#xff0c;比如一些情况直接跳出循环。 我的代码&#xff1a; class Solution { p…

说下JVM中一次完整的GC流程?

大家好&#xff0c;我是锋哥。今天分享关于【说下JVM中一次完整的GC流程&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说下JVM中一次完整的GC流程&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在JVM中&#xff0c;垃圾回收&#xff08;GC&am…

vs配置c++标准

在 vcxproj 文件中添加 <LanguageStandard>stdcpp17</LanguageStandard> 和在 Visual Studio 属性页面中设置 “C语言标准” 为 “ISO C17 标准 (/std:c17)” 是完全等价的。 它们的对应关系是&#xff1a; VS属性页面中的设置&#xff1a; 项目 -> 属性 ->…

TcpServer 服务器优化之后,加了多线程,对心跳包进行优化

TcpServer 服务器优化之后&#xff0c;加了多线程&#xff0c;对心跳包进行优化 TcpServer.h #ifndef TCPSERVER_H #define TCPSERVER_H#include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <vector> #include <map> #…

风控大讲堂|游戏黑产情报挖掘与治理

您的产品有没有遇到过被薅羊毛了&#xff1f;网络游戏行业的繁荣&#xff0c;催生了一批围绕游戏而生的职业玩家&#xff0c;他们利用多开、修改器等手段&#xff0c;疯狂薅游戏资源&#xff0c;破坏游戏经济平衡&#xff0c;给游戏公司带来了难以估量的巨大损失。那么针对此类…

最近邻搜索 - 经典树型结构 M-Tree

前言 如果你对这篇文章感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 最近邻搜索的目标是从 N N N 个对象中&#xff0c;快速找到距离查询点最近的对象。根据需求的不同&#xff0c;该任务又分…

Jmeter进阶篇(30)深入探索 JMeter 监听器

前言 在性能测试领域里,Apache JMeter 是一款经典而强大的工具,而其中的监听器(Listeners)组件更是发挥着不可或缺的关键作用。 监听器就像敏锐的观察者,默默记录测试执行过程中的各种数据,作为系统性能分析的数据依据。 本文将带你全方位走进 JMeter 监听器的奇妙世界,…

uni-app 个人课程表页面

uni-app 个人课程表页面 插件参考地址 大部分代码都是参考了上述代码&#xff0c;只对代码做出了优化 1. 页面模板 在 schedule.vue 文件中&#xff0c;编写页面结构&#xff1a; <template><view><u-navbar title"个人中心"><view class&q…

ElementEye,网页分析器

介绍 我们经常使用Python写爬虫&#xff0c;爬到网页数据之后&#xff0c;就需要用beautifulSoup进行解析。因为写爬虫并不是我的主营工作&#xff0c;大多数只是用来分析一下想要的数据而已&#xff0c;所以经常会忘记beautifulSoup的用法。 同时&#xff0c;我们总是分析页面…

【Compose multiplatform教程】01 创建你的多平台项目 <官网搬运>

这是 “创建带有共享逻辑和用户界面的 Compose 多平台应用” 教程的第一部分。 第一步&#xff1a;创建你的多平台项目 第二步&#xff1a;探究可组合代码 第三步&#xff1a;修改项目 第四步&#xff1a;创建你自己的应用程序 在这里&#xff0c;你将学习如何使用 Kotlin 多平…

使用OpenTK展示3D点云图像(C#)

最近在研究3D显示&#xff0c;找到一款在winform上展示3D点云的控件&#xff0c;并且实现了点线面的展示&#xff0c;及光照渲染纹理贴图等功能&#xff0c;如下面几张图所展示。 一些基础知识可以在LearnOpenTK - OpenTK 这个网站上学习到。 我这边使用的是openTK3.3.3版本&a…

李宏毅机器学习-批次 (batch)和动量(momentum)

一.batch&#xff08;批次&#xff09; 在计算微分时&#xff0c;不是对所有的数据算出来的Loss值做微分&#xff0c;而是将所有的数据分成一个一个的batch。一个batch是一个B&#xff0c;在更新参数时&#xff0c;拿B的资料计算Loss&#xff0c;计算gradient&#xff0c;再更新…

洗鞋小程序(源码+文档+部署+讲解)

本文将深入解析“洗鞋小程序”的项目&#xff0c;探究其架构、功能以及技术栈&#xff0c;并分享获取完整源码的途径。 系统概述 为洗鞋提供服务&#xff0c;包含小程序和管理端。 本项目名称为洗鞋小程序&#xff0c;是一个基于小程序的在线洗鞋平台。该系统提供下单、订单管…

【数据结构】二叉树的性质和存储结构

性质 在二叉树的第i层上至多有2^{i-1}个结点,至少有1个结点 深度为k的二叉树至多有2^{k-1}个结点&#xff08;k≥1&#xff09;&#xff0c;至少有k个结点 对任何一棵二叉树T&#xff0c;如果其叶子数为n0&#xff0c;度为2的结点数为n2&#xff0c;则n0n21 具有n个结点的完…

交换排序(Swap Sort)详解

交换排序Swap Sort详解 冒泡排序冒泡算法代码实现冒泡分析 快速排序快排算法代码实现快排分析 交换类排序主要是通过两两比较待排元素的关键字&#xff0c;若发现与排序要求相逆&#xff0c;则交换之。在这类排序方法中最常见的是起泡排序&#xff08;冒泡排序&#xff09;和快…

MySQL追梦旅途之性能优化

1、索引优化 索引可以显著加速查询操作&#xff0c;但过多或不适当的索引也会带来负面影响&#xff08;如增加写入开销&#xff09;。因此&#xff0c;选择合适的索引至关重要。 创建索引&#xff1a; 为经常用于WHERE子句、JOIN条件和ORDER BY排序的列创建索引。 CREATE I…

小程序IOS安全区域优化:safe-area-inset-bottom

ios下边有一个小黑线&#xff0c;位于底部的元素会被黑线阻挡 safe-area-inset-bottom 一 用法及作用&#xff1a; IOS全面屏底部有小黑线&#xff0c;位于底部的元素会被黑线阻挡&#xff0c;可以使用以下样式&#xff1a; .model{padding-bottom: constant(safe-area-ins…

矩阵的乘(包括乘方)和除

矩阵的乘分为两种&#xff1a; 一种是高等代数中对矩阵的乘的定义&#xff1a;可以去这里看看包含矩阵的乘。总的来说&#xff0c;若矩阵 A s ∗ n A_{s*n} As∗n​列数和矩阵 B n ∗ t B_{n*t} Bn∗t​的行数相等&#xff0c;则 A A A和 B B B可相乘&#xff0c;得到一个矩阵 …

解决阿里云轻量级服务器 Ubuntu 24.04.1 LTS 没网也 ping 不通 8.8.8.8 以及 route -n 没有输出任何转发信息

事情发生在两天前&#xff0c;位于公网的阿里云轻量级服务器&#xff08;Ubuntu 24.04.1 LTS&#xff09;忽然没网。主要是上次上服务器进行配置已经是一个多月前&#xff0c;最近也没有做什么事情&#xff0c;就忽然没网了&#xff0c;让人纳闷。更主要的是&#xff0c;上次备…