servlet学习笔记

1、Servlet笔记

1.1 Servlet在系统中扮演的角色

角色: 控制器

具体功能:总体的调度控制

简要流程:

  • 接受请求
  • 根据业务逻辑处理请求(调用service方法)
  • 分发页面(转发、重定向)
  • 返回响应

1.2 生命周期

生命周期环节调用的方法时机次数
创建对象无参构造器默认:第一次请求 修改:Web应用启动时一次
初始化init(ServletConfig servletConfig)创建对象后一次
处理请求service(ServletRequest servletRequest, ServletResponse servletResponse)接收到请求后多次
销毁操作destroy()Web应用卸载之前一次

1.3 servlet容器

  • 容器对象的功能:负责容器内对象的创建、初始化、工作、异常管理、清理、销毁等等各个方面。
  • 容器对象的数量:通常是单例的

1.4 servlet对象继承关系

Httpservlet --> GenericServlet --> Servlet

类图如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6pIK1iHl-1663981647452)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6232cf1acd69487bab658978b8256986~tplv-k3u1fbpfcp-watermark.image?)]

1.5 servlet实战

  1. 创建servlet
  • 实现servlet接口
  • 继承HttpServlet
  1. web.xml配置

    web.xml在新建web中,在web.xml配置servlet信息,主要配置两个和,整个mapping和servlet关联起来。示例如下:

 <!-- 配置Servlet本身 -->
    <servlet>
        <!-- 全类名太长,给Servlet设置一个简短名称 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- 配置Servlet的全类名 -->
        <servlet-class>com.study.servlet.HelloServlet</servlet-class>

        <!-- 配置初始化参数 -->
        <init-param>
            <param-name>goodMan</param-name>
            <param-value>me</param-value>
        </init-param>

        <!-- 配置Servlet启动顺序,可以不配置 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- 将Servlet和访问地址关联起来 -->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
  1. Servlet
    代码示例:
public class HelloServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        req.setCharacterEncoding("UTF-8");
        System.out.println(req.getParameter("fname"));
        System.out.println(req.getParameter("price"));
        System.out.println(req.getParameter("fcount"));
        System.out.println(req.getParameter("remark"));


        HttpSession session = req.getSession();
        System.out.println("【session isNew】"+session.isNew());
        System.out.println("【session id】"+session.getId());
        session.setAttribute("userName","......");

    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="hello" method="post">
    名称:<input type="text" name="fname"/><br/>
    价格:<input type="text" name="price"/><br/>
    库存:<input type="text" name="fcount"/><br/>
    备注:<input type="text" name="remark"/><br/>
    <input type="submit" value="添加">
</form>

</body>
</html>
  • 首先在服务端提交参数,action调用路径hello
  • hello映射到Servlet中,正对着web.xml配置信息

3.1 获取请求参数

请求参数情况调用方法
一个名字一个值request.getParameter(“请求参数名”)
一个名字多个值request.getParameterValues(“请求参数名”)

1.6 转发和重定向

  1. 代码实战
//转发
request.getRequestDispatcher("转发的目标资源地址").forward(request, response);
    
//重定向  
response.sendRedirect("重定向的目标资源的地址")

2、区别对比

转发重定向
一次请求两次请求
浏览器地址栏显示的是第一个资源的地址浏览器地址栏显示的是第二个资源的地址
全程使用的是同一个request对象全程使用的是不同的request对象
在服务器端完成在浏览器端完成
目标资源地址由服务器解析目标资源地址由浏览器解析
目标资源可以在WEB-INF目录下目标资源不能在WEB-INF目录下
目标资源仅限于本应用内部目标资源可以是外部资源

1.7 乱码解决

请求方法:

  • GET方法:在tomcat的server.xml中配置URIEncoding=“UTF-8”
  • POST方法:在service方法中获取请求参数前调用request.setCharacterEncoding(“UTF-8”)

