JavaWeb[总结]

文章目录

  • 一、Tomcat
    • 1. BS 与 CS 开发介绍
      • 1.1 BS 开发
      • 1.2 CS 开发
    • 2. 浏览器访问 web 服务过程详解(面试题)
      • 2.1 回到前面的 JavaWeb 开发技术栈图
      • 2.2 浏览器访问 web 服务器文件的 UML时序图(过程) !
  • 二、动态 WEB 开发核心-Servlet
    • 1. 为什么会出现 Servlet
    • 2. 什么是 Servlet
    • 3. Servlet 在 JavaWeb 项目位置
    • 4. Servlet 基本使用
      • 4.1 Servlet开发方式说明
      • 4.2浏览器调用 Servlet 流程分析[重点]
      • 4.3 Servlet 生命周期
    • 6. ServletConfig
      • 6.1 基本介绍
      • 6.2 ServletConfig 能干什么
    • 7. ServletContext
      • 7.1 为什么需要 ServletContext
      • 7.2 应用实例-简单的网站访问次数计数器
    • 8. HttpServletRequest
      • 8.1 HttpServletRequest介绍
      • 8.2 HttpServletRequest 常用方法
      • 8.3 应用实例
      • 8.4 注意事项和细节
      • 8.5 请求转发[重要]
        • 8.5.1 为什么需要请求转发
        • 8.5.2 请求转发声明
        • 8.5.3 实现请求转发原理图
        • 8.5.4 请求转发注意事项和细节
    • 9. HttpServletResponse
      • 9.1 HttpServletResponse介绍
      • 9.2 HttpServletResponse 类图
      • 9.3 向客户端返回数据方法
      • 9.4 请求重定向[重要]
        • 9.4.1 请求重定向原理示意图
        • 9.4.2 请求重定向注意事项和细节
  • 三、WEB开发通信协议-HTTP 协议
    • 1. HTTP请求包分析(GET)
    • 2. HTTP请求包分析(POST)
    • 3. GET 请求和 POST请求分别有哪些?
    • 4. HTTP 请求中怎么选择 GET 和 POST 方式
    • 5. HTTP响应包分析
    • 6. 状态码
      • 6.1 状态码 301
      • 6.2 状态码 304
    • 7. MIME 类型
      • 7.1 MIME 介绍
      • 7.2 常见的 MIME 类型
    • 8. HTTP 作业
  • 四、WEB 工程路径专题
    • 1. 解决方案: base 标签
      • 1.1 base 基本介绍
      • 1.2 应用实例
      • 1.3 WEB工程路径注意事项和细节
  • 五、Web 开发会话技术 -Cookie&Session
    • 1. 会话
      • 1.1 基本介绍
      • 1.2 会话的两种技术
    • 2. cookie 介绍
    • 3. Cookie 生命周期
    • 4 . Cookie 有效路径
    • 5. Cookie注意事项和细节
    • 6. Session 有什么用
    • 7. Session 基本原理
      • 7.1 Session 原理示意图
      • 7.2 Session 可以做什么
      • 7.3 如何理解 Session
    • 8. session 常用方法
    • 9. session 底层实现机制 *
      • 9.1 原理分析图
      • 9.2 代码演示
      • 1.7.3 Session 实现原理动画
    • 10. Session 生命周期
      • 10.1 session 生命周期-说明
      • 10.2 Session 生命周期-应用实例
    • 11. Session 经典案例-防止非法进入管理页面
      • 11.1 作业布置
      • 11.2 作业代码
  • 六、JavaWeb三大组件之监听器 Listener
    • 1. Listener 监听器介绍
    • 2. JavaWeb 的监听器
      • 2.1 ServletContextListener 监听器
      • 2.2 ServletContextAttributeListener 监听器
      • 2.3 其他监听器-使用较少
        • 2.3.1 HttpSessionListener 监听器
        • 2.3.2 HttpSessionAttributeListener 监听器
        • 2.3.3 **ServletRequestListener** **监听器**
        • 2.3.4 **ServletRequestAttributeListener** **监听器**
        • 2.3.5 HttpSessionBindingListener 感知监听器
        • 2.3.6 **HttpSessionActivationListener** **感知监听器**
  • 七、JavaWeb 三大组件之 过滤器 Filter
    • 1. Filter 过滤器说明
    • 2. Filter 过滤器基本原理
    • 3. Filter 应用案例
    • 4. Filter 过滤器 url-pattern
    • 5. Filter 过滤器生命周期
    • 6. FilterConfig
    • 7. FilterChain 过滤器链
  • 八、数据交换和异步请求 - JSON & Ajax
    • 1. JSON 介绍
    • 2. JSON 规则
    • 3. JSON 在 java 中使用
      • 1. 说明
      • 2. JSON 在 java中 应用场景
      • 3. 应用实例 JSON 在 java中应用场景
  • 九、Ajax 基本介绍
    • 1. Ajax 是什么
    • 2. Ajax 经典应用场景
    • 3. Ajax 原理示意图
    • 4. JavaScript 原生 Ajax 请求
  • 十、线程数据共享和安全 ThreadLocal
    • 1. 什么是 ThreadLocal
    • 2. 快速人门 ThreadLocal
    • 3. ThreadLocal 源码解读+画图

一、Tomcat

1. BS 与 CS 开发介绍

1.1 BS 开发

  1. B: browser(浏览器, 种类太多 ff, chrome, ie, edge,)
  2. S: Server(服务端, 考虑很多)
  3. 示意图

image-20231026110211787

对 BS 的解读

(1) 兼容性 , 因为浏览器的种类很多,发现你写的程序,在某个浏览器会出现问题,其它浏览器正常
(2) 安全性, 通常情况下,BS 安全性不如 CS 好控制
(3) 易用性, BS 好于 CS, 浏览器电脑有
(4) 扩展性, BS 相对统一,只需要写 Server

image-20231026104313960

1.2 CS 开发

1. C: Client(客户端)

2. S: Server(服务端)

示意图

image-20231026110416606

2. 浏览器访问 web 服务过程详解(面试题)

2.1 回到前面的 JavaWeb 开发技术栈图

image-20231026142847303

2.2 浏览器访问 web 服务器文件的 UML时序图(过程) !

image-20231026143000521

二、动态 WEB 开发核心-Servlet

1. 为什么会出现 Servlet

  • 引入我们动态网页(能和用户交互)技术 --> Servlet
  • 对 JavaWeb 技术体系的流程图改造说明(细化).[整体的概念]

image-20231026172700613

2. 什么是 Servlet

  • 什么是 Servlet

Servlet 在开发动态 WEB 工程中,得到广泛的应用,掌握好 Servlet 非常重要了, Servlet(基石)是 SpringMVC 的基础

  • Servlet(Java 服务端小程序),它的特点
  1. 他是由服务器端调用和执行的(一句话:是Tomcat解析和执行)
  2. 他是用java语言编写的, 本质就是Java类
  3. 他是按照Servlet规范开发的(除了tomcat->Servlet weblogic->Servlet)
  4. 功能强大,可以完成几乎所有的网站功能(在以前,我们老程员,使用Servlet开发网站) 技术栈要求高

3. Servlet 在 JavaWeb 项目位置

image-20231026172745345

4. Servlet 基本使用

4.1 Servlet开发方式说明

  1. servlet3.0 前使用 web.xml , servlet3.0 版本以后(包括 3.0)支持注解, 同时支持 web.xml配置
  2. 如何看 servlet 版本

image-20231026180706901

4.2浏览器调用 Servlet 流程分析[重点]

image-20231026180822630

4.3 Servlet 生命周期

  • 主要有三个方法
  1. init() 初始化阶段
  2. service() 处理浏览器请求阶段
  3. destroy() 终止阶段
  • 示意图(比较重要,而且形象)

image-20231026184539751

  • 初始化阶段(init 方法)

Servlet 容器(比如:Tomcat) 加载 Servlet,加载完成后,Servlet 容器会创建一个 Servlet 实例并调用 init()方法,init()方法只调用一次。

image-20231026185241248

