《JavaWeb篇》10.Session&Cookie看这一篇就够了(二)

简介: 《JavaWeb篇》10.Session&Cookie看这一篇就够了(二)

(1)demo1在第一次获取session对象的时候,session对象会有一个唯一的标识,假如是id:10


(2)demo1在session中存入其他数据并处理完成所有业务后,需要通过Tomcat服务器响应结果给浏览器


(3)Tomcat服务器发现业务处理中使用了session对象,就会把session的唯一标识id:10当做一个cookie,添加Set-Cookie:JESSIONID=10到响应头中,并响应给浏览器


(4)浏览器接收到响应结果后,会把响应头中的coookie数据存储到浏览器的内存中


(5)浏览器在同一会话中访问demo2的时候,会把cookie中的数据按照cookie: JESSIONID=10的格式添加到请求头中并发送给服务器Tomcat


(6)demo2获取到请求后,从请求头中就读取cookie中的JSESSIONID值为10,然后就会到服务器内存中寻找id:10的session对象,如果找到了,就直接返回该对象,如果没有则新创建一个session对象


(7)关闭打开浏览器后,因为浏览器的cookie已被销毁,所以就没有JESSIONID的数据,服务端获取到的session就是一个全新的session对象


至此,Session是基于Cookie来实现的这就话,我们就解释完了,接下来通过实例来演示下:


(1)使用chrome浏览器访问http://localhost:8080/cookie-demo/demo1,打开开发者模式(F12或Ctrl+Shift+I),查看==响应头(Response Headers)==数据:


image.png


(2)使用chrome浏览器再次访问http://localhost:8080/cookie-demo/demo2,查看请求头(Request Headers)数据:


image.png


小结


介绍完Session的原理,我们只需要记住


Session是基于Cookie来实现的

3.3 Session的使用细节

这节我们会主要讲解两个知识,第一个是Session的钝化和活化,第二个是Session的销毁,首先来学习什么是Session的钝化和活化?


3.3.1 Session钝化与活化

首先需要大家思考的问题是:


服务器重启后,Session中的数据是否还在?

要想回答这个问题,我们可以先看下下面这幅图,


image.png


(1)服务器端AServlet和BServlet共用的session对象应该是存储在服务器的内存中


(2)服务器重新启动后,内存中的数据应该是已经被释放,对象也应该都销毁了


所以session数据应该也已经不存在了。但是如果session不存在会引发什么问题呢?


举个例子说明下,


(1)用户把需要购买的商品添加到购物车,因为要实现同一个会话多次请求数据共享,所以假设把数据存入Session对象中


(2)用户正要付钱的时候接到一个电话,付钱的动作就搁浅了


(3)正在用户打电话的时候,购物网站因为某些原因需要重启


(4)重启后session数据被销毁,购物车中的商品信息也就会随之而消失


(5)用户想再次发起支付,就会出为问题


所以说对于session的数据,我们应该做到就算服务器重启了,也应该能把数据保存下来才对。


分析了这么多,那么Tomcat服务器在重启的时候,session数据到底会不会保存以及是如何保存的,我们可以通过实际案例来演示下:


注意:这里所说的关闭和启动应该要确保是正常的关闭和启动。


那如何才是正常关闭Tomcat服务器呢?


需要使用命令行的方式来启动和停止Tomcat服务器:


启动:进入到项目pom.xml所在目录,执行tomcat7:run


image.png


停止:在启动的命令行界面,输入ctrl+c


image.png


有了上述两个正常启动和关闭的方式后,接下来的测试流程是:


(1)先启动Tomcat服务器


(2)访问http://localhost:8080/cookie-demo/demo1将数据存入session中


(3)正确停止Tomcat服务器


(4)再次重新启动Tomcat服务器


(5)访问http://localhost:8080/cookie-demo/demo2 查看是否能获取到session中的数据


image.png


经过测试,会发现只要服务器是正常关闭和启动,session中的数据是可以被保存下来的。


那么Tomcat服务器到底是如何做到的呢?


具体的原因就是:Session的钝化和活化:


钝化:在服务器正常关闭后,Tomcat会自动将Session数据写入硬盘的文件中


钝化的数据路径为:项目目录\target\tomcat\work\Tomcat\localhost\项目名称\SESSIONS.ser