响应方法:

  • 设置方式一:response.setCharacterEncoding(“UTF-8”); 含义:设置服务器端对响应体数据的编码字符集,所以还需要设置浏览器的解码字符集

  • 设置方式二:response.setContentType(“text/html;charset=UTF-8”); 含义:告诉浏览器本次响应体的内容类型,等于设置浏览器的解码字符集,那么服务器端自动使用这个字符集编码

1.8. ServletConfig

  • 主要功能:获取ServletContext
  • 次要功能:获取初始化参数。例如上述web.xml中配置的
public interface ServletConfig {
    String getServletName();

    ServletContext getServletContext();

    String getInitParameter(String var1);

    Enumeration<String> getInitParameterNames();
}

1.9. ServletContext

代表:整个Web应用。ServletContext对象的生命周期和整个Web应用的生命周期一致。

是否单例:是

典型的功能:

  • 获取某个资源的真实路径:getRealPath()

  • 获取整个Web应用级别的初始化参数:getInitParameter()

  • 作为Web应用范围的域对象

    • 存入数据:setAttribute()
    • 取出数据:getAttribute()

(1)配置Web应用级别的初始化参数

    <!-- 配置Web应用的初始化参数 -->
    <context-param>
        <param-name>handsomeMan</param-name>
        <param-value>alsoMe</param-value>
    </context-param>

Web应用级别的初始化参数的作用举例:

  • 在整个项目级别,设置一些全局范围内的参数
  • 使用Spring框架时,配置Spring配置文件所在的位置

(2)获取参数

String handsomeMan = servletContext.getInitParameter("handsomeMan");
System.out.println("handsomeMan = " + handsomeMan);

1.10.Servlet源码解读

xxxxx后续进行补充,大概就是doGet、doPost、service方法,如果继承的子类没有实现具体的方法,那么这执行父类的方法,会报错403等

1.11.域对象

域对象包括:
- 请求域 request 一次请求
- 回话域 session 一次会话,客户端断开连接、或者到达一定时间结束
- 应用域 application 应用开启到关闭
PS:在我们使用的视图是JSP的时候,域对象有4个
-   pageContext
-   request:请求域
-   session:会话域
-   application:应用域
所以在JSP的使用背景下,我们可以说域对象有4个,现在使用Thymeleaf了,没有pageContext。
①操作请求域

Servlet中代码:

String requestAttrName = "helloRequestAttr";
String requestAttrValue = "helloRequestAttr-VALUE";

request.setAttribute(requestAttrName, requestAttrValue);

Thymeleaf表达式:

<p th:text="${helloRequestAttr}">request field value</p>
②操作会话域

Servlet中代码:

// ①通过request对象获取session对象
HttpSession session = request.getSession();

// ②存入数据
session.setAttribute("helloSessionAttr", "helloSessionAttr-VALUE");

Thymeleaf表达式:

<p th:text="${session.helloSessionAttr}">这里显示会话域数据</p>
③操作应用域

Servlet中代码:

// ①通过调用父类的方法获取ServletContext对象
ServletContext servletContext = getServletContext();

// ②存入数据
servletContext.setAttribute("helloAppAttr", "helloAppAttr-VALUE");

Thymeleaf表达式:

<p th:text="${application.helloAppAttr}">这里显示应用域数据</p>

2、Thymeleaf笔记

2.1.MVC模型

  • M 指的是mode,数据处理的模型。一般有dto、bo等
  • V 指的是view视图
  • C 指的controller控制器

MVC是在表述层开发中运用的一种设计理念。主张把封装数据的『模型』、显示用户界面的『视图』、协调调度的『控制器』分开。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yk7QE5mi-1663981647453)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d3f7ef8d8ac841ffa5ccb918ed2cff00~tplv-k3u1fbpfcp-watermark.image?)]

2.2.简介

官网地址(opens new window)

官方文档

Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text. The main goal of Thymeleaf is to provide an elegant and highly-maintainable way of creating templates. To achieve this, it builds on the concept of Natural Templates to inject its logic into template files in a way that doesn’t affect the template from being used as a design prototype. This improves communication of design and bridges the gap between design and development teams. Thymeleaf has also been designed from the beginning with Web Standards in mind – especially HTML5 – allowing you to create fully validating templates if that is a need for you.