Servlet 容器如果遇到上面的情况会重新装载 Servlet:

  1. Servlet 容器(Tomcat)启动时自动装载某些 servlet,实现这个需要在 web.xml 文件中添加 1 1 表示装载的顺序
  2. 在 Servlet 容器启动后,浏览器首次向 Servlet 发送请求(这个前面说过)
  3. Servlet 重新装载时(比如 tomcat 进行 redeploy【redeploy 会销毁所有的 Servlet 实例】),浏览器再向 Servlet 发送请求时,相当于第 1 次请求,先实例化Servlet --》 再调用 init(…) 方法 --》 调用service(…)方法
  • 处理浏览器请求阶段(service 方法)
  1. 每收到一个 http 请求,服务器就会产生一个新的线程取处理[线程]
  2. 创建一个用于封装 HTTP请求 消息的 ServletRequest 对象和一个代表 HTTP响应 消息的 ServletResponse 对象
  3. 然后调用 Servlet 的 service() 方法并将请求和响应对象作为参数传递进去
  • 终止阶段 destroy方法(体现 Servlet 完整的生命周期)

当 web 应用被终止,或者 Servlet 容器终止运行,或者 Servlet 类重新装载时,会调用 destroy() 方法,比如重启 Tomcat、或者 redeploye web (重新发布)应用。

  • 上个图,切记一定要自己练习一遍

工程路径:D:\IDEA_code\xjz_javaweb\servlet

image-20231026190454648

6. ServletConfig

6.1 基本介绍

  1. ServletConfig 类是为 Servlet 程序的配置信息的类
  2. Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建
  3. Servlet 程序默认是第 1 次访问的时候创建,ServletConfig 在 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象

6.2 ServletConfig 能干什么

  1. 获取 Servlet 程序的 servlet-name 的值

  2. 获取初始化参数 init-param

  3. 获取 ServletContext 对象

应用实例…

示意图(思路分析)

image-20231031161546465

7. ServletContext

7.1 为什么需要 ServletContext

  1. 先看一个需求: 如果我们希望统计某个 web 应用的所有 Servlet 被访问的次数,怎么办

  2. 方案 1-DB

image-20231031171859412

  1. 方案 2-ServletContext

image-20231031171922978

由于一个 WEB 应用中的所有 Servlet 共享同一个 ServletContext 对象,因此 Servlet 对象之间可以通过 ServletContext 对象来实现多个 Servlet 间通讯。ServletContext 对象通常也被称之为域对象。【示意图】

image-20231031172032250

详情看 韩顺平JavaWeb-笔记

7.2 应用实例-简单的网站访问次数计数器

  1. 需求:完成一个简单的网站访问次数计数器

image-20231031175539910

  1. 使用 Chrome 访问 payServlet, 每访问一次,就增加 1 访问次数,在后台输出,并将结果返回给浏览器显示
  2. 使用火狐访问 OrderServlet,每访问一次,就增加 1 访问次数,在后台输出,并将结果返回给浏览器显示

image-20231031175623372

代码如下D:\IDEA_code\xjz_javaweb\servlet\src\com\xjz\servlet\servletcontext

运行结果

image-20231031181128163

8. HttpServletRequest

8.1 HttpServletRequest介绍

  1. HttpServletRequest 对象代表客户端的请求
  2. 当客户端/浏览器通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这个对象中
  3. 通过这个对象的方法,可以获得客户端这些信息。

我们是OOP程序员,第一步,看它的类图(继承关系和方法)

8.2 HttpServletRequest 常用方法

  1. getRequestURI() 获取请求的资源路径 http://localhost:8080**/servlet/loginServlet**

  2. getRequestURL() 获 取 请 求 的 统 一 资 源 定 位 符 ( 绝 对 路 径 )
    http://localhost:8080/servlet/loginServlet

  3. getRemoteHost() 获取客户端的 主机, getRemoteAddr()

  4. getHeader() 获取请求头

  5. getParameter() 获取请求的参数

  6. getParameterValues() 获取请求的参数(多个值的时候使用) , 比如 checkbox, 返回的数组

  7. getMethod() 获取请求的方式 GET 或 POST

  8. setAttribute(key, value); 设置域数据

  9. getAttribute(key); 获取域数据

  10. getRequestDispatcher() 获取请求转发对象, 请求转发的核心对象

8.3 应用实例

package com.xjz.servlet.request;

import com.sun.org.apache.regexp.internal.RE;

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

/**
 * @author xjz_2002
 * @version 1.0
 */
public class HttpServletRequestMethods extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //这里我们使用 request 对象,获取表单提交的各种数据
        System.out.println("HttpServletRequestMethods doPost() 被调用...");

        /***********************************
         * 获取和 http 请求头相关信息
         ***********************************/
        System.out.println("请求的资源路径 URI= " + request.getRequestURI()); ///servlet/requestMethods
        //http://主机/uri
        System.out.println("请求的统一资源定位符(决定路径) URL= " + request.getRequestURL());// http://localhost:8080/servlet/requestMethods
        System.out.println("请求的客户端 ip地址=" + request.getRemoteAddr());//本地就是 127.0.0.1
        //思考题:如发现某个 ip 在 10s 中,访问的次数超过 100 次,就封 ip
        //实现思路:1 用一个集合 concurrentHashmap[ip:访问次数] 2[线程/定时扫描]3 做成处理
        System.out.println("http 请求头 HOST=" + request.getHeader("Host")); //HOST=localhost:8080
        //说明:如果我们希望得到请求头的相关信息,可以使用request.getHeader(""请求头字段)
        System.out.println("该请求的发起地址是=" + request.getHeader("Referer"));//
        //请获取访问网站的浏览器是什么?
        String userAgent = request.getHeader("User-agent");
        System.out.println("userAgent=" + userAgent);
        String[] s = userAgent.split(" ");
        System.out.println("浏览器=" + s[s.length - 1].split("\\/")[0]);
        // 主要是 Get / Post
        System.out.println("http 请求方式= " + request.getMethod());

        /***********************************
         * 获取和请求参数相关信息, 注意要求在返回数据前,获取参数
         ***********************************/
        //1. 获取表单的数据[单个数据]
        //username=tom&pwd=123&hobby=lyl&hobby=lzq
        String username = request.getParameter("username");
        String pwd = request.getParameter("pwd");

        //2. 获取表单的一组数据
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println("username= " + username);
        System.out.println("pwd= " + pwd);
        //增强 for 循环的快捷键 iter->回车即可 , 能使用快捷键,就使用快捷键
        for (String hobby : hobbies) {
            System.out.println("hobby= " + hobby);
        }


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //合并
        doPost(request, response);
    }
}

8.4 注意事项和细节

  1. 获 取 doPost 参 数 中 文 乱 码 解 决 方 案 , 注 意 setCharacterEncoding(“utf-8”) 要 写 在request.getParameter()前

  2. 注意:如果通过 PrintWriter writer, 有返回数据给浏览器,建议将获取参数代码写在writer.print() 之前,否则可能获取不到参数值(doPost)

  3. 处理 http 响应数据中文乱码问题

  4. 再次理解 Http 协议响应 Content-Type 的含义, 比如 text/plain application/x-tar**

image-20231031202754895

8.5 请求转发[重要]

8.5.1 为什么需要请求转发
  1. 目前我们学习的都是一次请求,对应一个 Servlet,如图

image-20231101091756835

  1. 但是在实际开发中,往往业务比较复杂,需要在一次请求中,使用到多个 Servlet 完成一个任务(Servlet 链, 流水作业) 如图:

image-20231101091823166

8.5.2 请求转发声明
  1. 实现请求转发:请求转发指一个 web 资源收到客户端请求后,通知服务器去调用另外一个 web 资源进行处理
  2. HttpServletRequest 对象(也叫 Request 对象)提供了一个 getRequestDispatcher 方法,该方法返回一个 RequestDispatcher 对象,调用这个对象的 forward 方法可以实现请求转发
  3. request 对象同时也是一个域对象,开发人员通过 request 对象在实现转发时,把数据通过 request 对象带给其它 web 资源处理
  • setAttribute方法
  • getAttribute方法
  • removeAttribute方法
  • getAttributeNames方法
8.5.3 实现请求转发原理图

请求转发原理示意图

image-20231101092006717

