当前位置: 首页 > news >正文

买好域名后怎么做网站/智能建站abc

买好域名后怎么做网站,智能建站abc,企业官网建站步骤,天眼查询系统文章目录 一、Tomcat1. BS 与 CS 开发介绍1.1 BS 开发1.2 CS 开发 2. 浏览器访问 web 服务过程详解(面试题)2.1 回到前面的 JavaWeb 开发技术栈图2.2 浏览器访问 web 服务器文件的 UML时序图(过程) ! 二、动态 WEB 开发核心-Servlet1. 为什么会出现 Servlet2. 什么是…

文章目录

  • 一、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://主机/uriSystem.out.println("请求的统一资源定位符(决定路径) URL= " + request.getRequestURL());// http://localhost:8080/servlet/requestMethodsSystem.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 / PostSystem.out.println("http 请求方式= " + request.getMethod());/************************************ 获取和请求参数相关信息, 注意要求在返回数据前,获取参数***********************************///1. 获取表单的数据[单个数据]//username=tom&pwd=123&hobby=lyl&hobby=lzqString 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();//找到带有中文的 cookieCookie 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,同时也可以创建sessionHttpSession session = request.getSession();//2. 给session 获取idSystem.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. 创建 sessionHttpSession session = request.getSession();System.out.println("CreateSession2 sid= " + session.getId());//2. 设置生命周期为 60ssession.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.获取到sessionHttpSession 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. 演示如何删除sessionHttpSession 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)//把用户名保存到 sessionHttpSession 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.htmlSystem.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,即从哪个网址请求过来的 urlString referer = request.getHeader("Referer");System.out.println("referer=" + referer);//判断打过来的请求 url是否是 login.html,如果不是,重定向到loginif ("http://localhost:8080/cs/login.html".equals(referer)) {//获取提交表单的 usernameCookie[] cookies = request.getCookies();//读取key为 username 的 cookieCookie 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();// 工程路径 => /csresponse.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 集合方式 1Type 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{@Overridepublic 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

相关文章:

JavaWeb[总结]

文章目录 一、Tomcat1. BS 与 CS 开发介绍1.1 BS 开发1.2 CS 开发 2. 浏览器访问 web 服务过程详解(面试题)2.1 回到前面的 JavaWeb 开发技术栈图2.2 浏览器访问 web 服务器文件的 UML时序图(过程) &#xff01; 二、动态 WEB 开发核心-Servlet1. 为什么会出现 Servlet2. 什么是…...

如何解决小程序异步请求问题

小程序异步请求问题指的是在小程序中进行异步请求时可能会出现的问题&#xff0c;比如请求失败、请求超时等。以下是一些解决方案&#xff1a; 检查网络连接&#xff1a;首先需要确保网络连接正常&#xff0c;只有网络连接正常时才能正常进行异步请求。 检查请求参数&#xff…...

NSSCTF第12页(3)

[NSSCTF 2nd]php签到 首先&#xff0c;代码定义了一个名为 waf 的函数&#xff0c;用于执行一个简单的文件扩展名检查来防止上传恶意文件。 $black_list 是一个存储不允许的文件扩展名的数组&#xff0c;如 “ph”、“htaccess” 和 “ini”。 pathinfo($filename, PATHINF…...

基于ssm+vue交通事故档案系统

摘要 摘要是对文章、论文或其他文本的主要观点、结论和关键信息的简洁概括。由于你没有提供具体的文章或主题&#xff0c;我将为你创建一个通用的摘要。 本文介绍了一种基于SSM&#xff08;Spring Spring MVC MyBatis&#xff09;和Vue.js的交通事故档案管理系统的设计与实现…...

DNS1(Bind软件)

名词解释 1、DNS&#xff08;Domain Name System&#xff09; DNS即域名系统&#xff0c;它是一个分层的分布式数据库&#xff0c;存储着IP地址与主机名的映射 2、域和域名 域为一个标签&#xff0c;而有多个标签域构成的称为域名。例如hostname.example.com&#xff0c;其…...

PDF自动打印

​ 最近接到用户提过来的需求&#xff0c;需要一个能够自动打印图纸的功能&#xff0c;经过几天的研究整出来个初版了的&#xff0c;分享出来给大家&#xff0c;希望能有帮助。 需求描述: ​ 生产车间现场每天都有大量的图纸需要打印&#xff0c;一个一个打印太慢了&#xff0…...

【C#】类型转换-显式转换:括号强转、Parse法、Convert法、其他类型转string

