1 案例1-显示上一次登陆的时间

1.1 需求

当用户访问我们的servlet时,如果是第一次访问,则提示是第一次访问,否则显示用户上一次的访问时间;

1.2 技术分析

需要记录用户上一次的访问时间,根据分析,request生命周期太短,不合适。servletContext生命周期太长,且是占用服务器的内存空间,使用会话技术,就可以解决这个问题。

1.3 会话概述

所谓的会话技术,就是浏览器与服务器的多次通信之间的一个技术。
按照会话技术的位置,可以分为客户端会话技术和服务器端会话技术。
客户端会话:
专业术语就是cookie技术。
Cookie就是由服务器负责创建的,由浏览器负责保存的一个小文件,这个小文件可以保存少量的信息。
服务器端会话技术:
Session是服务器端的会话技术,可以简单理解为是服务器为每一个浏览器创建的一个内存空间,用于保存与浏览器交互的过程中(会话)保存一些信息。

1.4 Cookie的作用

可以让多个request对象之间的数据共享(多次请求的数据共享);

1.5 Cookie的使用步骤

1:创建cookie的格式:
构造方法:Cookie(String name, String value)
name就是cookie的名称;
value就是cookie要保存的值(不能含中文,否则语法报错)
2:将cookie交给浏览器的方法
response.addCookie(cookie对象);
3:获取cookie的方法:
Cookie[] 数组名 = reqesut.getCookies();

迭代数组,可以获取每一个cookie对象;
面向cookie对象,获取cookie的名称和值;
cookie对象.getName();
cookie对象.getValue();

1.6 Cookie的路径与保存时间

(1)路径
Cookie可以设置一个有效路径(有效路径就是表示这个cookie在访问哪儿的时候有效),如果不设置,默认就是当前路径的上一级路径。
例如:
http://localhost/day33/c1 默认cookie的路径就是:http://localhost/day33
手动修改路径:
Cookie对象.setPath(“/”); 代表的就是当前这个服务器,只要访问的是这个服务器地址,都会带着cookie。
(2)保存时间
设置cookie的存活时间:
Cookie对象.setMaxAge(int值代表的是秒);
如果参数小于0,代表当前会话有效(只要浏览器不关闭,一直有效)
如果参数等于0,代表响应给浏览器的时候cookie立刻死亡(删除cookie的时候使用)
如果参数大于0,代表响应给浏览器的时候开始计时,指定的秒数后cookie死亡。

1.7 设置cookie的域名

  1. package com.itheima.demo01_cookie;
  2. import java.io.IOException;
  3. import javax.servlet.ServletException;
  4. import javax.servlet.http.Cookie;
  5. import javax.servlet.http.HttpServlet;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. /**
  9. * 设置cookie的域名
  10. */
  11. public class Cookie_扩展 extends HttpServlet {
  12. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  13. //1:创建一个cookie对象
  14. Cookie c1 = new Cookie("c11","jack11");
  15. //2:设置路径
  16. //c1.setPath("/");//只要访问这个tomcat,都会带cookie
  17. //设置cookie的域名
  18. c1.setDomain(".abc.com");//地址的域名是本ip地址的www.abc.com的时候,携带这个cookie
  19. //3:设置cookie的存活时间
  20. c1.setMaxAge(50);
  21. //3:将cookie响应给浏览器
  22. response.addCookie(c1);
  23. response.getWriter().print("okk...");
  24. }
  25. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  26. doGet(request, response);
  27. }
  28. }

1.8 案例-纪录上一次的访问时间-步骤分析