8.5.4 请求转发注意事项和细节
  1. 浏览器地址不会变化(地址会保留在第 1 个 servlet 的 url)
  2. 同一次 HTTP 请求中,进行多次转发仍然是一次 HTTP 请求
  3. 同一次 HTTP 请求中,进行多次转发多个 Servlet 可以共享 request 域/对象的数据(因为始终是同一个 request 对象)
  4. 可以转发到 WEB-INF 目录下(后面做项目使用)
  5. 不能访问当前 WEB 工程外的资源
  6. 因为浏览器地址栏会停止在第一个 servlet ,如果你刷新页面,会再次发出请求(并且会带数据), 所以在支付页面情况下,不要使用请求转发,否则会造成重复支付[演示]

9. HttpServletResponse

9.1 HttpServletResponse介绍

  1. 每次 HTTP 请求,Tomcat 会创建一个 HttpServletResponse 对象传递给 Servlet 程序去使用。

  2. HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,如果需要设置返回给客户端的信息,通过 HttpServletResponse 对象来进行设置即可

image-20231101112023126

9.2 HttpServletResponse 类图

image-20231101112039703

9.3 向客户端返回数据方法

image-20231101112113532

  1. 字节流 getOutputStream(); 常用于下载(处理二进制数据)
  2. 字符流 getWriter(); 常用于回传字符串
  3. (细节:)两个流同时只能使用一个。 使用了字节流,就不能再使用字符流,反之亦然,否则就会报错

9.4 请求重定向[重要]

9.4.1 请求重定向原理示意图
  1. 请求重定向指:一个 web 资源收到客户端请求后,通知客户端去访问另外一个 web资源,这称之为请求重定向

  2. 请求重定向原理示意图

image-20231101112318229

相关代码路径:D:\IDEA_code\xjz_javaweb\servlet\src\com\xjz\servlet\response\DownServlet.java

D:\IDEA_code\xjz_javaweb\servlet\src\com\xjz\servlet\response\DownServletNew.java

9.4.2 请求重定向注意事项和细节
  1. 最佳应用场景:网站迁移,比如原域名是 www.baidu.com 迁移到 www.baidu.cn ,但是百度抓取的还是原来网址.
  2. 浏览器地址会发生变化,本质是两次 http 请求.
  3. 不能共享 Request 域中的数据,本质是两次 http 请求,会生成两个 HttpServletRequest对象
  4. 不能重定向到 /WEB-INF 下的资源
  5. 可以重定向到 Web 工程以外的资源, 比如 到 www.baidu.com 【在前面的案例演示】
  6. 重定向有两种方式, 推荐使用第 1 种.
response.sendRedirect("/servlet/downServletNew");

//第二种重定向的写法
response.setStatus(302);//设置 http响应的状态码
//设置http响应的 Location: /servlet/downServletNew
response.setHeader("Location","/servlet/downServletNew");
  1. 动态获取到 application context
//5. 动态获取到 application context
String contextPath = getServletContext().getContextPath();
System.out.println("contextPath=" + contextPath);//servlet
//response.sendRedirect("/servlet/downServletNew");
response.sendRedirect(contextPath + "/downServletNew");

三、WEB开发通信协议-HTTP 协议

1. HTTP请求包分析(GET)

image-20231031100515211

2. HTTP请求包分析(POST)

image-20231031101729411

3. GET 请求和 POST请求分别有哪些?

image-20231031102502107

4. HTTP 请求中怎么选择 GET 和 POST 方式

image-20231031103432547

image-20231031103552321

image-20231031103705581

image-20231031104118237

5. HTTP响应包分析

  • HTTP响应包括3个部分

    1. 响应行
    2. 响应头
    3. 响应体
  • HTTP响应包分析图

image-20231031105231248

6. 状态码

6.1 状态码 301

image-20231031111204817

image-20231031111147111

6.2 状态码 304

image-20231031111046057

7. MIME 类型

7.1 MIME 介绍

image-20231031111402343

7.2 常见的 MIME 类型

image-20231031111604737

8. HTTP 作业

image-20231031160144923

四、WEB 工程路径专题

  • 先看一个问题 => 怎么解决访问资源的问题

image-20231103103736746

  • 工程路径解决方案
  1. 说明: 使用相对路径来解决, 一个非常重要的规则:页面所有的相对路径,在默认情况下,都会参考当前浏览器地址栏的路径 http://ip:port/工程名/ + 资源来进行跳转。所以我们可以直接这样写

image-20231103103825131

  1. 相对路径带来的问题举例 => 示意图

image-20231103103911373

  1. 如果需要指定页面相对路径参考的的路径,可以使用 base 标签来指定

1. 解决方案: base 标签

1.1 base 基本介绍

  1. base 标签是 HTML 语言中的基准网址标记,它是一个单标签,位于网页头部文件的 head标签内
  2. 一个页面最多只能使用一个 base 元素,用来提供一个指定的默认目标,是一种表达路径和连接网址的标记。
  3. 常见的 url 路径形式分别有相对路径与绝对路径,如果 base 标签指定了目标,浏览器将通过这个目标来解析当前文档中的所有相对路径,包括的标签有(a、img、link、form)
  4. 也就是说,浏览器解析时会在路径前加上 base 给的目标,而页面中的相对路径也都转换成了绝对路径。使用了 base 标签就应带上 href 属性和 target 属性

1.2 应用实例

D:\IDEA_code\xjz_javaweb\webpath\src\com\xjz\servlet

1.3 WEB工程路径注意事项和细节

  1. Web 工程的相对路径和绝对路径

image-20231103142227056

  1. 在实际开发中,路径都使用绝对路径,而不是相对路径
  2. 在 web 中 / 斜杠 如果被浏览器解析,得到的地址是:http://ip[域名]:port/ 比如: <ahref=“/”>斜杠
  3. 在 web 中 / 斜杠 如果被服务器解析,得到的地址是:http://ip[域名]:port/工程路径/,你也可以理解成 /工程路径/ 下面的几种情况就是如此:

image-20231103142334641

  1. 在 javaWeb 中 路径最后带 / 和 不带 / 含义不同, 一定要小心,
    比如 网址 : servlet03 表示资源

网址 : servlet03 表示路径

  1. 特别说明:重定向 response.sendRediect(“/”); 这条语句虽然是在服务器执行的,但是,服务器是把斜杠 / 发送给浏览器解析。因此得到地址 http://ip[域名]:port/

小结: 在编写资源路径时: , 考虑这么几点
(1) 这个路径 前面有没有 /
(2) 这个路径 在哪里被解析 [服务器还是浏览器] , 如果前面有 / , 并且是在 浏览器被解析的 被解析成 http://ip:port/ , 如果在服务器端被解析 , 被解析成 /工程路径/
(3) 如果这个路径,前面没有 / , 并且在浏览器被解析,则以浏览器当前的地址栏 去掉资源部分,作为一个相对路径.

(4) 这个路径,最后有没有 / , 如果最后有/ 表示路径, 如果没有 / 表示资源

五、Web 开发会话技术 -Cookie&Session

1. 会话

1.1 基本介绍

  1. 会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个 web 资源,然后关闭浏览器,整个过程称之为一个会话。

  2. 会话过程中要解决的一些问题?

  1. 每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,服务器要想办法为每个用户保存这些数据
  2. 例如:多个用户点击超链接通过一个 servlet 各自购买了一个商品,服务器应该想办法把每一个用户购买的商品保存在各自的地方,以便于这些用户点结帐 servlet 时,结帐servlet 可以得到用户各自购买的商品为用户结帐。

1.2 会话的两种技术

Cookie(小甜饼)是客户端技术,服务器把每个用户的数据以 cookie 的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的 web 资源时,就会带着各自的数据去。这样,web 资源处理的就是用户各自的数据了。【简单示意图】

image-20231103152046152

2. cookie 介绍

  1. Cookie 是服务器在客户端保存用户的信息,比如登录名,浏览历史等, 就可以以 cookie方式保存.
  2. Cookie 信息就像是小甜饼(cookie 中文)一样,数据量并不大,服务器端在需要的时候可以从客户端/浏览器读取(http 协议),可以通过图来理解

image-20231103152300148

image-20231103152325913

演示 Cookie 底层实现机制**,** 创建和读取 Cookie

