JavaWeb三大组件之Filter

news2024/10/7 18:21:01

目录

1、Filter概述

2、Filter快速入门

2.1、开发步骤

2.2、代码演示

3、Filter执行流程​编辑

4、Filter拦截路径 

5、过滤器链

5.1、概述

5.2、代码演示

5.3、问题

6、案例

6.1、需求

6.2、分析

6.3、代码实现

6.3.1、创建Filter

6.3.2、编写逻辑代码

6.3.3、测试并抛出问题

6.3.4、问题分析及解决


1、Filter概述

Filter表示过滤器,是JavaWeb三大组件(Servlet、Filter、Listener)之一。

过滤器可以把资源的请求拦截下来,从而实现一些特殊的功能。

如下图所示,浏览器可以访问服务器上的所有的资源(Servlet、jsp、html等)

而在访问到这些资源之前可以使用过滤器拦截下来,也就是说在访问资源之前会先经过Filter,如下图

拦截器拦截到后可以做什么功能呢?

        过滤器一般完成一些通用的操作

        比如每个资源都要写一些代码完成某个功能,我们总不能在每个资源中写这样的代码吧,而此时我们可以将这些代码写在过滤器中,因为请求每一个资源都要经过过滤器。


我们之前做的品牌数据管理的案例中就已经做了登陆的功能,而如果我们不登录能不能访问到数据呢?我们可以在浏览器直接访问首页 ,可以看到 查询所有 的超链接

当我点击该按钮,居然可以看到品牌的数据

这显然是不合理的。我们希望实现的效果是如果用户登录过了就跳转到数据展示页面;如果用户没有登录就跳转到登陆页面让用户进行登陆,要实现这个效果需要在每一个资源中都写上这段逻辑,而像这种通用的操作,我们就可以放在过滤器中进行实现。这个就是权限控制,以后我们还会进行细粒度权限控制。过滤器还可以做 统一编码处理敏感字符处理 等等…

2、Filter快速入门

2.1、开发步骤

进行Filter开发分成以下三步实现

        定义类,实现Filter接口,并重写其所有方法

import javax.servlet.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebFilter("/*")
public class FilterDemo implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

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

