Servlet第六篇【Session介绍、API、生命周期、应用、与Cookie区别】(修订版)

Servlet第六篇【Session介绍、API、生命周期、应用】 什么是Session Session 是另一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种的形式记录在服务器,这就是Session 如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器中 阅读详情

前言

只有光头才能变强。

文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y

什么是Session

Session 是另一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种的形式记录在服务器,这就是Session

如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器中建立了一份“客户明细表”。

为什么要使用Session技术?

Session比Cookie使用方便,Session可以解决Cookie解决不了的事情【Session可以存储对象,Cookie只能存储字符串。】。

Session API

  • long getCreationTime();【获取Session被创建时间】

  • String getId();【获取Session的id】

  • long getLastAccessedTime();【返回Session最后活跃的时间】

  • ServletContext getServletContext();【获取ServletContext对象】

  • void setMaxInactiveInterval(int var1);【设置Session超时时间】

  • int getMaxInactiveInterval();【获取Session超时时间】

  • Object getAttribute(String var1);【获取Session属性】

  • Enumeration getAttributeNames();【获取Session所有的属性名】

  • void setAttribute(String var1, Object var2);【设置Session属性】

  • void removeAttribute(String var1);【移除Session属性】

  • void invalidate();【销毁该Session】

  • boolean isNew();【该Session是否为新的】


Session作为域对象

从上面的API看出,Session有着request和ServletContext类似的方法。其实Session也是一个域对象。Session作为一种记录浏览器状态的机制,只要Session对象没有被销毁,Servlet之间就可以通过Session对象实现通讯

  • 我们来试试吧,在Servlet4中设置Session属性

        //得到Session对象	
        HttpSession httpSession = request.getSession();	
        //设置Session属性	
        httpSession.setAttribute("name", "看完博客就要点赞!!");
  • 在Servlet5中获取到Session存进去的属性

        //获取到从Servlet4的Session存进去的值	
        HttpSession httpSession = request.getSession();	
        String value = (String) httpSession.getAttribute("name");	
        System.out.println(value);
  • 访问Servlet4,再访问Servlet5

640?wx_fmt=png

  • 一般来讲,当我们要存进的是用户级别的数据就用Session,那什么是用户级别呢?只要浏览器不关闭,希望数据还在,就使用Session来保存。

Session的生命周期和有效期


  • Session在用户第一次访问服务器Servlet,jsp等动态资源就会被自动创建,Session对象保存在内存里,这也就为什么上面的例子可以直接使用request对象获取得到Session对象。



  • 如果访问HTML,IMAGE等静态资源Session不会被创建。



  • Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,无论是否对Session进行读写,服务器都会认为Session活跃了一次。



  • 由于会有越来越多的用户访问服务器,因此Session也会越来越多。为了防止内存溢出,服务器会把长时间没有活跃的Session从内存中删除,这个时间也就是Session的超时时间。



  • Session的超时时间默认是30分钟,有三种方式可以对Session的超时时间进行修改



  • 第一种方式:在tomcat/conf/web.xml文件中设置,时间值为20分钟,所有的WEB应用都有效


            <session-config>	
                <session-timeout>20</session-timeout>	
            </session-config>   

640?wx_fmt=png

  • 第二种方式:在单个的web.xml文件中设置,对单个web应用有效,如果有冲突,以自己的web应用为准。

            <session-config>	
                <session-timeout>20</session-timeout>	
            </session-config>   
  • 第三种方式:通过setMaxInactiveInterval()方法设置

        //设置Session最长超时时间为60秒,这里的单位是秒	
        httpSession.setMaxInactiveInterval(60);	
        System.out.println(httpSession.getMaxInactiveInterval());

640?wx_fmt=png

  • Session的有效期与Cookie的是不同的

640?wx_fmt=png