D:\IDEA_code\xjz_javaweb\cookie-session\src\com\xjz\cookie\CreateCookie.java

image-20231103155504035

3. Cookie 生命周期

  1. Cookie 的生命周期指的是如何管理 Cookie 什么时候被销毁(删除)

  2. setMaxAge()

● 正数,表示在指定的秒数后过期
● 负数,表示浏览器关闭,Cookie 就会被删除(默认值是-1)
● 0,表示马上删除 Cookie

4 . Cookie 有效路径

  1. Cookie 有效路径 Path 的设置

  2. Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器。哪些不发。 path属性是通过请求的地址来进行有效的过滤

  3. 规则如下

5. Cookie注意事项和细节

  1. 一个 Cookie 只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
  2. 一个 WEB 站点可以给一个浏览器发送多个 Cookie,一个浏览器也可以存储多个 WEB 站点提供的 Cookie。
  3. cookie 的总数量没有限制,但是每个域名的 COOKIE 数量和每个 COOKIE 的大小是有限制的 (不同的浏览器限制不同, 知道即可) , Cookie 不适合存放数据量大的信息。
  4. 注意,删除 cookie 时,path 必须一致,否则不会删除
  5. Java servlet 中 cookie 中文乱码解决 [代码演示 EncoderCookie.java ReadCookie2.java]

说明:如果存放中文的 cookie, 默认报错, 可以通过 URL 编码和解码来解决, 不建议存放中文的 cookie 信息

package com.xjz.cookie;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class EncoderCookie extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("EncoderCookie 被调用...");
        //1. 创建 Cookie,有中文
        //代码解读
        //1) 如果直接存放中文的 cookie,报错 Control character in cookie value or attribute.
        //2)  解决办法,就是将中文 编码成 URL编码  英文: Encode=编码
        //3) 编码后,再保存即可
        String name = URLEncoder.encode("程序员老徐", "utf-8");

        Cookie cookie = new Cookie("name", name);

        //2. 保存到浏览器
        response.addCookie(cookie);

        //3. 给浏览器返回信息
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>设置中文cookie成功~</h1>");
        writer.flush();
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

解码

package com.xjz.cookie;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class ServletReadCookie2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        Cookie[] cookies = request.getCookies();
        //找到带有中文的 cookie
        Cookie name = CookieUtils.readCookieByName("name", cookies);
        //处理的中文乱码问题
        writer.println("Cookie[" + name.getName()
                + "=" +
                URLDecoder.decode(name.getValue(), "utf-8") + "] <br/>");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

6. Session 有什么用

  1. 不同的用户登录网站后,不管该用户浏览该网站的哪个页面,都可显示登录人的名字,还可以随时去查看自己的购物车中的商品, 是如何实现的?
  2. 也就是说,一个用户在浏览网站不同页面时,服务器是如何知道是张三在浏览这个页面,还是李四在浏览这个页面?

image-20231104122907291

● 解决之道—session 技术, 简单说

  1. Session 是服务器端技术,服务器在运行时为每一个用户的浏览器创建一个其独享的session 对象/集合
  2. 由于 session 为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自的 session 中读取/添加数据, 从而完成相应任务

7. Session 基本原理

7.1 Session 原理示意图

image-20231104123005077

image-20231104123010846

  1. 当用户打开浏览器,访问某个网站, 操作 session 时,服务器就会在内存(在服务端)为该浏览器分配一个 session 对象,该 session 对象被这个浏览器独占, 如图
  2. 这个 session 对象也可看做是一个容器/集合,session 对象默认存在时间为 30min(这是在tomcat/conf/web.xml),也可修改

image-20231104123115565

7.2 Session 可以做什么

  1. 网上商城中的购物车
  2. 保存登录用户的信息
  3. 将数据放入到 Session 中,供用户在访问不同页面时,实现跨页面访问数据
  4. 防止用户非法登录到某个页面

7.3 如何理解 Session

  1. session 存储结构示意图

image-20231104131135843

  1. 你可以把 session 看作是一容器类似 HashMap,有两列(K-V),每一行就是 session 的一个属性。
  2. 每个属性包含有两个部分,一个是该属性的名字(String),另外一个是它的值(Object)

8. session 常用方法

  1. 创建和获取 Session,API 一样HttpSession hs=request.getSession();第 1 次调用是创建 Session 会话, 之后调用是获取创建好的 Session 对象

  2. 向 session 添加属性
    hs.setAttribute(String name,Object val);

  3. 从 session 得到某个属性
    Object obj=hs.getAttribute(String name);

  4. 从 session 删除调某个属性:

hs.removeAttribute(String name);

  1. isNew(); 判断是不是刚创建出来的 Session

  2. 每个 Session 都有 1 个唯一标识 Id 值。通过 getId() 得到 Session 的会话 id 值

9. session 底层实现机制 *

9.1 原理分析图

  • session 底层实现机制图解(重要)

image-20231104140912216

image-20231104140933012

9.2 代码演示

创建Session

package com.xjz.session;

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

/**
 * @author xjz_2002
 * @version 1.0
 */
public class CreateSession extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        System.out.println("CreateSession 被调用..");

        //1. 获取session,同时也可以创建session
        HttpSession session = request.getSession();
        //2. 给session 获取id
        System.out.println("当前sessionId=" + session.getId());
        //3. 给session 存放数据
        session.setAttribute("key1", "value1");

        //4. 给浏览器发送一个回复
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>创建/操作 session成功~");
        writer.flush();
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
  • 运行结果

image-20231104143215598

image-20231104143301188

第二次刷新后

image-20231104143440409

  • 读session
package com.xjz.session;

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

/**
 * @author xjz_2002
 * @version 1.0
 */
public class ReadSession extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        System.out.println("ReadSession 被调用..");

        //演示读取 session
        //1. 获取session,如果没有session,也会创建
        HttpSession session = request.getSession();
        //2. 读取属性
        Object key1 = session.getAttribute("key1");
        if (key1 != null){
            System.out.println("session属性 key1=" + (String) key1);
        } else {
            System.out.println("session中没有 key1属性 ");
        }
        //给浏览器回复一下
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>读取session成功~</h1>");
        writer.flush();
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

我们可以看出,两个servlet的JSEESIONID是同一JSESSIONID

image-20231104144308695

image-20231104144340653

有了代码支撑,我们在回头看 Session 的原理图,就有更深刻的理解

1.7.3 Session 实现原理动画

  • 服务器是如何实现一个 session 为一个用户浏览器服务的

image-20231104144544113

10. Session 生命周期

10.1 session 生命周期-说明

  1. public void setMaxInactiveInterval(int interval) 设置 Session 的超时时间(以秒为单位),超过指定的时长,Session 就会被销毁。
  2. 值为正数的时候,设定 Session 的超时时长。
  3. 负数表示永不超时
  4. public int getMaxInactiveInterval()获取 Session 的超时时间
  5. public void invalidate() 让当前 Session 会话立即无效
  6. 如果没有调用 setMaxInactiveInterval() 来指定 Session 的生命时长,Tomcat 会以 Session默认时长为准,Session 默认的超时为 30 分钟, 可以在 tomcat 的 web.xml 设置

image-20231104160447765

  1. Session 的生命周期指的是 :客户端/浏览器两次请求最大间隔时长,而不是累积时长。即当客户端访问了自己的 session,session 的生命周期将从 0 开始重新计算。(代码解读: 指的是同一个会话两次请求之间的间隔时间)
  2. 底层: Tomcat 用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,则将该会话销毁

10.2 Session 生命周期-应用实例

  • 需求:代码演示说明 Session 的生命周期
  1. 创建
package com.xjz.session;

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

/**
 * @author xjz_2002
 * @version 1.0
 */
public class CreateSession2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CreateSession2 被调用..");

        //1. 创建 session
        HttpSession session = request.getSession();
        System.out.println("CreateSession2 sid= " + session.getId());

        //2. 设置生命周期为 60s
        session.setMaxInactiveInterval(60);
        session.setAttribute("u","jack");

        //3. 回复一下浏览器
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>创建session成功,设置生命周期 60s</h1>");
        writer.flush();
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
  1. 读 Session
package com.xjz.session;

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

/**
 * @author xjz_2002
 * @version 1.0
 */