image.png

活化:再次启动服务器后,从文件中加载数据到Session中


数据加载到Session中后,路径中的SESSIONS.ser文件会被删除掉

对于上述的整个过程,大家只需要了解下即可。因为所有的过程都是Tomcat自己完成的,不需要我们参与。


小结


Session的钝化和活化介绍完后,需要我们注意的是:


session数据存储在服务端,服务器重启后,session数据会被保存


浏览器被关闭启动后,重新建立的连接就已经是一个全新的会话,获取的session数据也是一个新的对象


session的数据要想共享,浏览器不能关闭,所以session数据不能长期保存数据


cookie是存储在客户端,是可以长期保存


3.3.2 Session销毁

session的销毁会有两种方式:


默认情况下,无操作,30分钟自动销毁


对于这个失效时间,是可以通过配置进行修改的


在项目的web.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_3_1.xsd"
         version="3.1">
    <session-config>
        <session-timeout>100</session-timeout>
    </session-config>
</web-app>

如果没有配置,默认是30分钟,默认值是在Tomcat的web.xml配置文件中写死的


image.png


调用Session对象的invalidate()进行销毁


在SessionDemo2类中添加session销毁的方法

@WebServlet("/demo2")
public class SessionDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取数据,从session中
        //1. 获取Session对象
        HttpSession session = request.getSession();
        System.out.println(session);
        // 销毁
        session.invalidate();
        //2. 获取数据
        Object username = session.getAttribute("username");
        System.out.println(username);
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}


启动访问测试,先访问demo1将数据存入到session,再次访问demo2从session中获取数据


image.png


该销毁方法一般会在用户退出的时候,需要将session销毁掉。


Cookie和Session小结


Cookie 和 Session 都是来完成一次会话内多次请求间数据共享的。

所需两个对象放在一块,就需要思考:


Cookie和Session的区别是什么?


Cookie和Session的应用场景分别是什么?


区别:

存储位置:Cookie 是将数据存储在客户端,Session 将数据存储在服务端

安全性:Cookie不安全,Session安全

数据大小:Cookie最大3KB,Session无大小限制

存储时间:Cookie可以通过setMaxAge()长期存储,Session默认30分钟

服务器性能:Cookie不占服务器资源,Session占用服务器资源

应用场景:

购物车:使用Cookie来存储

以登录用户的名称展示:使用Session来存储

记住我功能:使用Cookie来存储

验证码:使用session来存储

结论

Cookie是用来保证用户在未登录情况下的身份识别

Session是用来保存用户登录后的数据

介绍完Cookie和Session以后,具体用哪个还是需要根据具体的业务进行具体分析。


4,用户登录注册案例


4.1 需求分析

需求说明:


完成用户登录功能,如果用户勾选“记住用户” ,则下次访问登录页面自动填充用户名密码


完成注册功能,并实现验证码功能


image.png


4.2 用户登录功能

需求:


image.png

用户登录成功后,跳转到列表页面,并在页面上展示当前登录的用户名称

用户登录失败后,跳转回登录页面,并在页面上展示对应的错误信息

实现流程分析


image.png

(1)前端通过表单发送请求和数据给Web层的LoginServlet


(2)在LoginServlet中接收请求和数据[用户名和密码]


(3)LoginServlet接收到请求和数据后,调用Service层完成根据用户名和密码查询用户对象


(4)在Service层需要编写UserService类,在类中实现login方法,方法中调用Dao层的UserMapper


(5)在UserMapper接口中,声明一个根据用户名和密码查询用户信息的方法


(6)Dao层把数据查询出来以后,将返回数据封装到User对象,将对象交给Service层


(7)Service层将数据返回给Web层


(8)Web层获取到User对象后,判断User对象,如果为Null,则将错误信息响应给登录页面,如果不为Null,则跳转到列表页面,并把当前登录用户的信息存入Session携带到列表页面。


具体实现

(1)完成Dao层的代码编写