2.3.Thymeleaf优势

  • SpringBoot官方推荐使用的视图模板技术,和SpringBoot完美整合。
  • 不经过服务器运算仍然可以直接查看原始值,对前端工程师更友好。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <p th:text="${hello}">Original Value</p>

</body>
</html>

2.4.物理视图和逻辑视图

①物理视图

在Servlet中,将请求转发到一个HTML页面文件时,使用的完整的转发路径就是物理视图。./images

/pages/user/login_success.html

如果我们把所有的HTML页面都放在某个统一的目录下,那么转发地址就会呈现出明显的规律:

/pages/user/login.html /pages/user/login_success.html /pages/user/regist.html /pages/user/regist_success.html

……

路径的开头都是:/pages/user/

路径的结尾都是:.html

所以,路径开头的部分我们称之为视图前缀,路径结尾的部分我们称之为视图后缀。

②逻辑视图

物理视图=视图前缀+逻辑视图+视图后缀

上面的例子中:

视图前缀逻辑视图视图后缀物理视图
/pages/user/login.html/pages/user/login.html
/pages/user/login_success.html/pages/user/login_success.html

2.5.使用方法

  1. jar包引用

    引用jar包如下:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-skFzJWDk-1663981647453)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2baa2a23ee43406d9d53d7ed926ad96b~tplv-k3u1fbpfcp-watermark.image?)]

  2. web.xml配置

物理视图=视图前缀+逻辑视图+视图后缀

说明:param-value中设置的前缀、后缀的值不是必须叫这个名字,可以根据实际情况和需求进行修改。

为什么要放在WEB-INF目录下?

原因:WEB-INF目录不允许浏览器直接访问,所以我们的视图模板文件放在这个目录下,是一种保护。以免外界可以随意访问视图模板文件。

访问WEB-INF目录下的页面,都必须通过Servlet转发过来,简单说就是:不经过Servlet访问不了。

这样就方便我们在Servlet中检查当前用户是否有权限访问。

那放在WEB-INF目录下之后,重定向进不去怎么办?

重定向到Servlet,再通过Servlet转发到WEB-INF下。

<!-- 在上下文参数中配置视图前缀和视图后缀 -->
<context-param>
    <param-name>view-prefix</param-name>
    <param-value>/WEB-INF/view/</param-value>
</context-param>
<context-param>
    <param-name>view-suffix</param-name>
    <param-value>.html</param-value>
</context-param>

3.创建servlet基类

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

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

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

4.通过servlet跳转到指定页面

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    // 1.声明当前请求要前往的视图名称
    String viewName = "target";
    
    // 2.调用ViewBaseServlet父类中的解析视图模板的方法
    super.processTemplate(viewName, request, response);
    
}

2.6.Thymeleaf前端语法

  1. 命名空间

    html命名空间修改为http://www.thymeleaf.org

  2. 基本语法

    xxx后续补充

3、会话控制笔记

cookie和session

问题:
保持用户登录状态,背后的底层逻辑是:服务器在接收到用户请求的时候,有办法判断这个请求来自于之前的某一个用户。所以保持登录状态,本质上是保持『会话状态』

img001.98859ab4.png

3.1.Cookie的工作机制

因为Http是无状态协议,所以需要引入cookie或session来识别用户身份

  1. cookie介绍

    • 存储在浏览器中
    • 以键值对的形式存在
    • 键和值都是字符串类型
    • 数据量很小
  2. Cookie在浏览器和服务器之间的传递

[1]没有Cookie的状态

在服务器端没有创建Cookie并返回的情况下,浏览器端不会保存Cookie信息。双方在请求和响应的过程中也不会携带Cookie的数据。

[2]创建Cookie对象并返回

// 1.创建Cookie对象
Cookie cookie = new Cookie("cookie-message", "hello-cookie");

// 2.将Cookie对象添加到响应中
response.addCookie(cookie);

// 3.返回响应
processTemplate("page-target", request, response);

[3]服务器端返回Cookie的响应消息头

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8zQFZyQU-1663981647454)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cf62586a83224ee59f66cb95e6bb2952~tplv-k3u1fbpfcp-watermark.image?)]