使用Session完成简单的购物功能

  • 我们还是以书籍为例,所以可以copy“显示浏览过的商品“例子部分的代码。

        response.setContentType("text/html;charset=UTF-8");	
        PrintWriter printWriter = response.getWriter();	
        printWriter.write("网页上所有的书籍:" + "<br/>");	
        //拿到数据库所有的书	
        LinkedHashMap<String, Book> linkedHashMap = DB.getAll();	
        Set<Map.Entry<String, Book>> entry = linkedHashMap.entrySet();	
        //显示所有的书到网页上	
        for (Map.Entry<String, Book> stringBookEntry : entry) {	
            Book book = stringBookEntry.getValue();	
            String url = "/ouzicheng/Servlet6?id=" + book.getId();	
            printWriter.write(book.getName());	
            printWriter.write("<a href='" + url + "'>购买</a>");	
            printWriter.write("<br/>");	
        }
  • 在购物车页面上,获取到用户想买的书籍【用户可能不单想买一本书,于是乎,就用一个List容器装载书籍】,有了:先遍历Cookie,再判断是否是第一次访问Servlet的逻辑思路,我们就可以先获取到Session的属性,如果Session的属性为null,那么就是还没有该属性

        //得到用户想买书籍的id	
        String id = request.getParameter("id");	
        //根据书籍的id找到用户想买的书	
        Book book = (Book) DB.getAll().get(id);	
        //获取到Session对象	
        HttpSession httpSession = request.getSession();	
        //由于用户可能想买多本书的,所以我们用一个容器装着书籍	
        List list = (List) httpSession.getAttribute("list");	
        if (list == null) {	
            list = new ArrayList();	
            //设置Session属性	
            httpSession.setAttribute("list",list);	
        }	
        //把书籍加入到list集合中	
        list.add(book);
  • 按我们正常的逻辑思路:先创建一个ArrayList对象,把书加到list集合中,然后设置Session的属性。这样是行不通的。每次Servlet被访问的时候都会创建一个ArrayList集合,书籍会被分发到不同的ArrayList中去。所以下面的代码是不行的!

        //得到用户想买书籍的id	
        String id = request.getParameter("id");	
        //根据书籍的id找到用户想买的书	
        Book book = (Book) DB.getAll().get(id);	
        //获取到Session对象	
        HttpSession httpSession = request.getSession();	
        //创建List集合	
        List list = new ArrayList();	
        list.add(book);	
        httpSession.setAttribute("list", list);
  • 既然用户已经购买了书籍,那么也应该给提供页面显示用户购买过哪些书籍

        //得到用户想买书籍的id	
        String id = request.getParameter("id");	
        //根据书籍的id找到用户想买的书	
        Book book = (Book) DB.getAll().get(id);	
        //获取到Session对象	
        HttpSession httpSession = request.getSession();	
        //由于用户可能想买多本书的,所以我们用一个容器装着书籍	
        List list = (List) httpSession.getAttribute("list");	
        if (list == null) {	
            list = new ArrayList();	
            //设置Session属性	
            httpSession.setAttribute("list",list);	
        }	
        //把书籍加入到list集合中	
        list.add(book);	
        String url = "/ouzicheng/Servlet7";	
        response.sendRedirect(url);
  • 列出用户购买过的书籍

        //要得到用户购买过哪些书籍,得到Session的属性遍历即可	
        HttpSession httpSession = request.getSession();	
        List<Book> list = (List) httpSession.getAttribute("list");	
        if (list == null || list.size() == 0) {	
            printWriter.write("对不起,你还没有买过任何商品");	
        } else {	
            printWriter.write("您购买过以下商品:");	
            printWriter.write("<br/>");	
            for (Book book : list) {	
                printWriter.write(book.getName());	
                printWriter.write("<br/>");	
            }	
        }
  • 效果如下

640?wx_fmt=png


Session的实现原理

  • 用现象说明问题,我在Servlet4中的代码设置了Session的属性

        //得到Session对象	
        HttpSession httpSession = request.getSession();	
        //设置Session属性	
        httpSession.setAttribute("name", "看完博客就要点赞!!");
  • 接着在Servlet7把Session的属性取出来

        String value = (String) request.getSession().getAttribute("name");	
        printWriter.write(value);
  • 自然地,我们能取到在Servlet4中Session设置的属性

640?wx_fmt=png

  • 接着,我在浏览器中新建一个会话,再次访问Servlet7

640?wx_fmt=png

  • 发现报了空指针异常的错误

640?wx_fmt=png


  • 现在问题来了:服务器是如何实现一个session为一个用户浏览器服务的?换个说法:为什么服务器能够为不同的用户浏览器提供不同session?



  • HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一个用户。于是乎:服务器向用户浏览器发送了一个名为JESSIONID的Cookie,它的值是Session的id值。其实Session依据Cookie来识别是否是同一个用户。



  • 简单来说:Session 之所以可以识别不同的用户,依靠的就是Cookie



  • 该Cookie是服务器自动颁发给浏览器的,不用我们手工创建的。该Cookie的maxAge值默认是-1,也就是说仅当前浏览器使用,不将该Cookie存在硬盘中



  • 我们来捋一捋思路流程:当我们访问Servlet4的时候,服务器就会创建一个Session对象,执行我们的程序代码,并自动颁发个Cookie给用户浏览器


640?wx_fmt=png

  • 当我们用同一个浏览器访问Servlet7的时候,浏览器会把Cookie的值通过http协议带过去给服务器,服务器就知道用哪一Session。

640?wx_fmt=png

  • 而当我们使用新会话的浏览器访问Servlet7的时候,该新浏览器并没有Cookie,服务器无法辨认使用哪一个Session,所以就获取不到值


浏览器禁用了Cookie,Session还能用吗?

上面说了Session是依靠Cookie来识别用户浏览器的。如果我的用户浏览器禁用了Cookie了呢?绝大多数的手机浏览器都不支持Cookie,那我的Session怎么办?

640?wx_fmt=png

  • 好的,我们来看看情况是怎么样的。用户浏览器访问Servlet4的时候,服务器向用户浏览器颁发了一个Cookie

640?wx_fmt=png

  • 但是呢,当用户浏览器访问Servlet7的时候,由于我们禁用了Cookie,所以用户浏览器并没有把Cookie带过去给服务器。