public class ReadSession2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("ReadSession2 被调用..");

        //1.获取到session
        HttpSession session = request.getSession();
        System.out.println("ReadSession2 sid= " + session.getId());

        //2. 读取session的属性
        Object u = session.getAttribute("u");
        if (u != null){
            System.out.println("获取到session属性 u=" + (String) u);
        } else {
            System.out.println("读取不到session属性 u 说明原来的session被销毁");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

image-20231104161044125

  • 删除session 使用 invalidate() 方法
package com.xjz.session;

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

/**
 * @author xjz_2002
 * @version 1.0
 */
public class DeleteSession extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("DeleteSession 被调用..");

        //1. 演示如何删除session
        HttpSession session = request.getSession();
        session.invalidate();

        //2. 如果我们要删除的是 session的某个属性
        //session.removeAttribute("xxx");

        //3. 回复一下浏览器
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>删除session成功</h1>");
        writer.flush();
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

image-20231104161938398

总结:Session 的生命周期

  1. 指的是两次访问 session 的最大间隔时间
  2. 如果你在 session 没有过期的情况下(默认30分钟),操作 session, 则会重新开始计算生命周期
  3. session 是否过期,是由服务器来维护和管理
  4. 如我们调用了 invaliate() 会直接将该 session 删除/销毁
  5. 如果希望删除 session 对象的某个属性, 使用 removeAttribute(“xx”)

11. Session 经典案例-防止非法进入管理页面

11.1 作业布置

  1. 需求说明:完成防止用户登录管理页面应用案例(如图)

image-20231104175541725

说明:

  1. 只要密码为 666666, 我们认为就是登录成功
  2. 用户名不限制
  3. 如果验证成功,则进入管理页面 ManageServelt.java ,否则进入 error.html
  4. 如果用户直接访问 ManageServet.java , 重定向到到 login.html

11.2 作业代码

D:\IDEA_code\xjz_javaweb\cookie-session\src\com\xjz\session\homework

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/cs/loginCheckServlet" method="post">
    用户名:<input type="text" name="username"><br/>
    密 码:<input type="password" name="pwd"><br/>
    <input type="submit" value="登录"/>
</form>
</body>
</html>

error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录失败</title>

    <base href="/cs/">
</head>
<body>
<h1>登录失败</h1>
<a href="login.html">点击返回重新登录</a>
<!-- 如果没有bese标签,可以用如下返回,带/ 为绝对路径,
     我们一般使用绝对路径,不带 / 为相对路径,不安全 !-->
<!--<a href="/login.html">点击返回重新登录</a>-->
</body>
</html>

LoginCheckServlet.java

package com.xjz.session.homework;

import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class LoginCheckServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //System.out.println("LoginCheckServlet 被调用..");

        //1. 获取提交表单的用户名和密码
        String username = request.getParameter("username");
        String pwd = request.getParameter("pwd");

//        //2. 将用户名 存放到 cookie中,并响应给浏览器   ==> Cookie方法
//        Cookie cookie = new Cookie("username",username);
//        response.addCookie(cookie);

        //3. 只要密码为 66666,我们认为就是登录成功,用户名不限制
        if (pwd != null && pwd.length() != 0) {
            if ("666666".equals(pwd)) {
                //2. 将用户名 存放到 session 中,并响应给浏览器   ==> Session方法 (生命周期默认30min)
                //把用户名保存到 session
                HttpSession session = request.getSession();
                session.setAttribute("loginuser",username);
                //超时1s 即销毁,否则在超时时间内,直接访问manageServlet2 可直接查看 管理员
                session.setMaxInactiveInterval(1);

                System.out.println("验证成功~");
                //请求转发
                //注意:请求转发 是在服务端请求的,默认路径是 http://localhost:8080/工程路径
                //     所以不需要带 /工程路径, 如果带了,访问地址为http://localhost:8080/cs/cs/login.html
                //     请求转发 不能访问 web以外的资源,如果是访问 servlet,则需要使用重定向!!
//                request.getRequestDispatcher("/manageServlet.html").forward(request, response);
                // session 方法
                request.getRequestDispatcher("/manageServlet2").forward(request, response);
            } else {
                //验证失败,密码不是666666,请求转发到 error.html
                System.out.println("验证失败");
                request.getRequestDispatcher("/error.html").forward(request, response);
            }
        } else {
            // 回复给浏览器
            response.setContentType("text/html;charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.println("<h1>密码不能为 null,请重新输入</h1>");
            writer.flush();
            writer.close();
        }

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

**ManageServlet.java **

使用 Cookie方法,用户直接访问 ManageServlet.java , 重定向到到 login.html

package com.xjz.session.homework;

import com.xjz.cookie.CookieUtils;

import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author xjz_2002
 * @version 1.0
 * 使用 Cookie方法,用户直接访问 ManageServlet.java , 重定向到到 login.html
 */
public class ManageServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        System.out.println("ManageServlet 被调用..");

        //获取referer,即从哪个网址请求过来的 url
        String referer = request.getHeader("Referer");
        System.out.println("referer=" + referer);
        //判断打过来的请求 url是否是 login.html,如果不是,重定向到login
        if ("http://localhost:8080/cs/login.html".equals(referer)) {
            //获取提交表单的 username
            Cookie[] cookies = request.getCookies();
            //读取key为 username 的 cookie
            Cookie usernameCookie = CookieUtils.readCookieByName("username", cookies);
            //获取该 cookie 的 value值
            String usernameVal = usernameCookie.getValue();
            System.out.println("usernameCookie= " + usernameVal);//xjz_2002
            // 给浏览器返回消息
            response.setContentType("text/html;charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.println("<h1>恭喜你,管理员:" + usernameVal + "</h1>");
            writer.flush();
            writer.close();
        } else {
            //如果用户直接访问 /manageServlet,重定向到 login.html
            //注意:请求重定向是 response响应到服务器的, 所以路径前必须加 /工程路径
            //String contextPath = request.getContextPath();// 工程路径 => /cs
            response.sendRedirect(request.getContextPath() + "/login.html");
        }

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

ManageServlet2.java

将用户名 存放到 cookie中,并响应给浏览器 ==> Session方法 (生命周期默认30min)

package com.xjz.session.homework;

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

/**
 * @author xjz_2002
 * @version 1.0
 * 将用户名 存放到 session中,并响应给浏览器   ==> Session方法 (生命周期默认30min)
 */
public class ManageServlet2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //判断该用户是否登录过
        HttpSession session = request.getSession();
        Object userlogin = session.getAttribute("loginuser");
        System.out.println("userlogin= " + userlogin);
        if (userlogin == null) { //说明该用户没有登录
            //重新登录 -> 请求重定向
//            response.sendRedirect("/cs/login.html");
            response.sendRedirect(request.getContextPath() + "/login.html");
            return;
        }

        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>恭喜你,管理员:" + userlogin.toString() + "</h1>");
        writer.flush();
        writer.close();

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

六、JavaWeb三大组件之监听器 Listener

1. Listener 监听器介绍

  1. Listener 监听器它是 JavaWeb 的三大组件之一。JavaWeb 的三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器

  2. Listener 是 JavaEE 的规范,就是接口

  3. 监听器的作用是,监听某种变化(一般就是对象创建/销毁, 属性变化), 触发对应方法完成相应的任务

  4. JavaWeb 中的监听器(共八个), 目前最常用的是ServletContextListener

2. JavaWeb 的监听器

2.1 ServletContextListener 监听器

  1. 作用:监听 ServletContext 创建或销毁(当我们 Web 应用启动时,就会创建 ServletContext),即生命周期监听,应用场景(1)加载初始化的配置文件;比如 spring 的配置文件 (2)任务调度(配合定时器 Timer/TimerTask)

  2. 相关方法

image-20231107111416139

  1. 配置 web.xml

image-20231107111511843

2.2 ServletContextAttributeListener 监听器

  1. 作用:监听 ServletContext 属性变化

  2. 相关方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3 其他监听器-使用较少

2.3.1 HttpSessionListener 监听器

1. 作用:监听 Session 创建或销毁,即生命周期监听

2. 相关方法

image-20231107155919741

  1. 使用方法和前面一样, 可以用于监控用户上线,离线
2.3.2 HttpSessionAttributeListener 监听器
  1. 作用:监听 Session 属性的变化
  2. 相关方法

image-20231107160049663

image-20231107160055551

  1. 使用少 , 使用方法和前面一样。
2.3.3 ServletRequestListener 监听器

1. ServletRequestListener 监听器

2. 作用:监听 Request 创建或销毁,即 Request 生命周期监听

相关方法

image-20231107160125232

  1. 可以用来监控, 某个 IP 访问我们网站的频率, 日志记录 ,访问资源的情况.
2.3.4 ServletRequestAttributeListener 监听器

1. 作用:监听 Request 属性变化

2. 相关方法

image-20231107160152805

image-20231107160159961

  1. 使用方法和前面类似
2.3.5 HttpSessionBindingListener 感知监听器
2.3.6 HttpSessionActivationListener 感知监听器

七、JavaWeb 三大组件之 过滤器 Filter

1. Filter 过滤器说明

image-20231107172917453

  • 过滤器介绍

**1. Filter 过滤器它是 JavaWeb 的三大组件之一(Servlet 程序、Listener 监听器、Filter 过滤器)

  1. Filter 过滤器是 JavaEE 的规范,是接口

image-20231107173012940

  1. Filter 过滤器它的作用是:拦截请求,过滤响应。
  2. 应用场景
  • 权限检查
  • 日记操作
  • 事务管理

2. Filter 过滤器基本原理

image-20231107173102642

3. Filter 应用案例

D:\IDEA_code\xjz_javaweb\filter

4. Filter 过滤器 url-pattern

1、url-pattern : Filter 的拦截路径, 即浏览器在请求什么位置的资源时,过滤器会进行拦截过滤
2.、精确匹配 /a.jsp 对应的 请求地址 http://ip[域名]:port/工程路径/a.jsp 会拦截
3、目录匹配 /manage/*对应的 请求地址http://ip[域名]:port/工程路径/manage/xx , 即 web 工程 manage 目录下所有资源 会拦截

4、后缀名匹配 *.jsp 后缀名可变,比如 *.action *.do 等等对应的 请求地址 http://ip[域名]:port/工程路径/xx.jsp , 后缀名为 .jsp 请求会拦截
5、Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在

5. Filter 过滤器生命周期

  • Filter 过滤器生命周期 图解

image-20231107193710685

6. FilterConfig

  • FilterConfig 接口图

image-20231107193801088

  • FilterConfig 说明
  1. FilterConfig 是 Filter 过滤器的配置类
  2. Tomcat 每次创建 Filter 的时候,也会创建一个 FilterConfig 对象,这里包含了 Filter 配置文件的配置信息。
  3. FilterConfig 对象作用是获取 filter 过滤器的配置内容
  • 应用实例

D:\IDEA_code\xjz_javaweb\filter\src\com\xjz\filter\XjzFilterConfig.java

7. FilterChain 过滤器链

  • FilterChain 简介

一句话: FilterChain: 在处理某些复杂业务时,一个过滤器不够,可以设计多个过滤器共同完成过滤任务,形成过滤器链。

  • 基本原理试示意图

image-20231107194837399

  • 应用实例

D:\IDEA_code\xjz_javaweb\filter\src\com\xjz\filter\AFilter.java/BFilter.java

  • 运行结果

image-20231108114655458

  • FilterChain 注意事项和细节
  1. 多个 filter 和目标资源在一次 http 请求,在同一个线程中

  2. 当一个请求 url 和 filter 的 url-pattern 匹配时, 才会被执行, 如果有多个匹配上,就会顺序执行,形成一个 filter 调用链(底层可以使用一个数据结构搞定)

  3. 多个 filter 共同执行时,因为是一次 http 请求, 使用同一个 request 对象

  4. 多个 filter 执行顺序,和 web.xml 配置顺序保持一致.

  5. chain.doFilter(req, resp)方法 将执行下一个过滤器的 doFilter 方法, 如果后面没有过滤器,则执行目标资源。

  6. 小结:注意执行过滤器链时, 顺序是(用前面的案例分析) Http请求 -> A 过滤器 dofilter() -> A 过滤器前置代码 -> A 过滤器 chain.doFilter() -> B 过滤器 dofilter() -> B 过滤器前置代码 -> B过滤器 chain.doFilter() -> 目标文件 -> B过滤器后置代码 -> A过滤器后置代码 -> 返回给浏览器页面/数据

八、数据交换和异步请求 - JSON & Ajax

1. JSON 介绍

  1. JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)

  2. JSON 是轻量级的文本数据交换格式

  3. JSON 独立于语言 [老韩解读:即 java 、php、asp.net , go 等都可以使用 JSON]

  4. JSON 具有自我描述性,更易理解, 一句话,非常的好用…

2. JSON 规则

  1. 映射(元素/属性)用冒号 : 表示,“名称”:值 , 注意名称是字符串,因此要用双引号引起来
  2. 并列的数据之间用逗号 , 分隔。“名称 1”:值,“名称 2”:值
  3. 映射的集合(对象)用大括号 {} 表示。{“名称 1”:值,“名称 2”:值}
  4. 并列数据的集合(数组)用方括号 [] 表示。 [{“名称 1”:值,“名称 2”:值}, {“名称 1”:值," 名称 2":值}]
  5. 元素值类型:string, number, object, array, true, false, null

3. JSON 在 java 中使用

1. 说明

  1. java 中使用 json,需要引入到第 3 方的包 gson.jar

  2. Gson 是 Google 提供的用来在 Java 对象和 JSON 数据之间进行映射的 Java 类库。

  3. 可以对 JSON 字符串 和 Java 对象相互转换

2. JSON 在 java中 应用场景

  1. Javabean 对象和 json 字符串 的转换
  2. List 对象和 json 字符串 的转换
  3. map 对象和 json 字符串 的转换
  4. 应用场景示意图

image-20231110190530434

3. 应用实例 JSON 在 java中应用场景

JavaJson.java

package com.xjz.json;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class JavaJson {

    //代码解读
    //1. 要把复杂的 json 字符串转换成为 java 对象。需要继承 TypeToken 类
    //2. TypeToken 是一个自定义泛型类,在创建时,需要指定具体类型,这里我们指定为 List<Book>
    // ,如果同学们忘记了,回去看 java 基础的泛型知识点
    //3. TypeToken 是由 gson 包提供的
    static class BookType extends TypeToken<List<Book>> {
    }

    public static void main(String[] args) {

        // new 一个 gson 对象。引入 gson 包
        Gson gson = new Gson();

        // java 对象和 json 的转换
        System.out.println("\n==== 1. java 对象 和 json 的转换 ====");
        Book book = new Book(100, "我爱学Java");

        //1. 演示把 javabean -> json字符串
        String strBook = gson.toJson(book);
        System.out.println("strBook= " + strBook);
        //2. json字符串 -> javabean
        //代码解读
        //(1) strBook 就是 json字符串
        //(2) Book.class 指定将 json字符串转成 Book对象
        //(3) 底层是反射机制
        Book book2 = gson.fromJson(strBook, Book.class);
        System.out.println("book2= " + book2);

        //2. List 集合 和 json 的转换
        System.out.println("\n==== 2. List 集合 和 json 的转换 ====");
        List<Book> bookList = new ArrayList<>();
        bookList.add(new Book(200, "男人帮"));
        bookList.add(new Book(300, "女人帮"));
        // 将 list 转成 json对象
        String bookListStr = gson.toJson(bookList);
        System.out.println("bookListStr= " + bookListStr);

        //将 json 字符串 转成 List 集合方式 1
        Type type = new BookType().getType();
        System.out.println("type= " + type); // java.util.List<com.xjz.json.Book>
        List<Book> bookList2 = gson.fromJson(bookListStr, type);
        System.out.println("bookList2= " + bookList2);

        //将 json 字符串 转成 List 集合方式 2
        //代码解读
        //(1) 如果我们 new TypeToken<List<Book>>() 提示
        //  'TypeToken()' has protected access in 'com.google.gson.reflect.TypeToken'
        //(2) 因为 TypeToken 的无参构造器是 protected , 而 new TypeToken<List<Book>>() 就是调用其无参构造器
        //(3) 根据java基础,如果一个方法是 protected,而且不在同一个包中,是不能直接访问的,因此报错
        //(4) 为什么 new TypeToken<List<Book>>(){} 使用就可以,这里就涉及到 匿名内部类的知识点.
        //(5) 当 new TypeToken<List<Book>>(){} 其实这个类型不是 TypeToken,而是一个 匿名内部类(可以理解为TypeToken的子类)
        //(6) 而且这个匿名内部类是有自己的无参构造器(隐式),根据java基础规则:当执行子类的无参构造器时,默认super()
        //Type type = new TypeToken<List<Book>>(){}.getType(); // java.util.List<com.xjz.json.Book>

        List<Book> bookList3 = gson.fromJson(bookListStr, new TypeToken<List<Book>>() {}.getType());
        System.out.println("bookList3= " + bookList3);

        //3.  map 集合 -> json 字符串
        Map<String, Book> bookMap = new HashMap<>();
        bookMap.put("k1",new Book(10,"三国演义"));
        bookMap.put("k2",new Book(20,"水浒传"));

        // 把 map 集合 -> json 字符串
        String strBookMap = gson.toJson(bookMap);
        System.out.println("strBookMap= " + strBookMap + "类型 = "+strBookMap.getClass());

        // 把 json 字符串 -> map 集合
        // new TypeToken<Map<String, Book>>() {}.getType() => java.util.Map<com.xjz.json.Book>
        Map<String, Book> bookMap2 = gson.fromJson(strBookMap,
                new TypeToken<Map<String, Book>>() {
                }.getType());
        System.out.println("bookMap2= " + bookMap2);
        
    }
}

九、Ajax 基本介绍

1. Ajax 是什么

  1. AJAX 即"Asynchronous Javascript And XML"(异步 JavaScript 和 XML)
  2. Ajax 是一种浏览器异步发起请求(指定发哪些数据),局部更新页面的技术

2. Ajax 经典应用场景

  1. 搜索引擎根据用户输入关键字,自动提示检索关键字
  2. 动态加载数据,按需取得数据【树形菜单、联动菜单…】
  3. 改善用户体验。【输入内容前提示、带进度条文件上传…】
  4. 电子商务应用。 【购物车、邮件订阅…】
  5. 访问第三方服务。【访问搜索服务、rss 阅读器】
  6. 页面局部刷新, https://piaofang.maoyan.com/dashboard

3. Ajax 原理示意图

  • 传统的WEB应用

image-20231111160818070

  • Ajax 原理示意图

image-20231111160934359

4. JavaScript 原生 Ajax 请求

在线文档:https://www.w3school.com.cn/js/js_ajax_intro.asp

  • 应用实例-验证用户名是否存在

演示 javascript 发送原生 ajax 请求的案例

  1. 在输入框输入用户名

  2. 点击验证用户名, 使用 ajax 方式, 服务端验证该用户名是否已经占用了, 如果该用户
    已经占用, 以 json 格式返回该用户信息

  3. 假定用户名为 king , 就不可用, 其它用户名可以=》 后面我们接入 DB[Mysql+JDBC]

  4. 对页面进行局部刷新, 显示返回信息

  5. 小思考: 为什么直接返回用户名是否可用信息, 完成案例后, 再思考?

image-20231111170858606

image-20231111170914202

十、线程数据共享和安全 ThreadLocal

1. 什么是 ThreadLocal

  1. ThreadLocal 的作用,可以实现在同一个线程数据共享, 从而解决多线程数据安全问题.
  2. ThreadLocal 可以给当前线程关联一个数据(普通变量、对象、数组)set 方法 [源码!]
  3. ThreadLocal 可以像 Map 一样存取数据,key 为当前线程, get 方法
  4. 每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个 ThreadLocal 对象实例
  5. 每个 ThreadLocal 对象实例定义的时候,一般为 static 类型
  6. ThreadLocal 中保存数据,在线程销毁后,会自动释放

image-20231112181826158

2. 快速人门 ThreadLocal

ThreadLocalTest.java

package com.xjz.threadlocal;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class ThreadLocalTest {

    public static ThreadLocal<Object> threadLocal1 = new ThreadLocal<>();
    public static ThreadLocal<Object> threadLocal2 = new ThreadLocal<>();


    public static class Task implements Runnable{

        @Override
        public void run() {
            Dog dog = new Dog();
            Pig pig = new Pig();
            /**
             * ===== set源码分析 只要明白这个机制,后面的 set get 全部通透=======
             *
             * public void set(T value) {
             *          //获取当前线程
             *         Thread t = Thread.currentThread();
             *         //获取当前线程的 ThreadLocal.ThreadLocalMap 属性 threadLocals,
             *         //  ,类型是 ThreadLocal 的静态内部类
             *         //threadLocals 有一个属性 Entry[],类型 }ThreadLocal.ThreadLocalMap.Entry
             *         // k-> ThreadLocal 对象  v -> 值
             *         ThreadLocalMap map = getMap(t);
             *         if (map != null)
             *             map.set(this, value); //存放这里的 this 就是 ThreadLocal1,可以 debug源码,一目了然
             *         else
             *             createMap(t, value); //创建
             *     }
             *
             *     =======  getMap 方法源码======
             *     ThreadLocalMap getMap(Thread t) { //获取当前线程的 ThreadLocal.ThreadLocalMap
             *         return t.threadLocals;
             *     }
             *
             *     说明:
             *     1. ThreadLocalMap 对象对象是和当前 Thread对象的绑定属性
             *     2. ThreadLocalMap 对象含有 Entry[] table; 这个 Entry(K,V)
             *     3. 这个 key 就是 ThreadLocal 对象, V 就是你要在放入的对象,比如 dog
             *     4. 当执行了 了 threadLocal.set(dog) 后,内存布局图为 wps[看图]
             *
             */
            threadLocal1.set(dog);
            threadLocal2.set(pig);// 会替换 dog
            //如果希望在同一个线程共享多个对象/数据,就只能再创建一个 ThreadLocal 对象
            //threadLocal2.set(pig);
            System.out.println("在 run方法中 线程 name=" + Thread.currentThread().getName()
                    + " 放入 ThreadLocal 的数据= " +  dog );
            new T1Service().update();
        }
    }
    public static void main(String[] args) {

        for (int i = 0; i < 1; i++) {
            new Thread(new Task()).start();//启动一个新的线程,注意不是主线程
        }
        System.out.println("在 main 方法中 ThreadLocal 的数据=" + threadLocal1.get());

    }
}