(1.1)将04-资料\1. 登录注册案例\2. MyBatis环境\UserMapper.java放到com.itheima.mapper`包下:


public interface UserMapper {
    /**
     * 根据用户名和密码查询用户对象
     * @param username
     * @param password
     * @return
     */
    @Select("select * from tb_user where username = #{username} and password = #{password}")
    User select(@Param("username") String username,@Param("password")  String password);
    /**
     * 根据用户名查询用户对象
     * @param username
     * @return
     */
    @Select("select * from tb_user where username = #{username}")
    User selectByUsername(String username);
    /**
     * 添加用户
     * @param user
     */
    @Insert("insert into tb_user values(null,#{username},#{password})")
    void add(User user);
}

(1.2)将04-资料\1. 登录注册案例\2. MyBatis环境\User.java放到com.itheima.pojo包下:


public class User {
    private Integer id;
    private String username;
    private String password;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    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;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}


(1.3)将04-资料\1. 登录注册案例\2. MyBatis环境\UserMapper.xml放入到resources/com/itheima/mapper`目录下:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.UserMapper">
</mapper>

(2)完成Service层的代码编写


(2.1)在com.itheima.service包下,创建UserService类


public class UserService {
    //1.使用工具类获取SqlSessionFactory
    SqlSessionFactory factory = SqlSessionFactoryUtils.getSqlSessionFactory();
    /**
     * 登录方法
     * @param username
     * @param password
     * @return
     */
    public User login(String username,String password){
        //2. 获取SqlSession
        SqlSession sqlSession = factory.openSession();
        //3. 获取UserMapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //4. 调用方法
        User user = mapper.select(username, password);
        //释放资源
        sqlSession.close();
        return  user;
    }
}


(3)完成页面和Web层的代码编写


(3.1)将04-资料\1. 登录注册案例\1. 静态页面拷贝到项目的webapp目录下:


image.png


(3.2)将login.html内容修改成login.jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
    <link href="css/login.css" rel="stylesheet">
</head>
<body>
<div id="loginDiv" style="height: 350px">
    <form action="/brand-demo/loginServlet" method="post" id="form">
        <h1 id="loginMsg">LOGIN IN</h1>
        <div id="errorMsg">用户名或密码不正确</div>
        <p>Username:<input id="username" name="username" type="text"></p>
        <p>Password:<input id="password" name="password" type="password"></p>
        <p>Remember:<input id="remember" name="remember" type="checkbox"></p>
        <div id="subDiv">
            <input type="submit" class="button" value="login up">
            <input type="reset" class="button" value="reset">&nbsp;&nbsp;&nbsp;
            <a href="register.html">没有账号?</a>
        </div>
    </form>
</div>
</body>
</html>

(3.3)创建LoginServlet类


@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    private UserService service = new UserService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 获取用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //2. 调用service查询
        User user = service.login(username, password);
        //3. 判断
        if(user != null){
            //登录成功,跳转到查询所有的BrandServlet
            //将登陆成功后的user对象,存储到session
            HttpSession session = request.getSession();
            session.setAttribute("user",user);
            String contextPath = request.getContextPath();
            response.sendRedirect(contextPath+"/selectAllServlet");
        }else {
            // 登录失败,
            // 存储错误信息到request
            request.setAttribute("login_msg","用户名或密码错误");
            // 跳转到login.jsp
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}


(3.4)在brand.jsp中标签下添加欢迎当前用户的提示信息:


<h1>${user.username},欢迎您</h1>

(3.5) 修改login.jsp,将错误信息使用EL表达式来获取


修改前内容:<div id="errorMsg">用户名或密码不正确</div>
修改后内容: <div id="errorMsg">${login_msg}</div>

(4)启动,访问测试


(4.1) 进入登录页面,输入错误的用户名或密码


image.png


(4.2)输入正确的用户和密码信息


image.png


小结


在LoginServlet中,将登录成功的用户数据存入session中,方法在列表页面中获取当前登录用户信息进行展示

在LoginServlet中,将登录失败的错误信息存入到request中,如果存入到session中就会出现这次会话的所有请求都有登录失败的错误信息,这个是不需要的,所以不用存入到session中

4.3 记住我-设置Cookie

需求:

如果用户勾选“记住用户” ,则下次访问登陆页面自动填充用户名密码。这样可以提升用户的体验。


image.png


对应上面这个需求,最大的问题就是: 如何自动填充用户名和密码?


实现流程分析