1:编写一个servlet,先获取用户携带的cookie,如果有,则显示用户上一次登陆的时候;
2:如果没有显示第一次登陆;
3:更新cookie的值为本次登陆的时间;
参考代码:

  1. /*
  2. * 1:编写一个servlet,先获取用户携带的cookie,如果有,则显示用户上一次登陆的时候;
  3. 2:如果没有显示第一次登陆;
  4. 3:更新cookie的值为本次登陆的时间;
  5. */
  6. //0:解决响应体的中文乱码
  7. response.setContentType("text/html;charset=utf-8");
  8. //1:编写一个servlet,先获取用户携带的cookie,如果有,则显示用户上一次登陆的时候;
  9. Cookie[] cs = request.getCookies();
  10. //1.5:为了解决有cookie,但不是hiscookie的情况,我们需要定义一个boolean类型的变量,用于解决逻辑文件
  11. boolean flag = false;//没有his cookie
  12. if(cs!=null){
  13. for (Cookie c : cs) {
  14. String name = c.getName();
  15. //1:判断用户携带过来的cookie,是不是我们想要的cookie
  16. if("his".equals(name)){
  17. //说明是我们要找的cookie
  18. String value = c.getValue();
  19. response.getWriter().println("亲,欢迎回来,您上一次的访问时间是:"+value);
  20. flag=true;//说明找到了
  21. break;
  22. }
  23. }
  24. }else{
  25. //什么cookie都没有
  26. response.getWriter().println("亲,您是第一次访问该网站...");
  27. }
  28. //判断flag
  29. if(!flag){
  30. ////有其他cookie,但是不是hiscookie
  31. response.getWriter().println("亲,您是第一次访问该网站...");
  32. }
  33. //3:更新cookie的值为本次登陆的时间;
  34. Cookie c = new Cookie("his",new Date().toLocaleString());
  35. c.setPath("/");
  36. c.setMaxAge(60*60);
  37. response.addCookie(c);

1.9 Cookie与缓存的区别

缓存:
是指服务器给浏览器响应的所有信息;(包含页面上的所有内容,例如:图片、文件、页面)
Cookie:
是指服务器让浏览器记住的一些很少量的信息(简单理解为只是缓存中的一小部分信息)

2 案例2—验证码

2.1 需求

当用户访问jsp页面的时候,显示一张验证码,并让用户填写一个验证码,当用户提交填写的验证码的时候在servlet中比对用户填写的验证码是否正确。

2.2 技术分析

1: 由于用户访问jsp时会发出一次请求,提交表单的时候会发出第二次请求,因此只能使用会话技术,保存真正的验证码的值,才可以在服务器端比较用户填写的验证码是否正确;
2: 会话技术有两种,一个是客户端会话技术(Cookie),另一个是服务器端会话技术(session)
本案例采用session技术实现。(因为cookie保存在客户端,不安全!!!,在开发中验证码绝对不能存在cookie里面,极度不安全,非常容易被破解。)

2.3 Session概述

Session是服务器端的会话技术,可以简单理解为是服务器为每一个浏览器创建的一个内存空间,用于保存与浏览器交互的过程中(会话)的一些信息。

2.4 Session的作用

1:保存验证码;
2:保存用户登录的对象;
3:用于与浏览器会话的数据保存;
4:session可以自动与cookie相互关联,完成会话技术(服务器可以自动识别每一个浏览器的身份)

2.5 Session使用原则

能少存尽量少存!因为服务器使用的是服务器的内存空间,能少存尽量少存,能让他快点死尽量让他快点死。

2.6 Session如何使用

Session主要用于保存信息,且session由服务器创建,保存在服务器端,程序员只能获取session并使用session,不能手动创建session。

常用API:
获取session:
request.getSession();
存值:
Session对象.setAttribite(“属性名”,属性值);
取值:
Session对象.getAttribite(“属性名”);
删除值:
Session对象.removeAttribute(“属性名”);
销毁session对象:
Session对象.invalidate();
设置存活时间:
Session对象.setMaxInactiveInterval(秒数); (默认存活30分钟)

2.7 Session的生命周期问题(面试常用)