[4]浏览器拿到Cookie之后

浏览器拿到Cookie之后,以后的每一个请求都会携带Cookie信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqxISV1V-1663981647454)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/eb5000852cf641cb827365d89fe91de3~tplv-k3u1fbpfcp-watermark.image?)]

[5]服务器端读取Cookie的信息

// 1.通过request对象获取Cookie的数组
Cookie[] cookies = request.getCookies();

// 2.遍历数组
for (Cookie cookie : cookies) {
    System.out.println("cookie.getName() = " + cookie.getName());
    System.out.println("cookie.getValue() = " + cookie.getValue());
    System.out.println();
}

③Cookie时效性

[1]理论

  • 会话级Cookie

    • 服务器端并没有明确指定Cookie的存在时间
    • 在浏览器端,Cookie数据存在于内存中
    • 只要浏览器还开着,Cookie数据就一直都在
    • 浏览器关闭,内存中的Cookie数据就会被释放
  • 持久化Cookie

    • 服务器端明确设置了Cookie的存在时间
    • 在浏览器端,Cookie数据会被保存到硬盘上
    • Cookie在硬盘上存在的时间根据服务器端限定的时间来管控,不受浏览器关闭的影响
    • 持久化Cookie到达了预设的时间会被释放

服务器端返回Cookie时附带过期时间的响应消息头如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oUjlAXoQ-1663981647454)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bbf5abcb03dc4d81ba4242169baa4e65~tplv-k3u1fbpfcp-watermark.image?)]

服务器通知浏览器删除Cookie时的响应消息头如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rs9ajC1T-1663981647454)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c3d77961b8034a829d455fc0e9193665~tplv-k3u1fbpfcp-watermark.image?)]

[2]代码

// ※给Cookie设置过期时间
// 正数:Cookie的过期时间,以秒为单位
// 负数:表示这个Cookie是会话级的Cookie,浏览器关闭时释放
// 0:通知浏览器立即删除这个Cookie
cookie.setMaxAge(20);

[3]会话和持久化Cookie对比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qEnhVpKr-1663981647455)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/30eecf420acd403799aaa4acf1657af1~tplv-k3u1fbpfcp-watermark.image?)]

④Cookie的domain和path

上网时间长了,本地会保存很多Cookie。对浏览器来说,访问互联网资源时不能每次都把所有Cookie带上。浏览器会使用Cookie的domain和path属性值来和当前访问的地址进行比较,从而决定是否携带这个Cookie。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-41kZHbGW-1663981647455)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c3d839b912d34c7c80daf7cdb6428c78~tplv-k3u1fbpfcp-watermark.image?)]

3.2.session工作机制

1、文字描述

前提:浏览器正常访问服务器

  • 服务器端没调用request.getSession()方法:什么都不会发生

  • 服务器端调用了request.getSession()方法

    • 服务器端检查当前请求中是否携带了JSESSIONID的Cookie

      • 有:根据JSESSIONID在服务器端查找对应的HttpSession对象

        • 能找到:将找到的HttpSession对象作为request.getSession()方法的返回值返回
        • 找不到:服务器端新建一个HttpSession对象作为request.getSession()方法的返回值返回
      • 无:服务器端新建一个HttpSession对象作为request.getSession()方法的返回值返回

2、流程图描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eVn2v6uQ-1663981647455)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d8614dc58089400888b0e5d7d6bf7c01~tplv-k3u1fbpfcp-watermark.image?)]

3、代码验证
// 1.调用request对象的方法尝试获取HttpSession对象
HttpSession session = request.getSession();

// 2.调用HttpSession对象的isNew()方法
boolean wetherNew = session.isNew();

// 3.打印HttpSession对象是否为新对象
System.out.println("wetherNew = " + (wetherNew?"HttpSession对象是新的":"HttpSession对象是旧的"));

// 4.调用HttpSession对象的getId()方法
String id = session.getId();

// 5.打印JSESSIONID的值
System.out.println("JSESSIONID = " + id);
4、时效性