因为记住我功能要实现的效果是,就算用户把浏览器关闭过几天再来访问也能自动填充,所以需要将登陆信息存入一个可以长久保存,并且能够在浏览器关闭重新启动后依然有效的地方,就是我们前面讲的Cookie,所以:


将用户名和密码写入Cookie中,并且持久化存储Cookie,下次访问浏览器会自动携带Cookie


在页面获取Cookie数据后,设置到用户名和密码框中


何时写入Cookie?


用户必须登陆成功后才需要写

用户必须在登录页面勾选了记住我的复选框

image.png


(1)前端需要在发送请求和数据的时候,多携带一个用户是否勾选Remember的数据


(2)LoginServlet获取到数据后,调用Service完成用户名和密码的判定


(3)登录成功,并且用户在前端勾选了记住我,需要往Cookie中写入用户名和密码的数据,并设置Cookie存活时间


(4)设置成功后,将数据响应给前端


具体实现

(1)在login.jsp为复选框设置值


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
    <link href="css/login.css" rel="stylesheet">
</head>
<body>
<div id="loginDiv" style="height: 350px">
    <form action="/brand-demo/loginServlet" method="post" id="form">
        <h1 id="loginMsg">LOGIN IN</h1>
        <div id="errorMsg">${login_msg}</div>
        <p>Username:<input id="username" name="username" type="text"></p>
        <p>Password:<input id="password" name="password" type="password"></p>
        <p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p>
        <div id="subDiv">
            <input type="submit" class="button" value="login up">
            <input type="reset" class="button" value="reset">&nbsp;&nbsp;&nbsp;
            <a href="register.html">没有账号?</a>
        </div>
    </form>