T1Service.java

package com.xjz.threadlocal;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class T1Service {
    public void update(){
        String name = Thread.currentThread().getName();
        /**
         * ====== ThreadLocalTest.threadLocal.get() 源码====
         *  public T get() {
         *         Thread t = Thread.currentThread();
         *         ThreadLocalMap map = getMap(t);
         *         if (map != null) {
         *             ThreadLocalMap.Entry e = map.getEntry(this);
         *             if (e != null) {
         *                 @SuppressWarnings("unchecked")
         *                 T result = (T)e.value;
         *                 return result;
         *             }
         *         }
         *         return setInitialValue();
         *     }
         *
         *     代码解读
         *     1. 先得到当前线程对象
         *     2. 获取当前对象绑定的 ThreadLocalMap 对象
         *     3. 根据 threadLocal对象(key)获取 ThreadLocalMap 对象的 Entry数组的 Entry对象 [hash]
         *     4. 取出 Entry对象的 value 就是放入到 ThreadLocal对象的数据 dog
         *
         */
        System.out.println("在 T1Service 的 update() 线程 name=" +
                name + "threadLocal 的数据= " + ThreadLocalTest.threadLocal1.get());
        System.out.println("在 T1Service 的 update() 线程 name=" +
                name + "threadLocal 的数据= " + ThreadLocalTest.threadLocal2.get());
        new T2DAO().update();
    }
}