①为什么Session要设置时限

用户量很大之后,Session对象相应的也要创建很多。如果一味创建不释放,那么服务器端的内存迟早要被耗尽。

②设置时限的难点

从服务器端的角度,很难精确得知类似浏览器关闭的动作。而且即使浏览器一直没有关闭,也不代表用户仍然在使用。

③服务器端给Session对象设置最大闲置时间

  • 默认值:1800秒

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sKpPYm9O-1663981647456)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c47a2ca387794f5faee7e7ae96b629d0~tplv-k3u1fbpfcp-watermark.image?)]

最大闲置时间生效的机制如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IfzdIFCr-1663981647456)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2c32444ab5b843d9a8674639f0be09ca~tplv-k3u1fbpfcp-watermark.image?)]

④代码验证

// ※测试时效性
// 获取默认的最大闲置时间
int maxInactiveIntervalSecond = session.getMaxInactiveInterval();
System.out.println("maxInactiveIntervalSecond = " + maxInactiveIntervalSecond);

// 设置默认的最大闲置时间
session.setMaxInactiveInterval(15);

⑤强制Session立即失效

session.invalidate();

4、过滤器笔记

4.1.过滤器简介

1、通过类比了解过滤器作用

②登录检查

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2XCFI03Y-1663981647456)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/78f3591f0a9144eabc7544144d12d5ff~tplv-k3u1fbpfcp-watermark.image?)]

2、过滤器的三要素

①拦截

过滤器之所以能够对请求进行预处理,关键是对请求进行拦截,把请求拦截下来才能够做后续的操作。而且对于一个具体的过滤器,它必须明确它要拦截的请求,而不是所有请求都拦截。

②过滤

根据业务功能实际的需求,看看在把请求拦截到之后,需要做什么检查或什么操作,写对应的代码即可。

③放行

过滤器完成自己的任务或者是检测到当前请求符合过滤规则,那么可以将请求放行。所谓放行,就是让请求继续去访问它原本要访问的资源。

友情提示:将来学习SpringMVC时,会学习SpringMVC中的『拦截器』,同样具备三要素。

3、HelloWorld
1、思路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-onkql36N-1663981647456)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/07577ab93ca7472b8f2e30f540dee6d9~tplv-k3u1fbpfcp-watermark.image?)]

2、操作步骤

①准备工作

  • 创建module
  • 加入Thymeleaf环境
  • 完成首页访问功能
  • 创建Target01Servlet以及target01.html
  • 创建SpecialServlet以及special.html

②创建Filter

[1]创建Target01Filter类

  • 要点1:实现javax.servlet.Filter接口

  • 要点2:在doFilter()方法中执行过滤

  • 要点3:如果满足过滤条件使用 chain.doFilter(request, response);放行

  • 要点4:如果不满足过滤条件转发或重定向请求

    • 附带问题:Thymeleaf模板渲染。这里我们选择的解决办法是跳转到一个Servlet,由Servlet负责执行模板渲染返回页面。
public class Target01Filter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        // 1.打印一句话表明Filter执行了
        System.out.println("过滤器执行:Target01Filter");

        // 2.检查是否满足过滤条件
        // 人为设定一个过滤条件:请求参数message是否等于monster
        // 等于:放行
        // 不等于:将请求跳转到另外一个页面
        // ①获取请求参数
        String message = request.getParameter("message");

        // ②检查请求参数是否等于monster
        if ("monster".equals(message)) {

            // ③执行放行
            // FilterChain对象代表过滤器链
            // chain.doFilter(request, response)方法效果:将请求放行到下一个Filter,
            // 如果当前Filter已经是最后一个Filter了,那么就将请求放行到原本要访问的目标资源
            chain.doFilter(request, response);

        }else{

            // ④跳转页面
            request.getRequestDispatcher("/SpecialServlet?method=toSpecialPage").forward(request, response);

        }

    }

    @Override
    public void destroy() {

    }
}

[2]配置Target01Filter类

这一步也可以叫『注册』。