配置Filter拦截资源的路径:在类上定义@WebFilter注解。而注解的value属性值 /* 表示拦截所有的资源

在doFilter方法中输出一句话,并放行

注意:

        上述代码中的chain.doFilter(request, response);就是放行,也就是让其访问本该访问的资源

2.2、代码演示

创建一个项目,项目下有一个hello.jsp页面,项目结构如下:

 pom.xml如下配置文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>filter-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- jsp -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>80</port>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

hello.jsp页面如下

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>hello JSP</h1>
</body>
</html>

启动测试

在浏览器输入 http://localhost/filter-demo/hello.jsp 访问 hello.jsp 页面,这里是可以访问到 hello.jsp 页面内容的。

 注意:

        这里访问时没有输入8080端口是因为我们在pom.xml中修改了端口号,如下所示

 接下来编写过滤器,过滤器是Web三大组件之一,所以我们将filter创建在com.clear.web.filter包下,起名 FilterDemo


@WebFilter("/*")
public class FilterDemo implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("FilterDemo....");


    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

重启启动服务器,再次重新访问 hello.jsp 页面,这次发现页面没有任何效果,但是在 idea 的控制台可以看到如下内容

上述效果说明了 FilterDemo这个过滤器的 doFilter()方法执行了,但是为什么在浏览器上看不到hello.jsp页面的内容呢?

这是因为在doFilter()方法中添加放行的方法才能访问到hello.jsp页面的内容,如下所示

 3、Filter执行流程

 如上图是使用过滤器的流程,我们通过以下问题来研究过滤器的执行流程:

        放行后访问对应资源,资源访问完成后,还会回到Filter中吗?

                从上图就可以看出肯定 会回到Filter

        如果回到Filter中,是重头执行还是执行放行后的逻辑呢?

                如果是重头执行的话,就意味着放行前的逻辑会被执行两次,肯定不会这样设计的;所以访问完资源后,会回到放行后的逻辑,执行该部分代码

通过上述说明,我们可以将Filter执行流程总结如下:

接下来我们通过代码验证一下,在doFilter()方法前后都加上输出语句,如下

 

 同时在 hello.jsp 页面加上输出语句,如下

 执行访问该资源打印的顺序是按照我们标记的标号进行打印的话,说明我们上边总结出来的流程是没有问题的。启动服务器访问 hello.jsp 页面,在控制台打印的内容如下:

以后我们可以将对请求进行处理的代码放在放行之前进行处理,而如果请求完资源后还要对响应的数据进行处理时可以在放行后进行逻辑处理。

4、Filter拦截路径 

拦截路径表示Filter会对请求的哪些资源进行拦截,使用 @WebFilter注解进行配置。如下

@WebFilter("拦截路径")

拦截路径有如下四种配置方式:

        拦截具体的资源:如:/index.jsp:之一访问index.jsp时才会被拦截

        目录拦截:如:/user/*:访问/user下的所有资源都会被拦截

        后缀名拦截:如:*.jsp:访问后缀名为jsp的资源,都会被拦截

        拦截所有:/*:访问所有的资源,都会被拦截

通过上述,可以发现拦截路径的配置方式和Servlet的请求资源路径配置方式一样,但是表示的含义不同。

5、过滤器链

5.1、概述

过滤器链是指在一个Web应用,可以配置多个过滤器,这多个过滤器称为过滤器链。

如下图就是一个过滤器链,我们学习过滤器链主要是学习过滤器链执行的流程

上图中的过滤器链执行顺序如下:

1、执行Filter1的放行前逻辑

2、执行Filter1的放行代码

3、执行Filter2的放行前逻辑

4、执行Filter2的放行代码

5、访问到资源

6、执行Filter1的放行后逻辑

7、执行Filter2的放行后逻辑

以上流程串起来就像一条链子,故称之为过滤器链

5.2、代码演示

编写第一个过滤器FIlterDemo,配置成拦截所有资源


@WebFilter("/*")
public class FilterDemo implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 放行前,对 request数据进行处理
        System.out.println("1、FilterDemo....");
        // 放行
        filterChain.doFilter(servletRequest,servletResponse);
        // 放行后,对 response数据进行处理
        System.out.println("5、FilterDemo....");

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

编写第二个过滤器FilterDemo2,配置成拦截所有

@WebFilter("/*")
public class FilterDemo2 implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("2、FilterDemo....");
        // 放行
        filterChain.doFilter(servletRequest,servletResponse);
        // 放行后,对 response数据进行处理
        System.out.println("4、FilterDemo....");

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

修改hello.jsp页面中脚本的输出语句

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>hello JSP</h1>
    <%
        System.out.println("3、hello jsp");
    %>
</body>
</html>

启动,在浏览器输入 http://localhost/filter-demo/hello.jsp 进行测试,在控制台打印内容如下

 从结果可以看到确实是按照我们之前说的执行流程进行执行的。

5.3、问题

上述代码中为什么先执行 FIlterDemo,后执行FilterDemo2呢?

我们现在使用的是注解配置Filter,而这种配置方式的优先级是按照过滤器类名(字符串)的自然排序

比如有如下两个名称的过滤器 : BFilterDemoAFilterDemo 。那一定是 AFilterDemo 过滤器先执行。

6、案例

6.1、需求

访问服务器资源时,需要先进行登录验证,如果没有登录,则自动跳转到登录页面

6.2、分析

我们要实现该功能是在每一个资源里加入登陆状态校验的代码吗?显然是不需要的,只需要写一个 Filter ,在该过滤器中进行登陆状态校验即可。而在该 Filter 中逻辑如下:

6.3、代码实现

6.3.1、创建Filter

在之前的brand-demo工程创建com.clear.web.filter包,在该包下创建LoginFilter的过滤器


@WebFilter("/*")
public class LoginFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

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

6.3.2、编写逻辑代码

在doFilter()方法中编写登录状态校验的逻辑代码

我们首先需要从 session 对象中获取用户信息,但是 ServletRequest 类型的 requset 对象没有获取 session 对象的方法,所以此时需要将 request对象强转成 HttpServletRequest 对象

HttpServletRequest req = (HttpServletRequest) request;

然后完成以下逻辑:

        获取Session对象

        从Session对象中获取名为 user 的数据

        判断获取的数据是否为null

                如果不是,说明已经登录,放行

                如果是,说明未登录,将提示信息存储到域对象,并跳转至登录页面

代码如下:


@WebFilter("/*")
public class LoginFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

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

        HttpSession session = req.getSession();
        Object user = session.getAttribute("user");
        if (user == null) {
            // 没有登陆,存储提示信息,跳转到登录页面
            req.setAttribute("login_msg","您尚未登录");
            req.getRequestDispatcher("/login.jsp").forward(request, response);
            
        }else {
            // 登录过,放行
            chain.doFilter(request, response);
        }
    }
}

 6.3.3、测试并抛出问题

在浏览器上输入 http://localhost:8080/brand-demo/ ,可以看到如下页面效果

从上面效果可以看出登录页面确实是跳转了,但是登录页面为什么会变成这种效果呢?

6.3.4、问题分析及解决

因为登录页面需要 css/login.css这个文件进行样式渲染,下面是登录页面引入的css文件图解

 而在请求这个css资源时被过滤器拦截,就相当于没有加载到样式文件导致的。解决这个问题,只需要对所以的登陆相关的资源进行放行即可。还有一种情况就是当我没有用户信息时需要进行注册,而注册时也希望被过滤器放行

综上,我们需要在判断session中是否包含用户信息user之前,应该加上对登录及注册相关资源放行的逻辑处理

LoginFilter代码如下如下


@WebFilter("/*")
public class LoginFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

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

        //判断访问资源路径是否和登录注册相关
        //1、在数组中存储登陆和注册相关的资源路径
        String[] urls = {"/login.jsp", "/imgs","/css","/loginServlet",
                "/register.jsp","/registerServlet","/checkCodeServlet"};
        //2、获取当前访问的资源路径
        String url = req.getRequestURL().toString();

        //3、遍历数组,获取到每一个需要放行的资源路径
        for (String u: urls) {
            //4、判断当前访问的资源路径字符串是否包含要放行的的资源路径字符串
            /*
             	比如当前访问的资源路径是  /brand-demo/login.jsp
             	而字符串 /brand-demo/login.jsp 包含了  字符串 /login.jsp ,所以这个字符串就需要放行
             */
            if(url.contains(u)){
                // 放行
                chain.doFilter(request,response);
                return;
            }

        }

        HttpSession session = req.getSession();
        Object user = session.getAttribute("user");
        if (user == null) {
            // 没有登陆,存储提示信息,跳转到登录页面
            req.setAttribute("login_msg", "您尚未登录");
            req.getRequestDispatcher("/login.jsp").forward(request, response);

        } else {
            // 登录过,放行
            chain.doFilter(request, response);
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SuperMap GIS管线数据处理QA

一、数据简介 传统的以二维平面展现网络数据的方式&#xff0c;在一定程度上限制了信息的表达&#xff0c;尤其是在复杂的空间位置关系上。三维网络是对现实中的网络的真实模拟&#xff0c;而非抽象模拟&#xff0c;因此能够全方位的展现信息。   例如&#xff0c;多层结构的…

python期末复习案例

一.条件判断 1. 判断一个数能否同时被3和7整除 and 两者都要为真 2.判断一个数能同时被3或者7整除 但不能同时被3和7整除 ★要使用not 3.输入年份&#xff0c;看是否为闰年 闰年条件&#xff1a;能被4整除但不能被100整除&#xff0c;或者能被四百整除 定义两个变量 保存一个…

leetcode 464. 我能赢吗 官方代码的一步步演进

这里写自定义目录标题题目示例解题优化1 记忆化搜索优化2&#xff1a;使用二进制代替choosable_list计算复杂性题目 在 “100 game” 这个游戏中&#xff0c;两名玩家轮流选择从 1 到 10 的任意整数&#xff0c;累计整数和&#xff0c;先使得累计整数和 达到或超过 100 的玩家…

Kafka - 09 Kafka副本 | Leader选举流程 | Follower故障 | Leader故障

文章目录1. 副本基本信息2. Leader选举流程3. Follower故障4. Leader故障1. 副本基本信息 1&#xff09;Kafka 副本作用&#xff1a;提高数据可靠性。 2&#xff09;Kafka 默认副本 1 个&#xff0c;生产环境一般配置为 2 个&#xff0c;保证数据可靠性&#xff1b;太多副本会…

深度学习网络模型——DenseNet模型详解与代码复现

深度学习网络模型——DenseNet模型详解与代码复现1、DenseNet概述2、DenseNet网络结构1、DenseNet中的DenseBlock模块2、DenseNet中的Transition模块3、DenseNet网络结构参数设置4、实验结果对比1、DenseNet概述 2、DenseNet网络结构 1、DenseNet中的DenseBlock模块 2、DenseNe…

内网穿透:针对小白的VSCode+云服务器+本地Ubuntu搭建GPU云服务器

前言 自己实验室的情况&#xff1a; 实验室拥有自己的GPU集群、工作站使用仅限于线下或者远程向日葵(不稳定、速度慢)拥有自己的廉价cpu轻量云服务器&#xff08;阿里云服务器(2G2*cpu)&#xff0c;大概40左右一年&#xff09; 平时出差、在宿舍等需要远程操作&#xff0c;向…

Python学习笔记-数字类型

目录 1. 数字类型 1.1 整型 1.2 浮点数 1.3 复数 1.4 布尔类型 2. 常用内置数值计算函数库 3. 随机数函数 本文记录python中的基本数字类型信息&#xff0c;以及一些其他的相关知识点。 1. 数字类型 python中用于标识数字或者数值的数据类型&#xff0c;主要有如下分类…

​鸽群卫星(Flock)​介绍

鸽群卫星&#xff08;Flock&#xff09;是美国Planet公司[1]研制的3U遥感立方体卫星星座&#xff0c;单颗卫星重约5kg&#xff0c;也被称为“鸽子”&#xff08;Dove&#xff09;。鸽群星座主要有两类轨道&#xff1a;空际空间站释放420km高、52度倾角轨道&#xff08;ISS&…

R语言基于决策树的银行信贷风险预警模型

引言 我国经济高速发展&#xff0c;个人信贷业务也随着快速发展&#xff0c;而个人信贷业务对提高内需&#xff0c;促进消费也有拉动作用。有正必有反&#xff0c;在个人信贷业务规模不断扩大的同时&#xff0c;信贷的违约等风险问题也日益突出&#xff0c;一定程度上制约着我…

力扣(LeetCode)115. 不同的子序列(C++)

动态规划 状态转移方程 f[i,j]{f[i−1,j]f[i−1,j]f[i−1,j−1]if s[i]t[j]f[i,j]\begin{cases} f[i-1,j]\\ f[i-1,j]f[i-1,j-1]&\text{if } s[i]t[j] \end{cases}f[i,j]{f[i−1,j]f[i−1,j]f[i−1,j−1]​if s[i]t[j]​ 无论选不选 s[i]s[i]s[i] &#xff0c; f[i][j]f[i…

解决报错:fatal: in unpopulated submodule *

目录 问题 解决 问题 今天想把两个 Git 工程合并成一个工程&#xff0c;尽管已经将其中一个工程的 .git 目录删除了&#xff0c;但是在合并提交时还是遇到了一个和子模块相关的报错&#xff0c;具体报错信息如下&#xff1a; fatal: in unpopulated submodule * 报错截图如下…

【iMessage苹果相册日历推位置推送】软件安装deviceToken是由APNs生成的

推荐内容IMESSGAE相关 作者推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者推荐内容3.日历推 *** 点击即可查看作者要求内容信息作者推荐…

SpringBoot+html+vue模板开发

除了对某个表基本的增删改查以外&#xff0c;可能需要额外的增加操作&#xff0c;这里是通过按钮来实现的 1、新增一个测试按钮 <el-button type"primary" class"butT" click"test()">测试</el-button> 2、这个按钮绑定一个方法t…

Android 创建桌面组件Widget——构建应用微件(二)

Android 创建桌面组件Widget——构建应用微件&#xff08;二&#xff09;Android 创建桌面组件Widget——构建应用微件&#xff08;二&#xff09;概览使用 AppWidgetProvider 类接收应用微件广播 Intent固定应用微件设置预览图片完整代码Android 创建桌面组件Widget——构建应…

Spark学习(7)-SparkSQL函数定义

1 SparkSQL 定义UDF函数 目前在SparkSQL中&#xff0c;仅仅支持UDF和UDAF函数&#xff0c;python仅支持UDF。 1.1 定义方式 定义方式有两种&#xff1a; sparksession.udf.register() 注册的UDF可以用于DSL和SQL&#xff0c;返回值用于DSL风格&#xff0c;传参内的名字用于SQ…

如何在Odoo中添加水印?

为了防止信息的泄露&#xff0c;水印作为一种防泄密的方式&#xff0c;被使用的频率越来越高。 那么在Odoo中&#xff0c;如何添加水印呢&#xff1f;其实添加的方法有很多&#xff0c;如利用svg生成背景图&#xff0c;重复的dom元素覆盖等等。 本文主要讲解利用canvas输出背…

不懂单链表? 这篇文章就帮你搞明白

坚持看完&#xff0c;结尾有思维导图总结 链表对指针的操作要求不低链表的概念链表的特性链表的功能(最重要)定义和初始化头插头删细节说明尾插尾删寻找链表元素与打印链表在 某位置后插入删除在某位置的插入删除销毁链表链表的概念 什么是链表 官方概念&#xff1a;链表是一种…

链表(1)

我们以前学过的线性数据结构底层原理都是依托静态数组来实现的&#xff0c;今天我们讲学习一个最简单的动态数据结构---->链表&#xff01; 掌握链表有助于学习更加复杂的数据结构&#xff0c;例如&#xff1a;二叉树、trie 链表的优点是不需要处理固定的问题&#xff0c;…

mavon-editor的使用

vue3vitets下安装mavon-editor 3.0.0-beta版本&#xff0c;效果如下&#xff1a; 安装 //引入样式 import mavon-editor/dist/css/index.css; import mavonEditor from mavon-editor; app.use(router).use(mavonEditor).mount(#app);<template><div class"rich…

zabbix主动监控和被动监控

目录 一、环境准备 1、搭建zabbix基础环境 二、主动监控与被动监控介绍 三、设置客户端为主动监控 1、给web2主机安装zabbix_agent 2、修改主动监控配置 四、设置zabbix管理端主动监控 1、克隆模板 2、给目标主机绑定主动监控模板 3、查看主动监控的数据 一、环境准备…