T2DAO.java

package com.xjz.threadlocal;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class T2DAO {

    public void update(){
        String name = Thread.currentThread().getName();
        System.out.println("在 T2DAO 的 update() 线程是=" + name
            + "threadlocal 数据是=" + ThreadLocalTest.threadLocal1.get());
        System.out.println("在 T2DAO 的 update() 线程是=" + name
                + "threadlocal 数据是=" + ThreadLocalTest.threadLocal2.get());
    }

}

6. 完成测试, 检测 ThreadLocal 可以实现在同一个线程数据安全共享

image-20231112212321404

3. ThreadLocal 源码解读+画图

  1. ThreadLocal 原理分析图(重点 set 和 get)

  1. Debug 源码图,非常重要

image-20231112212645317

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/158576.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux 查看命令使用说明

查看命令的使用说明的命令有三种&#xff0c;但并不是每个命令都可以使用这三种命令去查看某个命令的使用说明&#xff0c;如果一种不行就使用另外一种试一试。 1.whatis 命令 概括命令的作用 2.命令 --help 命令的使用格式和选项的作用 3.man 命令 命令的作用和选项的详细…

基于Python3的scapy解析SSL报文

scapy对于SSL的支持个人觉得不太好&#xff0c;至少在构造报文方面没有HTTP或者DNS这种常见的报文有效方便&#xff0c;但是scapy对于SSL的解析还是可以的。下面我们以一个典型的HTTPS的报文为例&#xff0c;展示scapy解析SSL报文。 一&#xff1a;解析ClientHello报文 from sc…