640?wx_fmt=png


  • 一看,Session好像不能用了。但是Java Web提供了解决方法:URL地址重写



  • HttpServletResponse类提供了两个URL地址重写的方法:


    • encodeURL(String url)

    • encodeRedirectURL(String url)


  • 需要值得注意的是:这两个方法会自动判断该浏览器是否支持Cookie,如果支持Cookie,重写后的URL地址就不会带有jsessionid了【当然了,即使浏览器支持Cookie,第一次输出URL地址的时候还是会出现jsessionid(因为没有任何Cookie可带)】



  • 下面我们就以上面“购物”的例子来做试验吧!首先我们来看看禁用掉Cookie对原来的小例子有什么影响。



  • 访问Servlet1,随便点击一本书籍购买


640?wx_fmt=png

  • 无论点击多少次,都会直接提示我们有买过任何商品

640?wx_fmt=png


  • 原因也非常简单,没有Cookie传递给服务器,服务器每次创建的时候都是新的Session,导致最后获取到的List集合一定是空的。



  • 不同Servlet获取到的Session的id号都是不同的。


640?wx_fmt=png


  • 下面我们就对URL进行重写,看看能不能恢复没有禁掉Cookie之前的效果。



  • 原则:把Session的属性带过去【传递给】另外一个Servlet,都要URL地址重写



  • 在跳转到显示购买过商品的Servlet的时候,URL地址重写。


  • 再次访问Servlet1,当我点击javaweb的时候,已经能够成功出现我买过的商品了。并且Session的id通过URL地址重写,使用的是同一个Session

640?wx_fmt=png

640?wx_fmt=png

  • URL地址重写的原理:将Session的id信息重写到URL地址中。服务器解析重写后URL,获取Session的id。这样一来,即使浏览器禁用掉了Cookie,但Session的id通过服务器端传递,还是可以使用Session来记录用户的状态。


Session禁用Cookie


  • Java Web规范支持通过配置禁用Cookie



  • 禁用自己项目的Cookie

    640?wx_fmt=png


    • 在META-INF文件夹下的context.xml文件中修改(没有则创建)

  1.        <?xml version='1.0' encoding='utf-8'?>

        &lt;Context path="/ouzicheng" cookies="false"&gt;	
        &lt;Context path="/ouzicheng" cookies="false"&gt;



  2.     &lt;/Context&gt;	
        &lt;/Context&gt;



禁用全部web应用的Cookie

640?wx_fmt=png


  • 在conf/context.xml中修改

注意:该配置只是让服务器不能自动维护名为jsessionid的Cookie,并不能阻止Cookie的读写。


Session案例

使用Session完成用户简单登陆

  • 先创建User类

    private String username = null;	
    private String password = null;	
    public User() {	
    }	
    public User(String username, String password) {	
        this.username = username;	
        this.password = password;	
    }	
    ....各种set、get方法
  • 使用简单的集合模拟一个数据库

    private static List<User> list = new ArrayList<>();	
    //装载些数据进数据库	
    static {	
        list.add(new User("aaa","111"));	
        list.add(new User("bbb","222"));	
        list.add(new User("ccc","333"));	
    }	
    //通过用户名和密码查找用户	
    public static User find(String username, String password) {	
        for (User user : list) {	
            if (user.getUsername().equals(username) && user.getPassword().equals(password)) {	
                return user;	
            }	
        }	
        return null;	
    }
  • 表单提交的工作我就在jsp写了,如果在Servlet写太麻烦了!

<form action="/ouzicheng/LoginServlet" method="post">	
    用户名:<input type="text" name="username"><br/>	
    密码:<input type="password" name="password"><br/>	
    <input type="submit" value="提交">	
</form>
  • 获取到表单提交的数据,查找数据库是否有相对应的用户名和密码。如果没有就提示用户名或密码出错了,如果有就跳转到另外一个页面

        String username = request.getParameter("username");	
        String password = request.getParameter("password");	
        User user = UserDB.find(username, password);	
        //如果找不到,就是用户名或密码出错了。	
        if (user == null) {	
            response.getWriter().write("you can't login");	
            return;	
        }	
        //标记着该用户已经登陆了!	
        HttpSession httpSession = request.getSession();	
        httpSession.setAttribute("user", user);	
        //跳转到其他页面,告诉用户成功登陆了。	
        response.sendRedirect(response.encodeURL("index.jsp"));
  • 我们来试试下数据库没有的用户名和密码,提示我不能登陆。

640?wx_fmt=png

640?wx_fmt=png

  • 试试数据库存在的用户名和密码

640?wx_fmt=png

640?wx_fmt=png