目录 一、括号强转 1.有符号整型 2.无符号整型 3.浮点之间 4.无符号和有符号 5.浮点和整型 6.char和数值类型 7.bool和string是不能够通过 括号强转的 二、Parse法 1.有符号 2.无符号 3.浮点型 4.特殊类型 三、Convert法 1.转字符串 2.转浮点型 3.特殊类型转换…...

【智能家居】4、智能家居框架设计和代码文件工程建立

目录 一、智能家居项目框架 二、智能家居工厂模式示意 三、代码文件工程建立 SourceInsight创建新工程步骤 一、智能家居项目框架 二、智能家居工厂模式示意 三、代码文件工程建立 创建一个名为si的文件夹用于保存SourceInsight生成的文件信息&#xff0c;然后在SourceInsig…...

【GAN】数据增强基础知识

最近要用到&#xff0c;但是一点基础都没有&#xff0c;故开个文章记录一下笔记 目录 GAN DCGAN WGAN EEGGAN GAN 参考 生成对抗网络&#xff08;GAN&#xff09; - 知乎 (zhihu.com) 文章 [1406.2661] Generative Adversarial Networks (arxiv.org) 代码 GitHub - …...

Skywalking流程分析_3(服务的准备、启动、关闭)

前文将SkyWalkingAgent.premain中的&#xff1a; SnifferConfigInitializer.initializeCoreConfig(agentArgs)pluginFinder new PluginFinder(new PluginBootstrap().loadPlugins())这两个方法分析完毕&#xff0c;下面继续分析premain方法其余部分 创建byteBuddy final By…...

mysql中的各种日志文件redo log、undo log和binlog

mysql中的各种日志文件redo log、undo log和binlog mysql中的各种日志文件redo log、undo log和binlog1.MySQL日志文件类型2.redo log日志2.1 作用2.2工作原理&#xff1a;2.3详解 3.undo log日志4.binlog日志5.总结 mysql中的各种日志文件redo log、undo log和binlog 1.MySQL…...

【电视剧-长相思】经典语录

小编看了这么长时间的电视剧&#xff0c;突然感觉摘抄经典语录最有成就感&#xff0c;嘿嘿&#xff0c;下面是我在《长相思》&#xff08;第一季&#xff09;中感觉好的一些语录&#xff0c;语录是乱序排列哈 玟小六&#xff1a;我怕寂寞&#xff0c;寻不到长久的相依&#xff…...

串口通信原理及应用

Content 1. 前言介绍2. 连接方式3. 数据帧格式4. 代码编写 1. 前言介绍 串口通信是一种设备间非常常用的串行接口&#xff0c;以比特位的形式发送或接收数据&#xff0c;由于成本很低&#xff0c;容易使用&#xff0c;工程师经常使用这种方式来调试 MCU。 串口通信应用广泛&a…...

python爬取穷游网景点评论

爬取穷游网的景点评论数据&#xff0c;使用selenium爬取edge浏览器的网页文本数据。 同程的评论数据还是比较好爬取&#xff0c;不像大众点评需要你登录验证杂七杂八的&#xff0c;只需要找准你想要爬取的网页链接就能拿到想要的文本数据。 这里就不得不提一下爬取过程中遇到的…...

Phar 文件上传以及反序列化

1.phar反序列化 触发条件&#xff1a; 1、能将phar文件上传 2、可利用函数 stat、fileatime、filectime、file_exists、file_get_contents、file_put_contents、file、filegroup、fopen、fileinode、filemtime、fileowner、fileperms、is_dir、is_executable、is_file、is_link…...

面试其他注意事项

面试其他注意事项 一、面试反问 这个岗位的日常工作和主要职责是什么&#xff1f;咱们这边主要负责什么业务&#xff0c;用到了哪些技术呢&#xff1f;对于我们校招生有没有培养体系呢&#xff1f;脱产培训&#xff0c;还是边工作边熟悉&#xff1f;会有导师带嘛&#xff1f;…...

sklearn 笔记 BallTree/KD Tree

由NearestNeighbors类包装 1 主要使用方法 sklearn.neighbors.BallTree(X, leaf_size40, metricminkowski, **kwargs) X数据集中的点数leaf_size改变 leaf_size 不会影响查询的结果&#xff0c;但可以显著影响查询的速度和构建树所需的内存metric用于距离计算的度量。默认为…...

ConstraintLayout使用详解

