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

目录

一、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"代码如下。
java 复制代码
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>标签在线引入。
html 复制代码
<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()。代码如下。
javascript 复制代码
<script type="text/javascript">
        //js定义函数
        function refreshCode(){
            //不做下面处理,就会走浏览器缓存, url没有变化, 导致使用上一次缓存内容,不会刷新验证码
            //选择器 #id名------>获取到img标签
            //使用attr()设置属性"src"值。
            //加一个时间戳, 每次都不一样, 浏览器发现参数不一样, 误以为是新请求,不走缓存,就会刷新
            $("#vcode").attr("src","/checkCode?"+new Date().getTime());
        }
    </script>
(2)生成验证码的Servlet类。
java 复制代码
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技术)
java 复制代码
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);
        }

    }
}
相关推荐
小仙有礼了10 分钟前
Arcgis for javascript 开发学习经验
javascript·学习·arcgis
JWASX18 分钟前
【BUG记录】Apifox 参数传入 + 号变成空格的 BUG
java·bug·urlencoder·urldecoder
澄澈i23 分钟前
设计模式学习[13]---抽象工厂模式+简单工厂+工厂方法模式回顾
学习·设计模式·抽象工厂模式
gen_40 分钟前
本地maven项目打包部署到maven远程私库
java·maven
loop lee43 分钟前
计算机网络 - HTTP 协议和万维网
java·网络协议·servlet·tomcat
daiyang123...1 小时前
JavaEE 【知识改变命运】06 多线程进阶(1)
java·java-ee
当归10241 小时前
代码生成器
java
LI JS@你猜啊1 小时前
MySQL 集群
java·数据库·mysql
--地平线--1 小时前
如何将 Java 微服务引入云
java·开发语言·微服务
柔弱女子爱java1 小时前
spring专题笔记(五):依赖注入--p命名空间注入、c命名空间注入、util命名空间
java·笔记·后端·spring·架构·系统架构