利用Session防止表单重复提交


  • 重复提交的危害:


    • 在投票的网页上不停地提交,实现了刷票的效果。

    • 注册多个用户,不断发帖子,扰乱正常发帖秩序。


  • 首先我们来看一下常见的重复提交。


    • 在处理表单的Servlet中刷新。

    • 后退再提交

    • 网络延迟,多次点击提交按钮


  • 下面的gif是后退再提交,在处理提交请求的Servlet中刷新 640?wx_fmt=gif



  • 下面的gif是网络延迟,多次点击提交按钮 640?wx_fmt=gif



  • 对于网络延迟造成的多次提交数据给服务器,其实是客户端的问题。于是,我们可以使用javaScript来防止这种情况



  • 要做的事情也非常简单:当用户第一次点击提交按钮时,把数据提交给服务器。当用户再次点击提交按钮时,就不把数据提交给服务器了。



  • 监听用户提交事件。只能让用户提交一次表单!


<%@ page contentType="text/html;charset=UTF-8" language="java" %>	
<html>	
<head>	
    <title>表单提交</title>	
    <script type="text/javascript">	
        //定义一个全局标识量:是否已经提交过表单数据	
        var isCommitted = false;	
        function doSubmit() {	
            //false表示的是没有提交过,于是就可以让表单提交给Servlet	
            if(isCommitted==false) {	
                isCommitted = true;	
                return true;	
            }else {	
                return false;	
            }	
        }	
    </script>	
</head>	
<body>	
<form action="/ouzicheng/Servlet7" onsubmit="return doSubmit()">	
    用户名:<input type="text" name="username">	
    <input type="submit" value="提交">	
</form>	
</body>	
</html>
  • 好的,我们来试一下是不是真的可以解决网络延迟所造成的多次提交表单数据,注意鼠标,我已经点击过很多次的了!

640?wx_fmt=gif


  • 由于网络延迟造成的多次提交数据给服务器,我们还可以使用javaScript代码这样解决:当我点击过一次提交按钮时,我就把提交的按钮隐藏起来。不能让用户点击了!



  • 想要让按钮隐藏起来,也很简单。只要获取到按钮的节点,就可以控制按钮的隐藏或显示了!


    <script type="text/javascript">	
        function doSubmit() {	
            var button = document.getElementById("button");	
            button.disabled = disabled;	
            return true;	
        }	
    </script>
  • 我们再来看一下效果

640?wx_fmt=gif


  • 在处理表单的Servlet中刷新和后退再提交这两种方式不能只靠客户端来限制了。也就是说javaScript代码无法阻止这两种情况的发生。



  • 于是乎,我们就想得用其他办法来阻止表单数据重复提交了。我们现在学了Session,Session可以用来标识一个用户是否登陆了。Session的原理也说了:不同的用户浏览器会拥有不同的Session。而request和ServletContext为什么就不行呢?request的域对象只能是一次http请求,提交表单数据的时候request域对象的数据取不出来。ServletContext代表整个web应用,如果有几个用户浏览器同时访问,ServletContext域对象的数据会被多次覆盖掉,也就是说域对象的数据就毫无意义了。



  • 可能到这里,我们会想到:在提交数据的时候,存进Session域对象的数据,在处理提交数据的Servlet中判断Session域对象数据????。究竟判断Session什么?判断Session域对象的数据不为null?没用呀,既然已经提交过来了,那肯定不为null。



  • 此时,我们就想到了,在表单中还有一个隐藏域,可以通过隐藏域把数据交给服务器。


    • 判断Session域对象的数据和jsp隐藏域提交的数据是否对应。

    • 判断隐藏域的数据是否为空【如果为空,就是直接访问表单处理页面的Servlet】

    • 判断Session的数据是否为空【servlet判断完是否重复提交,最好能立马移除Session的数据,不然还没有移除的时候,客户端那边儿的请求又来了,就又能匹配了,产生了重复提交。如果Session域对象数据为空,证明已经提交过数据了!】


  • 我们向Session域对象的存入数据究竟是什么呢?简单的一个数字?好像也行啊。因为只要Session域对象的数据和jsp隐藏域带过去的数据对得上号就行了呀,反正在Servlet上判断完是否重复提交,会立马把Session的数据移除掉的。更专业的做法是:向Session域对象存入的数据是一个随机数【Token--令牌】。



  • 生成一个独一无二的随机数


/*	
* 产生随机数就应该用一个对象来生成,这样可以避免随机数的重复。	
* 所以设计成单例	
* */	
public class TokenProcessor {	
    private TokenProcessor() {	
    }	
    private final static TokenProcessor TOKEN_PROCESSOR = new TokenProcessor();	
    public static TokenProcessor getInstance() {	
        return TOKEN_PROCESSOR;	
    }	
    public static String makeToken() {	
        //这个随机生成出来的Token的长度是不确定的	
        String token = String.valueOf(System.currentTimeMillis() + new Random().nextInt(99999999));	
        try {	
            //我们想要随机数的长度一致,就要获取到数据指纹	
            MessageDigest messageDigest = MessageDigest.getInstance("md5");	
            byte[] md5 = messageDigest.digest(token.getBytes());	
            //如果我们直接 return  new String(md5)出去,得到的随机数会乱码。	
            //因为随机数是任意的01010101010,在转换成字符串的时候,会查gb2312的码表,gb2312码表不一定支持该二进制数据,得到的就是乱码	
            //于是乎经过base64编码成了明文的数据	
            BASE64Encoder base64Encoder = new BASE64Encoder();	
            return base64Encoder.encode(md5);	
        } catch (NoSuchAlgorithmException e) {	
            e.printStackTrace();	
        }	
        return null;	
    }	
}
  • 创建Token随机数,并跳转到jsp页面

        //生出随机数	
        TokenProcessor tokenProcessor = TokenProcessor.getInstance();	
        String token = tokenProcessor.makeToken();	
        //将随机数存进Session中	
        request.getSession().setAttribute("token", token);	
        //跳转到显示页面	
        request.getRequestDispatcher("/login.jsp").forward(request, response);
  • jsp隐藏域获取到Session的值