<!-- 配置Target01Filter -->
<filter>
    <!-- 配置Filter的友好名称 -->
    <filter-name>Target01Filter</filter-name>

    <!-- 配置Filter的全类名,便于Servlet容器创建Filter对象 -->
    <filter-class>com.atguigu.filter.filter.Target01Filter</filter-class>
</filter>

<!-- 配置Filter要拦截的目标资源 -->
<filter-mapping>
    <!-- 指定这个mapping对应的Filter名称 -->
    <filter-name>Target01Filter</filter-name>

    <!-- 通过请求地址模式来设置要拦截的资源 -->
    <url-pattern>/Target01Servlet</url-pattern>

4.2过滤器生命周期

回顾Servlet生命周期
1、Filter生命周期

和Servlet生命周期类比,Filter生命周期的关键区别是:在Web应用启动时创建对象

生命周期阶段执行时机执行次数
创建对象Web应用启动时一次
初始化创建对象后一次
拦截请求接收到匹配的请求多次
销毁Web应用卸载前一次

4.3.过滤器匹配规则

本节要探讨的是在filter-mapping中如何将Filter同它要拦截的资源关联起来。

1、精确匹配

指定被拦截资源的完整路径:

<!-- 配置Filter要拦截的目标资源 -->
<filter-mapping>
    <!-- 指定这个mapping对应的Filter名称 -->
    <filter-name>Target01Filter</filter-name>

    <!-- 通过请求地址模式来设置要拦截的资源 -->
    <url-pattern>/Target01Servlet</url-pattern>
</filter-mapping>
2、模糊匹配

相比较精确匹配,使用模糊匹配可以让我们创建一个Filter就能够覆盖很多目标资源,不必专门为每一个目标资源都创建Filter,提高开发效率。

①前杠后星