Redis对象的数据结构及其原理汇总

本文首发于公众号&#xff1a;Hunter后端 原文链接&#xff1a;Redis对象的数据结构及其底层实现原理汇总 当我们被问到 Redis 中有什么数据结构&#xff0c;或者说数据类型&#xff0c;我们可能会说有字符串、列表、哈希、集合、有序集合。 其实这几种数据类型在 Redis 中都由…

数据结构02附录01:顺序表考研习题[C++]

图源&#xff1a;文心一言 考研笔记整理~&#x1f95d;&#x1f95d; 之前的博文链接在此&#xff1a;数据结构02&#xff1a;线性表[顺序表链表]_线性链表-CSDN博客~&#x1f95d;&#x1f95d; 本篇作为线性表的代码补充&#xff0c;每道题提供了优解和暴力解算法&#xf…

二十一、数组(1)

本章概要 数组特性 用于显示数组的实用程序 一等对象返回数组 简单来看&#xff0c;数组需要你去创建和初始化&#xff0c;你可以通过下标对数组元素进行访问&#xff0c;数组的大小不会改变。大多数时候你只需要知道这些&#xff0c;但有时候你必须在数组上进行更复杂的操作…

KofamScan-KEGG官方推荐的使用系同源和隐马尔可夫模型进行KO注释

文章目录 简介安装使用输入蛋白序列输出detail-tsv格式输出detail格式输出mapper格式 输出结果detail和detail-tsv格式mapper格式常用命令tmp目录 与emapper结果比较其他参数参考 简介 KofamScan 是一款基于 KEGG 直系同源和隐马尔可夫模型&#xff08;HMM&#xff09;的基因功…

oracle21c报错 【ORA-65096: 公用用户名或角色名无效】

1.数据库版本 oracle21c 2.问题提示 创建用户提示【ORA-65096: 公用用户名或角色名无效】 create user 自定义用户名 identified by 密码;--例:用户为test1&#xff0c;密码为123456 create user test1 identified by 123456;三.解决办法及结果 oracle11g之后的版本&#xff…

飞书开发学习笔记(八)-开发飞书小程序Demo

飞书开发学习笔记(八)-开发飞书小程序Demo 一.小程序开发概述 1.1 小程序开发概述 飞书开发文档中查看&#xff1a;小程序开发概述 飞书小程序是指可以运行在飞书客户端中的小程序&#xff0c;小程序的一套代码可以适配 Android、iOS、PC 多平台&#xff0c;且用户体验与飞书…

Android Glide加载transform CenterCrop, CircleCrop ShapeableImageView圆形图并描边,Kotlin

Android Glide加载transform CenterCrop, CircleCrop ShapeableImageView圆形图并描边&#xff0c;Kotlin import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.bumptech.glide.load.resource.bitmap.CenterCrop import com.bumptech.glide.…

【MySQL】聚合函数:汇总、分组数据

文章目录 学习目标MAX()、MIN()、AVG()、SUM()、COUNT()COUNT(*) 得到所有记录条目DISTINCT去重练习1&#xff08;使用UNION &#xff0c; SUM&#xff0c; BETEEN AND&#xff09;GROUP BY子句练习2&#xff08;使用sum&#xff0c;group by&#xff0c; join on&#xff0c; …

数据库学习 02-01 关系数据模型详细学习(数据库模式中的一种)

关系型数据模型的相关概念介绍&#xff1a; 01.关系&#xff08;Relation&#xff09; 一个关系对应通常说的一张表 02.元组&#xff08;Tuple&#xff09; 表中的一行即为一个元组&#xff0c;也就是一个对象 03.属性&#xff08;Attribute&#xff09; 表中的一列即为一个属性…

Ingress安全网关

目录 文章目录 目录本节实战TCP 流量拆分&#x1f6a9; 实战&#xff1a;TCP 流量拆分-2023.11.15(测试成功) Ingress安全网关Kubernetes Ingress&#x1f6a9; 实战&#xff1a;Kubernetes Ingress-2023.11.15(测试成功) Ingress GatewayIngress Gateway&#x1f6a9; 实战&am…

案例精选|聚铭综合日志分析系统提升长沙(中国水务)集团有限公司信息安全审计效率

长沙&#xff08;中国水务&#xff09;集团有限公司是经宁乡县自来水公司改制后成立的城市供水企业&#xff0c;隶属香港联合交易所主板上市公司-中国水务集团有限公司。目前&#xff0c;公司拥有2个水厂5个加压站&#xff0c;日供水能力为28万吨/日&#xff0c;供水范围已从城…

Java编程中,使用时间戳机制实现增量更新的示例

一、需求 课程下可以创建多个讲次&#xff0c;然后分享出去。 在没有更新分享前&#xff0c;通过分享链接看到的课程及讲次详情是快照。课程制作者可以继续修改调整自己的课程&#xff0c;对分享用户是不可见。 当制作者完成修改后&#xff0c;更新分享&#xff0c;让用户看到…

Heidenhain海德汉触摸屏数控面板维修MC 7522

海德汉HEIDENHAIN系统触摸屏维修/海德汉HEIDENHAIN系统操作面板维修。 数控系统维修范围&#xff1a; 海德汉数控系统维修范围&#xff1a;iTNC530系统、TNC620系统、Hi800-A系统、Hi800-E系统、Hi800-M系统、Hi800-D系统、Hi800-S系统、Hi200-S系统等&#xff1b; 发格数控系…

成功解决:文档根元素 “mapper“ 必须匹配 DOCTYPE 根 “null“

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 文章目录 前言错误信息解决方法 前言 错误…

使用Microsoft Dynamics AX 2012 - 2. 入门:导航和常规选项

Microsoft Dynamics AX的核心原则之一是为习惯于Microsoft软件的用户提供熟悉的外观和感觉。然而&#xff0c;业务软件必须适应业务流程&#xff0c;这可能相当复杂。 用户界面和常见任务 在我们开始进行业务流程和案例研究之前&#xff0c;我们想了解一下本章中的常见功能。…

【原创】java+swing+mysql校园活动管理系统设计与实现

前言&#xff1a; 本文介绍了一个校园活动管理系统的设计与实现。该系统基于JavaSwing技术&#xff0c;采用C/S架构&#xff0c;使用Java语言开发&#xff0c;以MySQL作为数据库。系统实现了活动发布、活动报名、活动列表查看等功能&#xff0c;方便了校园活动的发布和管理&am…

群晖7.2版本安装CloudDriver2(套件)挂载alist(xiaoya)到本地

CloudDrive是一个强大的多云盘管理工具&#xff0c;为用户提供包含云盘本地挂载的一站式的多云盘解决方案。挂载到本地后&#xff0c;可以像本地文件一样进行操作。 一、套件库添加矿神源 二、安装CloudDriver2 1、搜索安装 搜索框输入【clouddrive】&#xff0c;搜索到Clou…

基于探路者算法优化概率神经网络PNN的分类预测 - 附代码

基于探路者算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于探路者算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于探路者优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络…