<form action="/ouzicheng/Servlet7" >	
    用户名:<input type="text" name="username">	
    <input type="submit" value="提交" id="button">	
    <%--使用EL表达式取出session中的Token--%>	
    <input type="hidden" name="token" value="${token}" >	
</form>
  • 在处理表单提交页面中判断:jsp隐藏域是否有值带过来,Session中的值是否为空,Session中的值和jsp隐藏域带过来的值是否相等

        String serverValue = (String) request.getSession().getAttribute("token");	
        String clientValue = request.getParameter("token");	
        if (serverValue != null && clientValue != null && serverValue.equals(clientValue)) {	
            System.out.println("处理请求");	
            //清除Session域对象数据	
            request.getSession().removeAttribute("token");	
        }else {	
            System.out.println("请不要重复提交数据!");	
        }
  • 下面我们再来看一下,已经可以解决表单重复提交的问题了!

640?wx_fmt=gif

实现原理是非常简单的:

  • 在session域中存储一个token

  • 然后前台页面的隐藏域获取得到这个token

  • 在第一次访问的时候,我们就判断seesion有没有值,如果有就比对。对比正确后我们就处理请求,接着就把session存储的数据给删除了

  • 等到再次访问的时候,我们session就没有值了,就不受理前台的请求了!


一次性校验码


  • 一次性校验码其实就是为了防止暴力猜测密码



  • 在讲response对象的时候,我们使用response对象输出过验证码,但是没有去验证!



  • 验证的原理也非常简单:生成验证码后,把验证码的数据存进Session域对象中,判断用户输入验证码是否和Session域对象的数据一致。



  • 生成验证码图片,并将验证码存进Session域中


        //在内存中生成图片	
        BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);	
        //获取到这张图片	
        Graphics2D graphics2D = (Graphics2D) bufferedImage.getGraphics();	
        //设置背景色为白色	
        graphics2D.setColor(Color.white);	
        graphics2D.fillRect(0, 0, 80, 20);	
        //设置图片的字体和颜色	
        graphics2D.setFont(new Font(null, Font.BOLD, 20));	
        graphics2D.setColor(Color.BLUE);	
        //生成随机数	
        String randomNum = makeNum();	
        //往这张图片上写数据,横坐标是0,纵坐标是20	
        graphics2D.drawString(randomNum, 0, 20);	
        //将随机数存进Session域中	
        request.getSession().setAttribute("randomNum", randomNum);	
        //控制浏览器不缓存该图片	
        response.setHeader("Expires", "-1");	
        response.setHeader("Cache-Control", "no-cache");	
        response.setHeader("Pragma", "no-cache");	
        //通知浏览器以图片的方式打开	
        response.setHeader("Content-type", "image/jpeg");	
        //把图片写给浏览器	
        ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
  • 生成随机数的方法:

    private String makeNum() {	
        Random random = new Random();	
        //生成0-6位的随机数	
        int num = random.nextInt(999999);	
        //验证码的数位全都要6位数,于是将该随机数转换成字符串,不够位数就添加	
        String randomNum = String.valueOf(num);	
        //使用StringBuffer来拼凑字符串	
        StringBuffer stringBuffer = new StringBuffer();	
        for (int i = 0; i < 6 - randomNum.length(); i++) {	
            stringBuffer.append("0");	
        }	
        return stringBuffer.append(randomNum).toString();	
    }
  • jsp显示页面

<form action="/ouzicheng/Login2Servlet">	
    用户名:<input type="text" name="username"><br>	
    密码:<input type="password" name="password"><br>	
    验证码:<input type="text" name="randomNum">	
    <img src="/ouzicheng/ImageServlet" ><br><br>	
    <input type="submit" value="提交">	
</form>
  • 处理提交表单数据的Servlet,判断用户带过来验证码的数据是否和Session的数据相同。

        //获取用户输入验证码的数据	
        String client_randomNum = request.getParameter("randomNum");	
        //获取Session中的数据	
        String session_randomNum = (String) request.getSession().getAttribute("randomNum");	
        //判断他俩数据是否相等,用户是否有输入验证码,Session中是否为空	
        if (client_randomNum == null || session_randomNum == null || !client_randomNum.equals(session_randomNum)) {	
            System.out.println("验证码错误了!!!");	
            return ;	
        }	
        //下面就是验证用户名和密码...................
  • 显示页面是这样子的