从session对象创建到session对象死亡;
(1)创建时机
1)这个浏览器在servlet中第一次使用session的时候会创建。
2)这个浏览器第一次访问jsp的时候,服务器也会为这个浏览器创建一个session对象。
(2)销毁时机
1)程序员调用invalidate方法(立刻销毁)
2)设置的存活时间到了(默认是30分钟)
3)服务器非正常关闭(例如突然断电)
注意事项:
1: 正常关闭服务器,session不会销毁,而是直接序列化到硬盘上,下一次服务器启动的时候,会重新创建出来。
2: 如果浏览器单方面关闭会话,服务器上对应的session不会死亡,但是会导致服务器给浏览器创建的JSESSIONID的cookie死亡,当cookie死亡后,会导致浏览器无法找到上一个session对象,会造成服务器中session死亡的假象。(非常浪费服务器性能)

2.8 案例的思路分析与代码步骤

验证码案例的流程分析.png
部分参考代码:
项目结构
image.png
index.jsp

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  4. <html>
  5. <head>
  6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  7. <title>Insert title here</title>
  8. <script type="text/javascript">
  9. function change(t) {
  10. t.src="http://localhost/day33/code?"+new Date().getTime();
  11. }
  12. </script>
  13. </head>
  14. <body>
  15. <font color="red">
  16. <%=
  17. request.getAttribute("msg")==null?"":request.getAttribute("msg")
  18. %>
  19. </font>
  20. <form action="http://localhost/day33/CodeYanZheng" method="get">
  21. 验证码:<input type="text" name="code">
  22. <img src="http://localhost/day33/code" onclick="change(this)">
  23. <br>
  24. <input type="submit" value="开始验证">
  25. </form>
  26. </body>
  27. </html>

CodeServlet.java
这是个生成验证码的servlet,改写的代码是62-64行主要是将生成的验证码添加到session中

package com.itheima.demo04_验证码;

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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CodeServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 使用java图形界面技术绘制一张图片

        int charNum = 4;
        int width = 20 * 4;
        int height = 28;

        // 1. 创建一张内存图片
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 2.获得绘图对象
        Graphics graphics = bufferedImage.getGraphics();

        // 3、绘制背景颜色
        graphics.setColor(Color.YELLOW);
        graphics.fillRect(0, 0, width, height);

        // 4、绘制图片边框
        graphics.setColor(Color.GRAY);
        graphics.drawRect(0, 0, width - 1, height - 1);

        // 5、输出验证码内容
        graphics.setColor(Color.RED);
        graphics.setFont(new Font("宋体", Font.BOLD, 22));

        // 随机输出4个字符
        String s = "ABCDEFGHGKLMNPQRSTUVWXYZ23456789";
        Random random = new Random();

        // session中要用到
        String msg = "";

        int x = 5;
        for (int i = 0; i < charNum; i++) {
            int index = random.nextInt(32);
            String content = String.valueOf(s.charAt(index));

            msg += content;
            graphics.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
            graphics.drawString(content, x, 22);
            x += 20;
        }

        System.out.println("本次验证码是:"+msg);
        //将msg的值保存到session中
        request.getSession().setAttribute("seCode",msg);


        // 6、绘制干扰线
        graphics.setColor(Color.GRAY);
        for (int i = 0; i < 5; i++) {
            int x1 = random.nextInt(width);
            int x2 = random.nextInt(width);

            int y1 = random.nextInt(height);
            int y2 = random.nextInt(height);
            graphics.drawLine(x1, y1, x2, y2);
        }

        // 释放资源
        graphics.dispose();

        // 图片输出 ImageIO
        ImageIO.write(bufferedImage, "jpg", response.getOutputStream());

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

}

CodeYanZheng.java

package com.itheima.demo04_验证码;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class EqualsServlet
 */
public class CodeYanZheng extends HttpServlet {
    //专门比较验证码的servlet
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1:参  调   存    转
        String c = request.getParameter("code");//获取用户填写的验证码
        //2:获取session中的验证码
        Object sec = request.getSession().getAttribute("seCode");//根据属性名从session获取属性值
        //3:比较
        if(c!=null&&c.equalsIgnoreCase((String)sec)){
            //说明验证码对了
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().println("验证码正确,可以去购物了...");
        }else{
            //说明验证码错了
            request.setAttribute("msg","验证码错误!");
            request.getRequestDispatcher("/index.jsp").forward(request, response);
        }
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}