在我们配置了url-pattern为/user/*之后,请求地址只要是/user开头的那么就会被匹配。

<filter-mapping>
    <filter-name>Target02Filter</filter-name>

    <!-- 模糊匹配:前杠后星 -->
    <!--
        /user/Target02Servlet
        /user/Target03Servlet
        /user/Target04Servlet
    -->
    <url-pattern>/user/*</url-pattern>
</filter-mapping>

极端情况:/*匹配所有请求

②前星后缀

下面我们使用png图片来测试后缀拦截的效果,并不是只能拦截png扩展名。

[1]创建一组img标签

    <img th:src="@{/./images/img017.png}"/><br/>
    <img th:src="@{/./images/img018.png}"/><br/>
    <img th:src="@{/./images/img019.png}"/><br/>
    <img th:src="@{/./images/img020.png}"/><br/>
    <img th:src="@{/./images/img024.png}"/><br/>
    <img th:src="@{/./images/img025.png}"/><br/>

[2]创建Filter

<filter>
    <filter-name>Target04Filter</filter-name>
    <filter-class>com.atguigu.filter.filter.Target04Filter</filter-class>
</filter>
<filter-mapping>
    <filter-name>Target04Filter</filter-name>
    <url-pattern>*.png</url-pattern>
</filter-mapping>

③前杠后缀,星号在中间

配置方式如下:

<url-pattern>/*.png</url-pattern>

按照这个配置启动Web应用时会抛出异常:

java.lang.IllegalArgumentException: Invalid /*.png in filter mapping

结论:这么配是不允许的!

3、匹配Servlet名称[了解]
<filter-mapping>
    <filter-name>Target05Filter</filter-name>

    <!-- 根据Servlet名称匹配 -->
    <servlet-name>Target01Servlet</servlet-name>
</filter-mapping>

4.4.过滤器链

1、概念
  • 多个Filter的拦截范围如果存在重合部分,那么这些Filter会形成Filter链。
  • 浏览器请求重合部分对应的目标资源时,会依次经过Filter链中的每一个Filter。
  • Filter链中每一个Filter执行的顺序是由web.xml中filter-mapping配置的顺序决定的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UwoMhun6-1663981647457)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4618dfb1d92a456e92ca983c74ad1bba~tplv-k3u1fbpfcp-watermark.image?)]

2、测试

①准备工作

创建超链接访问一个普通的Servlet即可。

②创建多个Filter拦截Servlet

<filter-mapping>
    <filter-name>TargetChain03Filter</filter-name>
    <url-pattern>/Target05Servlet</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>TargetChain02Filter</filter-name>
    <url-pattern>/Target05Servlet</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>TargetChain01Filter</filter-name>
    <url-pattern>/Target05Servlet</url-pattern>
</filter-mapping>

控制台打印效果:

过滤器执行:Target03Filter[模糊匹配 前杠后星 /*]

测试Filter链:TargetChain03Filter 测试Filter链:TargetChain02Filter 测试Filter链:TargetChain01Filter

5、监听器笔记

5.1.观察者模式

  • 观察者:监控『被观察者』的行为,一旦发现『被观察者』触发了事件,就会调用事先准备好的方法执行操作。
  • 被观察者:『被观察者』一旦触发了被监控的事件,就会被『观察者』发现

5.2.监听器简介

1、概念

监听器:专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。 Servlet监听器:Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext,HttpSession 和HttpServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。

2、分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XDBVc1kr-1663981647457)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cceea510c72e4667bc4c6af87480800f~tplv-k3u1fbpfcp-watermark.image?)]

  • 域对象监听器
  • 域对象的属性域监听器
  • Session域中数据的监听器
3、监听器列表

①ServletContextListener

作用:监听ServletContext对象的创建与销毁

方法名作用
contextInitialized(ServletContextEvent sce)ServletContext创建时调用
contextDestroyed(ServletContextEvent sce)ServletContext销毁时调用

ServletContextEvent对象代表从ServletContext对象身上捕获到的事件,通过这个事件对象我们可以获取到ServletContext对象。

②HttpSessionListener

作用:监听HttpSession对象的创建与销毁

方法名作用
sessionCreated(HttpSessionEvent hse)HttpSession对象创建时调用
sessionDestroyed(HttpSessionEvent hse)HttpSession对象销毁时调用

HttpSessionEvent对象代表从HttpSession对象身上捕获到的事件,通过这个事件对象我们可以获取到触发事件的HttpSession对象。

③ServletRequestListener

作用:监听ServletRequest对象的创建与销毁

方法名作用
requestInitialized(ServletRequestEvent sre)ServletRequest对象创建时调用
requestDestroyed(ServletRequestEvent sre)ServletRequest对象销毁时调用

ServletRequestEvent对象代表从HttpServletRequest对象身上捕获到的事件,通过这个事件对象我们可以获取到触发事件的HttpServletRequest对象。另外还有一个方法可以获取到当前Web应用的ServletContext对象。

④ServletContextAttributeListener

作用:监听ServletContext中属性的创建、修改和销毁

方法名作用
attributeAdded(ServletContextAttributeEvent scab)向ServletContext中添加属性时调用
attributeRemoved(ServletContextAttributeEvent scab)从ServletContext中移除属性时调用
attributeReplaced(ServletContextAttributeEvent scab)当ServletContext中的属性被修改时调用

ServletContextAttributeEvent对象代表属性变化事件,它包含的方法如下:

方法名作用
getName()获取修改或添加的属性名
getValue()获取被修改或添加的属性值
getServletContext()获取ServletContext对象

⑤HttpSessionAttributeListener

作用:监听HttpSession中属性的创建、修改和销毁

方法名作用
attributeAdded(HttpSessionBindingEvent se)向HttpSession中添加属性时调用
attributeRemoved(HttpSessionBindingEvent se)从HttpSession中移除属性时调用
attributeReplaced(HttpSessionBindingEvent se)当HttpSession中的属性被修改时调用

HttpSessionBindingEvent对象代表属性变化事件,它包含的方法如下:

方法名作用
getName()获取修改或添加的属性名
getValue()获取被修改或添加的属性值
getSession()获取触发事件的HttpSession对象

⑥ServletRequestAttributeListener

作用:监听ServletRequest中属性的创建、修改和销毁

方法名作用
attributeAdded(ServletRequestAttributeEvent srae)向ServletRequest中添加属性时调用
attributeRemoved(ServletRequestAttributeEvent srae)从ServletRequest中移除属性时调用
attributeReplaced(ServletRequestAttributeEvent srae)当ServletRequest中的属性被修改时调用

ServletRequestAttributeEvent对象代表属性变化事件,它包含的方法如下:

方法名作用
getName()获取修改或添加的属性名
getValue()获取被修改或添加的属性值
getServletRequest ()获取触发事件的ServletRequest对象

⑦HttpSessionBindingListener

作用:监听某个对象在Session域中的创建与移除

方法名作用
valueBound(HttpSessionBindingEvent event)该类的实例被放到Session域中时调用
valueUnbound(HttpSessionBindingEvent event)该类的实例从Session中移除时调用

HttpSessionBindingEvent对象代表属性变化事件,它包含的方法如下:

方法名作用
getName()获取当前事件涉及的属性名
getValue()获取当前事件涉及的属性值
getSession()获取触发事件的HttpSession对象

⑧HttpSessionActivationListener

作用:监听某个对象在Session中的序列化与反序列化。

方法名作用
sessionWillPassivate(HttpSessionEvent se)该类实例和Session一起钝化到硬盘时调用
sessionDidActivate(HttpSessionEvent se)该类实例和Session一起活化到内存时调用

HttpSessionEvent对象代表事件对象,通过getSession()方法获取事件涉及的HttpSession对象。

5.3.ServletContextListener

1、实用性

将来学习SpringMVC的时候,会用到一个ContextLoaderListener,这个监听器就实现了ServletContextListener接口,表示对ServletContext对象本身的生命周期进行监控。

2、具体用法

①创建监听器类

public class AtguiguListener implements ServletContextListener {
    @Override
    public void contextInitialized(
            // Event对象代表本次事件,通过这个对象可以获取ServletContext对象本身
            ServletContextEvent sce) {
        System.out.println("Hello,我是ServletContext,我出生了!");

        ServletContext servletContext = sce.getServletContext();
        System.out.println("servletContext = " + servletContext);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("Hello,我是ServletContext,我打算去休息一会儿!");
    }
}

②注册监听器

<!-- 每一个listener标签对应一个监听器配置,若有多个监听器,则配置多个listener标签即可 -->
<listener>
    <!-- 配置监听器指定全类名即可 -->
    <listener-class>com.atguigu.listener.AtguiguListener</listener-class>
</listener>

事件触发过程中控制台日志的打印:

Connected to server [2021-03-20 04:23:20,982] Artifact pro10-listener:war exploded: Artifact is being deployed, please wait… 三月 20, 2021 4:23:21 下午 org.apache.catalina.deploy.WebXml setVersion 警告: Unknown version string [4.0]. Default version will be used. Hello,我是ServletContext,我出生了! servletContext = org.apache.catalina.core.ApplicationContextFacade@6a66017e [2021-03-20 04:23:21,426] Artifact pro10-listener:war exploded: Artifact is deployed successfully [2021-03-20 04:23:21,426] Artifact pro10-listener:war exploded: Deploy took 444 milliseconds 三月 20, 2021 4:23:30 下午 org.apache.catalina.startup.HostConfig deployDirectory 信息: Deploying web application directory D:\software\apache-tomcat-7.0.57\webapps\manager 三月 20, 2021 4:23:31 下午 org.apache.catalina.startup.HostConfig deployDirectory 信息: Deployment of web application directory D:\software\apache-tomcat-7.0.57\webapps\manager has finished in 124 ms [2021-03-20 04:24:06,422] Artifact pro10-listener:war exploded: Artifact is being deployed, please wait… Hello,我是ServletContext,我打算去休息一会儿! Hello,我是ServletContext,我出生了! servletContext = org.apache.catalina.core.ApplicationContextFacade@2a55374c [2021-03-20 04:24:07,115] Artifact pro10-listener:war exploded: Artifact is deployed successfully [2021-03-20 04:24:07,115] Artifact pro10-listener:war exploded: Deploy took 694 milliseconds

6、Ajax笔记

待补充
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值