640?wx_fmt=png

  • 我们来看一下效果!

640?wx_fmt=gif

对于校验码实现思路是这样子的:

  • 使用awt语法来描写一张验证码,生成随机数保存在seesion域中,我们让验证码不能缓存起来【做到验证码都不一样】

  • 页面直接访问Servlet来获取我们的验证码,于是我们验证码的值就会改变【同时session的值也会被改变】

  • 当用户验证的时候,就是session内的值的验证了。

Session和Cookie的区别


  • 从存储方式上比较


    • Cookie只能存储字符串,如果要存储非ASCII字符串还要对其编码。

    • Session可以存储任何类型的数据,可以把Session看成是一个容器


  • 从隐私安全上比较


    • Cookie存储在浏览器中,对客户端是可见的。信息容易泄露出去。如果使用Cookie,最好将Cookie加密

    • Session存储在服务器上,对客户端是透明的。不存在敏感信息泄露问题。


  • 从有效期上比较


    • Cookie保存在硬盘中,只需要设置maxAge属性为比较大的正整数,即使关闭浏览器,Cookie还是存在的

    • Session的保存在服务器中,设置maxInactiveInterval属性值来确定Session的有效期。并且Session依赖于名为JSESSIONID的Cookie,该Cookie默认的maxAge属性为-1。如果关闭了浏览器,该Session虽然没有从服务器中消亡,但也就失效了。


  • 从对服务器的负担比较


    • Session是保存在服务器的,每个用户都会产生一个Session,如果是并发访问的用户非常多,是不能使用Session的,Session会消耗大量的内存。

    • Cookie是保存在客户端的。不占用服务器的资源。像baidu、Sina这样的大型网站,一般都是使用Cookie来进行会话跟踪。


  • 从浏览器的支持上比较


    • 如果浏览器禁用了Cookie,那么Cookie是无用的了!

    • 如果浏览器禁用了Cookie,Session可以通过URL地址重写来进行会话跟踪。


  • 从跨域名上比较


    • Cookie可以设置domain属性来实现跨域名

    • Session只在当前的域名内有效,不可夸域名


Cookie和Session共同使用


  • 如果仅仅使用Cookie或仅仅使用Session可能达不到理想的效果。这时应该尝试一下同时使用Session和Cookie



  • 那么,什么时候才需要同时使用Cookie和Session呢?



  • 在上一篇博客中,我们使用了Session来进行简单的购物,功能也的确实现了。现在有一个问题:我在购物的途中,不小心关闭了浏览器。当我再返回进去浏览器的时候,发现我购买过的商品记录都没了!!为什么会没了呢?原因也非常简单:服务器为Session自动维护的Cookie的maxAge属性默认是-1的,当浏览器关闭掉了,该Cookie就自动消亡了。当用户再次访问的时候,已经不是原来的Cookie了。



  • 我们现在想的是:即使我不小心关闭了浏览器了,我重新进去网站,我还能找到我的购买记录。



  • 要实现该功能也十分简单,问题其实就在:服务器为Session自动维护的Cookie的maxAge属性是-1,Cookie没有保存在硬盘中。我现在要做的就是:把Cookie保存在硬盘中,即使我关闭了浏览器,浏览器再次访问页面的时候,可以带上Cookie,从而服务器识别出Session。



  • 第一种方式:只需要在处理购买页面上创建Cookie,Cookie的值是Session的id返回给浏览器即可


        Cookie cookie = new Cookie("JSESSIONID",session.getId());	
        cookie.setMaxAge(30*60);	
        cookie.setPath("/ouzicheng/");	
        response.addCookie(cookie);

  • 第二种方式: 在server.xml文件中配置,将每个用户的Session在服务器关闭的时候序列化到硬盘或数据库上保存。但此方法不常用,知道即可!



最后

乐于输出干货的Java技术公众号:Java3y。公众号内有200多篇原创技术文章、海量视频资源、精美脑图,不妨来关注一下!

640?wx_fmt=jpeg

有帮助?好看!转发!640


【学习笔记】人群归因分数 PAF 以及combined PAF(更新) 在此推荐2篇发表在lancet以及jama子刊上的paf文章,这两篇文章套路是一样的,只是在不同国家进行。希望对大家学习PAF有所帮助,后面有新内容也会继续分享,也欢迎大家分享使用R语言计算PAF的经验~~~的时候,先建立了相关矩阵,再做主成分分析,得到communality。详细信息大家可翻阅原文。 阅读详情

相关推荐

STM32F103C8T6用官方bootloader实现IAP升级操作方法

在使用STM32F103C8T6单片机IAP功能时,可以自己写bootloader程序,也可以使用官方bootloader文件。下面说一下使用官方bootloader的使用方法。 首先下载官方bootloader文件 目前使用的是这个版本,打开文件夹,选择适合自己编译器的工程。 目前使用的是keil,所以打开MDK-ARM文件夹 打开IAP工程 打开后根据自己的单片机型号,对工程进行简单的修...