作为一名程序员&#xff0c;可能会经历以下难受的事情&#xff1a; 解决难以调试的代码错误处理复杂的代码库和维护遗留代码修改已经存在很长时间的代码&#xff0c;需要考虑兼容性和稳定性长时间工作&#xff0c;缺乏身体运动和社交互动&#xff0c;导致压力和孤独感遇到不能…...

Java8Stream快速使用

将List集合存入流中 List<String> list new ArrayList<>();list.add("张一");list.add("张二");list.add("张三");list.add("李四");list.add("赵五");list.add("张六");list.add("王八"…...

work环境配置

1.计算机右键找到属性 2.配置环境变量 3.新加环境变量 4.修改环境变量path .bat文件内容 php ApplicationsChatstart_register.php ApplicationsChatstart_gateway.php ApplicationsChatstart_businessworker.php pause...

Flutter应用-使用sqflite升级数据库

文章目录 问题描述具体做法代码示例更多条件限制升级 数据库迁移和备份简介数据库迁移数据库备份 问题描述 使用fluttter开发的应用程序发布后&#xff0c;发现数据库有些设计不合理。如何来更新数据库呢&#xff1f; 使用sqflite来处理数据库&#xff0c;但是第一版软件发布后…...

集群搭建(redis7)

一、主从复制(replica)&#xff08;不推荐&#xff09; 介绍 主从复制 mmaster以写为主&#xff0c;slave以读为主当master数据变化时&#xff0c;自动将新的数据异步同步到其他slave数据库 读写分离down机恢复数据备份水平扩容支撑高并发 基本操作 配从不配主 权限细节 maste…...

高能分享:软件测试十大必问面试题(附带答案)

1 介绍之前负责的项目 参考答案&#xff1a;先大概描述一下这个项目是做什么的&#xff08;主要功能&#xff09;&#xff0c;包括哪些模块&#xff0c;是什么架构的&#xff08;B/S、C/S、移动端&#xff1f;&#xff09;&#xff0c;你在其中负责哪些模块的测试。期间经历了几…...

Java 反射设置List属性

使用 Java 反射可以动态地设置对象的属性值&#xff0c;包括 List 类型的属性。以下是一个示例代码&#xff0c;演示如何通过反射设置 List 类型的属性&#xff1a; 假设有一个类 Person&#xff0c;包含一个 List 类型的属性 names&#xff1a; java public class Person { …...

wpf devexpress Property Grid创建属性定义

WPF Property Grid控件使用属性定义定义如何做和显示 本教程示范如何绑定WP Property Grid控件到数据和创建属性定义。 执行如下步骤 第一步-创建属性定义 添加PropertyGridControl组件到项目。 打开工具箱在vs&#xff0c;定位到DX.23.1: Data 面板&#xff0c;选择Prope…...

78.子集--77.组合

78&#xff0c;子集 递归 class Solution(object):def subsets(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""# 结果ans[]# 临时结果dp_[]def dfs(nums,index):if indexlen(nums):# 保存结果co_dpdp_[:]ans.append(co_dp)r…...

【C++】模版-初阶

目录 泛型编程--模版 函数模版 类模版 泛型编程--模版 函数模版 如何实现一个通用的交换函数呢?void Swap(int& left, int& right){int temp left;left right;right temp;}void Swap(double& left, double& right){double temp left;left right;righ…...

【JavaEE初阶】 TCP服务器与客户端的搭建

文章目录 &#x1f332;前言&#x1f334;ServerSocket API&#x1f384;Socket API&#x1f340;TCP中的长短连接&#x1f38d;建立TCP回显客户端与服务器&#x1f6a9;TCP搭建服务器&#x1f6a9;TCP搭建客户端&#x1f6a9;通信过程展示&#xff1a; &#x1f333;多个客户端…...

23111710[含文档+PPT+源码等]计算机毕业设计基于SpringBoot的体育馆场地预约赛事管理系统的设计

文章目录 **软件开发环境及开发工具&#xff1a;****功能介绍&#xff1a;****论文截图&#xff1a;****数据库&#xff1a;****实现&#xff1a;****代码片段&#xff1a;** 编程技术交流、源码分享、模板分享、网课教程 &#x1f427;裙&#xff1a;776871563 软件开发环境及…...

【论文解读】GPT Understands, Too

一.论文 1.1 P-tuning 区别于之前的工作&#xff0c;这篇工作认为promote可以在句子中的任意位置起到作用&#xff0c;可以将它们插入上下文或目标中 上图中&#xff0c;左图是不使用任何操作&#xff0c;右图是选择在居首和目标前插入promote的embedding&#xff0c;插入pro…...