🤓 会话技术(三)

简介: 🤓 会话技术

3.3 Session的使用细节


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


3.3.1 Session钝化与活化


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


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


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


网络异常,图片无法展示
|


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


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


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


举个例子说明下,


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


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


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


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


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


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


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


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


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


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


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


网络异常,图片无法展示
|


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


网络异常,图片无法展示
|


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


(1)先启动Tomcat服务器


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


(3)正确停止Tomcat服务器


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


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


网络异常,图片无法展示
|


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


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


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


  • 钝化:在服务器正常关闭后,Tomcat会自动将Session数据写入硬盘的文件中
  • 钝化的数据路径为:项目目录\target\tomcat\work\Tomcat\localhost\项目名称\SESSIONS.ser
    网络异常,图片无法展示
    |
  • 活化:再次启动服务器后,从文件中加载数据到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配置文件中写死的



网络异常,图片无法展示
|


  • 调用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中获取数据
    网络异常,图片无法展示
    |
  • 该销毁方法一般会在用户退出的时候,需要将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 需求分析


需求说明:


  1. 完成用户登录功能,如果用户勾选“记住用户” ,则下次访问登录页面自动填充用户名密码
  2. 完成注册功能,并实现验证码功能


网络异常,图片无法展示
|


4.2 用户登录功能


  1. 需求:


网络异常,图片无法展示
|


  • 用户登录成功后,跳转到列表页面,并在页面上展示当前登录的用户名称
  • 用户登录失败后,跳转回登录页面,并在页面上展示对应的错误信息


  1. 实现流程分析


网络异常,图片无法展示
|


(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. 具体实现


(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目录下:


网络异常,图片无法展示
|


(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中标签下添加欢迎当前用户的提示信息:


${user.username},欢迎您


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

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

(4)启动,访问测试


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


网络异常,图片无法展示
|


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


网络异常,图片无法展示
|


小结


  • 在LoginServlet中,将登录成功的用户数据存入session中,方法在列表页面中获取当前登录用户信息进行展示
  • 在LoginServlet中,将登录失败的错误信息存入到request中,如果存入到session中就会出现这次会话的所有请求都有登录失败的错误信息,这个是不需要的,所以不用存入到session中


4.3 记住我-设置Cookie


  1. 需求:


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


网络异常,图片无法展示
|


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


  1. 实现流程分析


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


  • 将用户名和密码写入Cookie中,并且持久化存储Cookie,下次访问浏览器会自动携带Cookie
  • 在页面获取Cookie数据后,设置到用户名和密码框中
  • 何时写入Cookie?
  • 用户必须登陆成功后才需要写
  • 用户必须在登录页面勾选了记住我的复选框


网络异常,图片无法展示
|


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


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


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


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


  1. 具体实现


(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>



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

@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);
    }
}

(3)启动访问测试,


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


网络异常,图片无法展示
|


目录
相关文章
|
7月前
|
存储 缓存 前端开发
从此告别网速慢,轻松掌握浏览器缓存知识点!(一)
从此告别网速慢,轻松掌握浏览器缓存知识点!
|
7月前
|
存储 缓存 前端开发
从此告别网速慢,轻松掌握浏览器缓存知识点!(二)
从此告别网速慢,轻松掌握浏览器缓存知识点!
|
7月前
|
存储 搜索推荐 UED
通俗科普:Cookie和Session是什么?
通俗科普:Cookie和Session是什么?
64 0
|
算法 安全 Java
快速了解常用的消息摘要算法,再也不用担心面试官的刨根问底
加密算法通常被分为两种:对称加密和非对称加密。其中,对称加密算法在加密和解密时使用的密钥相同;非对称加密算法在加密和解密时使用的密钥不同,分为公钥和私钥。此外,还有一类叫做消息摘要算法,是对数据进行摘要并且不可逆的算法。 这次我们了解一下消息摘要算法。
649 0
快速了解常用的消息摘要算法,再也不用担心面试官的刨根问底
|
SQL 安全 数据库
记一次稍微有点曲折的getshell
记一次稍微有点曲折的getshell
|
存储 前端开发 安全
🤓 会话技术(四)
🤓 会话技术
86 0
|
存储 Web App开发 前端开发
🤓 会话技术(一)
🤓 会话技术
107 0
|
存储 Web App开发 编解码
🤓 会话技术(二)
🤓 会话技术
80 0
原来后台是这样分辨浏览器请求的 浏览器发送请求给服务器 服务器通过反射辨别Servlet类 通过methodName分辨方法 妈妈再也不用担心我的学习了
原来后台是这样分辨浏览器请求的 浏览器发送请求给服务器 服务器通过反射辨别Servlet类 通过methodName分辨方法 妈妈再也不用担心我的学习了
210 0
|
存储 编解码 Java
javaWeb(十二)----- 会话技术:Cookie
javaWeb(十二)----- 会话技术:Cookie
javaWeb(十二)----- 会话技术:Cookie