HXYDJ的博客 1万+

Hibernate--Session对象及常用API、Transaction对象及API详解

Session: Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句)。但需要注意的是**Session是非线程安全的。**同时,Hibernate的session不同于JSP应用中的HttpSession。这里当使用session这个术语时,其实指的是Hibernate中的session,而以后会将HttpSession对象成为用...

吴声子夜歌的博客 1391

Android手机本地语音转文字实战:用FunASR+ONNX Runtime打造离线ASR应用(附模型下载)

本文详细介绍了如何在Android应用中集成FunASR和ONNX Runtime,构建高性能的离线语音识别系统。通过模型选择、工程化集成和性能调优等实战技巧,开发者可以实现本地语音转文字功能,有效保护用户隐私并提升响应速度。

weixin_29046611的博客 266

Servlet API中的会话管理操作(基于Cookie与Session)

本篇文章将介绍Servlet中的会话管理操作,前面在介绍HTTP的时候,我们已经说了Cookie与Session的基本原理,Cookie相当于就诊卡,就诊卡一刷得到的信息就相当于Session,Servlet对Cookie与Session有着很好的支持,可以实现会话的管理操作。............

未见花闻的博客 1034

【低空经济】森林火情高精度监测与早期预警无人机巡护方案

在全球范围内,森林火灾已成为一个严重的生态和社会问题。它不仅对自然生态系统造成了毁灭性的影响,还对人类的生命财产安全构成了极大的威胁。根据国际森林发展组织的统计,全球每年因森林火灾造成的经济损失高达数百亿美元,甚至在某些年份,火灾损失占到某些国家国民经济总量的相当一部分。因此,开展高效的森林火情监测与早期预警工作显得尤为重要。随着科技的发展,无人机作为新兴的监测工具,以其高效、灵活和经济的特点在森林火灾监测领域展现出了巨大的潜力。

2502_92579126的博客 1212

如何用Python编程实现算术割圆术?

第10章 割圆术 Python编程要点 from … import …语句 math模块的sqrt()函数 round()函数 10.1 图解九章 {:–}觚( gū ):正多边形。“六觚”即正六边形,“十二觚”即正十二边形。 图10-1 六觚、十二觚、二十四觚 提示 图10-1所示由图解九章源码中的“图解割圆术.py”自动绘制而成,我们可运行脚本文件,查看动态的绘制过程。 割六觚以...

人邮异步社区 3237

Servlet——Session

一、Session概述 Session即会话,是Web开发中的一种会话跟踪技术 Session是以javax.servlet.http.HttpSession的接口对象的形式出现的 二、Session与Cookie区别 Cookie是将会话状态保存在了客户端 Session是将会话状态保存在了服务端 三、Session的创建 HttpSession...

浅然的专栏 1958

Coze 打通飞书多维表格,实现数据增删改查操作实战详解

基于Coze 打通飞书多维表实现数据录入系统实战详解

congge 5780

Servlet初学总结(四)

一.为什么需要会话跟踪? 使用浏览器发送的http请求,http请求使用的是http协议,而http协议是一种无状态的协议,它不会去主动记录使用这个http协议的用户是谁,一旦请求发送成功,服务器做出响应以后,那么此时浏览器与服务器之间的链接就会消失,这时服务器就不知道请求来自哪里,是谁发送来的。所以这时我们就需要记录/保存请求/链接的状态,实现这个记录记录/保存请求/链接的状态的过程就叫会话跟踪。 二.什么是会话跟踪? 服务器处理程序实现记录/保存请求/链接的状态的过程就叫会话跟踪。 三.四种会话跟踪技

weixin_47720233的博客 337

GPU 运维实战:H100/H800/B300 换卡与压测

(烧多久、看什么、什么算合格)。文末还给了一个能直接跑的验收判定脚本,三个真实场景的裁决输出都在。

老韩的Linux云计算架构师进阶之路 271

基于ROS2 Humble和VGR数据集完整部署GADEN气体分散仿真环境及模型替换实践

文章摘要 本文详细介绍了基于ROS2 Humble和VGR数据集部署GADEN气体分散仿真环境的方法。GADEN是一款专为移动机器人嗅觉研究设计的3D仿真框架,能够精确模拟气体扩散过程并集成多种环境传感器。文章从系统配置开始,逐步指导读者完成ROS2 Humble环境的搭建、GADEN框架的编译部署,以及VGR数据集的使用。VGR数据集包含120个基于真实房屋模型的CFD仿真案例,为研究提供高度真实的测试环境。教程涵盖了常见问题的解决方案,并深入探讨了气体扩散模型参数的修改方法,为机器人嗅觉算法的开发和验证

huanghm88的专栏 276

Servlet第六篇【Session介绍、API、生命周期、应用、与Cookie区别】

Session 是另一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种的形式记录在服务器,这就是Session如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器中建立了一份“客户明细表”。

ldxxxxll的博客 920