</div>
</body>
</html>
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    private UserService service = new UserService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 获取用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //获取复选框数据
        String remember = request.getParameter("remember");
        //2. 调用service查询
        User user = service.login(username, password);
        //3. 判断
        if(user != null){
            //登录成功,跳转到查询所有的BrandServlet
            //判断用户是否勾选记住我,字符串写前面是为了避免出现空指针异常
            if("1".equals(remember)){
                //勾选了,发送Cookie
                //1. 创建Cookie对象
                Cookie c_username = new Cookie("username",username);
                Cookie c_password = new Cookie("password",password);
                // 设置Cookie的存活时间
                c_username.setMaxAge( 60 * 60 * 24 * 7);
                c_password.setMaxAge( 60 * 60 * 24 * 7);
                //2. 发送
                response.addCookie(c_username);
                response.addCookie(c_password);
            }
            //将登陆成功后的user对象,存储到session
            HttpSession session = request.getSession();
            session.setAttribute("user",user);
            String contextPath = request.getContextPath();
            response.sendRedirect(contextPath+"/selectAllServlet");
        }else {
            // 登录失败,
            // 存储错误信息到request
            request.setAttribute("login_msg","用户名或密码错误");
            // 跳转到login.jsp
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

(2)在LoginServlet获取复选框的值并在登录成功后进行设置Cookie



(3)启动访问测试,


只有当前用户名和密码输入正确,并且勾选了Remeber的复选框,在响应头中才可以看得cookie的相关数据


image.png


4.4 记住我-获取Cookie

需求

登录成功并勾选了Remeber后,后端返回给前端的Cookie数据就已经存储好了,接下来就需要在页面获取Cookie中的数据,并把数据设置到登录页面的用户名和密码框中。


image.png


如何在页面直接获取Cookie中的值呢?


实现流程分析

在页面可以使用EL表达式,${cookie.key.value}


key:指的是存储在cookie中的键名称


image.png


(1)在login.jsp用户名的表单输入框使用value值给表单元素添加默认值,value可以使用${cookie.username.value}


(2)在login.jsp密码的表单输入框使用value值给表单元素添加默认值,value可以使用${cookie.password.value}


具体实现

(1)修改login.jsp页面


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
    <link href="css/login.css" rel="stylesheet">
</head>
<body>
<div id="loginDiv" style="height: 350px">
    <form action="/brand-demo/loginServlet" method="post" id="form">
        <h1 id="loginMsg">LOGIN IN</h1>
        <div id="errorMsg">${login_msg}</div>
        <p>Username:<input id="username" name="username" value="${cookie.username.value}" type="text"></p>
        <p>Password:<input id="password" name="password" value="${cookie.password.value}" type="password"></p>
        <p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p>
        <div id="subDiv">
            <input type="submit" class="button" value="login up">
            <input type="reset" class="button" value="reset">&nbsp;&nbsp;&nbsp;
            <a href="register.html">没有账号?</a>
        </div>
    </form>
</div>
</body>
</html>

访问测试,重新访问登录页面,就可以看得用户和密码已经被填充。


image.png


相关文章
|
24天前
|
存储 安全 搜索推荐
理解Session和Cookie:Java Web开发中的用户状态管理
理解Session和Cookie:Java Web开发中的用户状态管理
47 4
|
27天前
|
存储 缓存 网络协议
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点,GET、POST的区别,Cookie与Session
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点、状态码、报文格式,GET、POST的区别,DNS的解析过程、数字证书、Cookie与Session,对称加密和非对称加密
|
2月前
|
缓存 Java Spring
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
文章比较了在Servlet和Spring Boot中获取Cookie、Session和Header的方法,并提供了相应的代码实例,展示了两种方式在实际应用中的异同。
170 3
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
|
2月前
|
存储 安全 数据安全/隐私保护
Cookie 和 Session 的区别及使用 Session 进行身份验证的方法
【10月更文挑战第12天】总之,Cookie 和 Session 各有特点,在不同的场景中发挥着不同的作用。使用 Session 进行身份验证是常见的做法,通过合理的设计和管理,可以确保用户身份的安全和可靠验证。
24 1
|
3月前
|
存储 缓存 数据处理
php学习笔记-php会话控制,cookie,session的使用,cookie自动登录和session 图书上传信息添加和修改例子-day07
本文介绍了PHP会话控制及Web常用的预定义变量,包括`$_REQUEST`、`$_SERVER`、`$_COOKIE`和`$_SESSION`的用法和示例。涵盖了cookie的创建、使用、删除以及session的工作原理和使用,并通过图书上传的例子演示了session在实际应用中的使用。
php学习笔记-php会话控制,cookie,session的使用,cookie自动登录和session 图书上传信息添加和修改例子-day07
|
3月前
|
存储 前端开发 Java
JavaWeb基础7——会话技术Cookie&Session
会话技术、Cookie的发送和获取、存活时间、Session钝化与活化、销毁、用户登录注册“记住我”和“验证码”案例
JavaWeb基础7——会话技术Cookie&Session
|
3月前
|
存储 安全 NoSQL
Cookie、Session、Token 解析
Cookie、Session、Token 解析
63 0
|
4月前
|
存储 JavaScript 前端开发
Cookie 反制策略详解:Cookie加解密原理、Cookie和Session机制、Cookie hook、acw_sc__v2、jsl Cookie调试、重定向Cookie
Cookie 反制策略详解:Cookie加解密原理、Cookie和Session机制、Cookie hook、acw_sc__v2、jsl Cookie调试、重定向Cookie
221 1
|
4月前
|
存储 安全 搜索推荐
【JavaWeb 秘籍】Cookie vs Session:揭秘 Web 会话管理的奥秘与实战指南!
【8月更文挑战第24天】本文以问答形式深入探讨了Web开发中关键的会话管理技术——Cookie与Session。首先解释了两者的基本概念及工作原理,随后对比分析了它们在存储位置、安全性及容量上的差异。接着,通过示例代码详细介绍了如何在JavaWeb环境中实现Cookie与Session的操作,包括创建与读取过程。最后,针对不同应用场景提供了选择使用Cookie或Session的指导建议,并提出了保障二者安全性的措施。阅读本文可帮助开发者更好地理解并应用这两种技术。
64 1
|
4月前
|
存储 安全 搜索推荐
深入探讨Session和Cookie的概念、用途以及如何在Java Web开发中有效地使用它们进行用户状态管理。
在Java Web开发中,Session和Cookie是管理用户状态的核心技术。Session存储于服务器端,通过唯一的Session ID识别用户,确保数据安全与隐私;Cookie则存储于客户端,用于记录用户偏好等信息。两者各有优势:Session适合存储敏感数据,但需合理管理避免资源浪费;Cookie便于持久化存储,但在安全性上需谨慎设置。开发者可通过Servlet API轻松操作二者,实现个性化用户体验与应用性能优化。
65 2