芯片原厂linux驱动开发的分享

大家好,我是XX,来自湖南XX学院,电子信息18级,也曾在创新基地控制组学习过两三年,毕业后就职于一家芯片原厂的解决方案部,担任驱动工程师的职位,算上实习期,我的工作时长已有两年。在此我想将这两年期间学习与积累到的一些经验输出出来,与大家一同分享。知识面有限,只能简单介绍一些驱动开发方向的一些经验,且由于经验尚浅,文中难免会有一些疏漏和错误之处,还请大家积极地批评指正。

嵌入式技术开发 849

会话技术第二篇【Session介绍、API、生命周期、应用、与Cookie区别】

什么是Session Session 是另一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种的形式记录在服务器,这就是Session 如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器...

MazenChan的博客 422

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Java Web基础知识(Servlet、Cookie、Session、Filter、Listener)

Servlet是运行在Web服务器中的小型Java程序,侠义的Servlet是实现了Java语言实现的一个接口,广义的Servlet是任何实现了这个Servlet接口的类,作用是:接受用户的请求,并对请求做出处理,将处理结果响应给客户端。Servlet有三种实现方式:实现Servlet接口,继承抽象类GennericServlet,继承HttPServlet。Servlet是可以接受HTTP请求并做出相应的一种结束,是Java语言编写的一种动态资源。

coding is an art 1307

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Servlet API 详解

在我们的 doGet / doPost 方法中, 就执行到了我们自己的代码. 我们自己的代码会根据请求中的一些信息, 来给 HttpServletResponse 对象设置一些属性. 例如状态码, header, body 等。 我们的 doGet / doPost 执行完毕后, Tomcat 就会自动把 HttpServletResponse 这个我们刚设置好的对象转换成一个符合 HTTP 协议的字符串, 通过 Socket 把这个响应发送出去...

m0_60494863的博客 5492

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Servlet、Session、Cookie

Servlet Servlet 官方API文档 Servlet调用过程 具体调用过程 Servlrt 两个继承类 GenericServlet HttpServlet Servlet 细节 同一个Servlet可以被映射到多个URL上 在Servlet映射到URL中也可以使用通配,但是只能由两种固定格式:.扩展名;/* Servlet 对象创建在浏览器第一次...

qq_40535097的博客 574

【Servlet】Servlet 详解(使用+原理)

文章目录1. Servlet 介绍1.1 什么是 Servlet1.2 Servlet 的主要工作2. Servlet 程序创建步骤2.1 创建项目2.2 引入依赖2.3 创建目录2.4 编写代码2.5 打包程序2.6 部署程序2.7 验证程序3. 使用 Smart Tomcat 进行部署3.1 安装 Smart Tomcat3.2 配置 Smart Tomcat3.3 使用 Smart Tomcat4. 访问出错解决方案4.1 出现 4044.2 出现 4054.3 出现 5004.4 出现“空白页面”4

吞吞吐吐大魔王的博客 3万+

【JavaWeb】Maven、Servlet、cookie/session

Servlet就是sun公司开发动态web的一门技术。Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:编写一个类,实现Servlet接口;把开发好的Java类部署到web服务器中。把实现了Servlet接口Java程序叫做Servlet。

杨DaB的博客 1555

Servlet详解 [Session/Cookie]

Servlet说明 优点 缺点 Servlet三生命周期 Servlet和JSP区别 客户跟踪 Session session的实现原理 典型应用:购物车 Cookie

↫/(ㄒoㄒ)/~~不太会打代码的搬运工↬ 548

Servlet之Cookie和Session

会话技术 在了解cookie和session之前,需要先了解一个概念:会话 1. 概念 在日常生活中,从拨通电话到挂断电话之间的一连串的你问我答的过程就是一个会话。web应用中的会话过程类似于生活中的打电话过程,它指的是客户端(浏览器)与web服务器之间连续发生的一系列请求和响应的过程。例如:一个用户在某个网站上的整个购物过程就是一个会话。 2. HttpServletRequest对象和Se...

时光、疏离了记忆づ童话的博客 536

【Servlet】什么是Servlet;常见状态码;Servlet API;Cookie和Session

【Servlet】什么是Servlet;常见状态码;Servlet API;Cookie和Session

Wisk1019的博客 581

Cookie 和 Session详解

Cookie 和 Session 是 Web 开发中用于**状态管理**的两个核心技术。理解它们的区别和联系对于构建任何需要用户登录或个性化体验的网站都至关重要。

m0_52710583的博客 1027

Cookie和Session的使用及二者的区别

本篇博客主要回顾一下Cookie的功能和作用还有Session的概念及Servlet中Session的使用,以及二者之间的区别,最后会使用Session来模拟实现一个简单的登录功能。

m0_64986499的博客 742
上一篇: Tomcat+Servlet面试题都在这里(修订版)
下一篇: Servlet第一篇【HTTP协议、WEB目录结构、编写入门Servlet程序、Servlet生命周期】(修订版)...
Java3y
Java3y 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 509原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值