javaweb基础:过滤器Filter

现在聊一下javaweb三大核心(servlet 程序 Listener 监听器 Filter过滤器)之一的过滤器。

过滤器本身也是javaee中的一个接口,而其主要作用就是:拦截请求,过滤响应。

用一个不十分恰当的例子来说,过滤器像是净水器中过滤芯片,水过滤片的时候都会被拦住,然后将水中杂质给阻挡到出水口,而纯净的水可以通过。

所以网站很多时候通过过滤器进行权限检查比如最常见的购物网站,如果不登陆就无法打开购物车等。

产生原因

这个就有一个问题,不是jsp支持编程脚本吗,我直接如下判断不就行了:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
    <title>Title</title>
</head>
<body>
 <%
  String name= (String) session.getAttribute("username");
  if (name!=null && name.equals("")){
        request.getRequestDispatcher("/资源路径").forward(request,response);
  }
 %>
</body>

</html>

完美解决了问题了,这样干嘛还需要写一个过滤器,还需与实现过滤器接口,然后创建一个java文件呢。但是不要忽略一点,对于忘了url请求不单单是jsp,比如图片,还有pdf等格式,你如何在其内容中写java编程呢。

现在又有一个大胆的想法了,既然如此那我可以在servlet中判断一下不久可以了。还是这个例子似乎解决如下:

@WebServlet("/test")
public class test extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name= (String) req.getSession().getAttribute("username");
        if (name!=null && name.equals("")){
//            通过service服务逻辑得到资源
        }else{
            req.getRequestDispatcher("/登录路径").forward(req,resp);
        }
    }

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

虽然可以解决问题,但是有一个问题,那就是需要在每个servlet中写一遍是不是很麻烦,当然还有一种写法,就是写一个baseservlet,在这个方法里面写,然后其它的方法继承这个方法:

baseservlet类文件如下:

public class baseservlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        url 对方法进行重新命名,而不适用dopsost或者doget
        String action = req.getParameter("action");
        try {
            String name = (String) req.getSession().getAttribute("username");
            if (name != null && name.equals("")) {
                Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
                method.invoke(this, req, resp);
            } else {
                req.getRequestDispatcher("/登录路径").forward(req, resp);
            }

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }

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

    }
}

然后写一个继承类即可不过这样写也有问题,虽然可以解决问题,但是有时候发现这个过滤会有大量需求,那么为什么不提炼处理一个类,然后直接调用即可,没必要每次都手写一个,而且还有一个就是对于一些拦截的路径也可以使用类似正则表达式的方式拦截。

所以过滤器这个东西的意义就有了,比如在配置的时候:

    <filter>
        <filter-name>testFilters</filter-name>
        <filter-class>com.test.testFilters</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>testFilters</filter-name>
<!--        这个是拦截本项目下的所有请求  , /test/* 表示拦截 项目/test  路径的所有请求-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

初体验

先看一个资源:

在这里插入图片描述

然后写一个过滤器,然后配置:

package com.test;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

public class testFilters 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 httprequest= (HttpServletRequest) request;
        String name = (String) httprequest.getSession().getAttribute("username");
        System.out.println(name);
        if (name != null && !(name.equals(""))) {
            chain.doFilter(request,response);
        } else {
            response.setContentType("text/html; charset=UTF-8");
            response.getWriter().write("请登录才行");
        }
    }
}

然后进行配置:

   <filter>
        <filter-name>testFilters</filter-name>
        <filter-class>com.test.testFilters</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>testFilters</filter-name>
<!--        这个是拦截本项目下的所有请求  , /test 表示拦截 项目/test  路径的所有请求-->
        <url-pattern>/jpg/*</url-pattern>
    </filter-mapping>

然后访问地址:http://localhost:8080/javaweb/jpg/gu.png(这是我的地址,自己使用自己的地址)

结果如下:

在这里插入图片描述

如果再写一个log.jsp,只会简单将其赋值一个session中的属性值而已

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
    <title>Title</title>
</head>
<body>
 <%
// 我们直接通过脚本赋值给session属性
  session.setAttribute("username","张三");
 %>
</body>
</html>

然后先访问:http://localhost:8080/javaweb/test.jsp

然后在访问:http://localhost:8080/javaweb/jpg/gu.png

在这里插入图片描述

所以可以看出过滤器的作用了,其就是对请求的路径进行一次筛选,符合的就让进去,不符合的就拒绝。(感觉像火车站的是检票员)

过滤器的生命周期

其实和servlet很相似,现在说一下其生命周期:

先看一下过滤器有什么方法:

在这里插入图片描述

然后如下尝试:

public class testFilters implements Filter {
    public testFilters(){
        System.out.println("构造方法");
    }
    public void init(FilterConfig config) throws ServletException {
        System.out.println("初始化了");
    }

    public void destroy() {
        System.out.println("销毁了");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        System.out.println("过滤器启动了");
    }
}

然后启动tomcat后:

在这里插入图片描述

然后访问(因为配置的还是前面演示的配置):http://localhost:8080/javaweb/jpg/gu.png 多访问几次

在这里插入图片描述

关闭tomcat:

在这里插入图片描述

所以总结:

  • 第一步: 构造方法(这个不用多说,毕竟为面向对象的java)
  • 第二步:初始化方法(init), 这前俩步在web工程启动的时候就执行了。
  • 第三步:过滤方式(doFilter): 每次拦截的请求的时候就会执行。
  • 第四步:销毁(destroy):停止web工程的时候就会执行。

FilterConfig

这个看名字就知道,是过滤器的配置对象类,有点像是servletConfig对象相似,只不过一个是服务于servlet一个服务于filter。

而且FilterConfig也是在Filter创建的时候同时就会创建一个FilterConfig类的,这里包含了Filter配置文件的配置信息。

看官网文档:

在这里插入图片描述

而创建的时候,都是在filter中初始化init方法中得到Filterconfig:

public void init(FilterConfig config) throws ServletException {
       
    }

对于FilterConfig的方法然后如下尝试:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextname</param-name>
        <param-value>全局数据</param-value>
    </context-param>
    <filter>
        <filter-name>testFilters</filter-name>
        <filter-class>com.test.testFilters</filter-class>
        <init-param>
            <param-name>test</param-name>
            <param-value>小三</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>testFilters</filter-name>
<!--        这个是拦截本项目下的所有请求  , /test 表示拦截 项目/test  路径的所有请求-->
        <url-pattern>/jpg/*</url-pattern>
    </filter-mapping>
</web-app>   

然后看一下过滤器:

public class testFilters implements Filter {


    public void init(FilterConfig config) throws ServletException {
        System.out.println("getFilterName()  初始化了"+config.getFilterName());
        System.out.println("getServletContext()初始化了"+config.getServletContext().getInitParameter("contextname"));
        System.out.println("getInitParameter() 初始化了"+config.getInitParameter("test"));
        System.out.println("getInitParameterNames()初始化了"+config.getInitParameterNames());
    }

    public void destroy() {
 
    }

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

在这里插入图片描述

其实看起和servletconfig很相似,也就是可以得到配置文件web.xml配置的信息。

多个过滤器套用

其实有时候过滤器不是单独一个使用,而是可以套用的,为什么这样说呢?看下官网文档:

在这里插入图片描述

可以看出过滤器器首先会查看是否有下一个过滤器,如果没有再返回过滤器判断之后的资源。先不说这个而是做一个测试。

首先写两个过滤器:

testFilters.java

public class testFilters implements Filter {


    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
        System.out.println("销毁了");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
     System.out.println("test_filter.......前");
     chain.doFilter(request,response);
     System.out.println("test_filter.......后");
    }
}

testFilters1.java

public class testFilters1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("test_filter111111.......前");
        chain.doFilter(request,response);
        System.out.println("test_filter1111.......后");
    }

    @Override
    public void destroy() {

    }
}

不过先说一下在配置的web.xml :

先配置 testFilterstestFilters1前面。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <filter>
        <filter-name>testFilters</filter-name>
        <filter-class>com.test.testFilters</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>testFilters</filter-name>
<!--        这个是拦截本项目下的所有请求  , /test 表示拦截 项目/test  路径的所有请求-->
        <url-pattern>/jpg/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>testFilters1</filter-name>
        <filter-class>com.test.testFilters1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>testFilters1</filter-name>
        <!--        这个是拦截本项目下的所有请求  , /test 表示拦截 项目/test  路径的所有请求-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

结果如下:

在这里插入图片描述

如果先配置 testFilters1testFilters前面。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    
      <filter>
        <filter-name>testFilters1</filter-name>
        <filter-class>com.test.testFilters1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>testFilters1</filter-name>
        <!--        这个是拦截本项目下的所有请求  , /test 表示拦截 项目/test  路径的所有请求-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    
    <filter>
        <filter-name>testFilters</filter-name>
        <filter-class>com.test.testFilters</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>testFilters</filter-name>
<!--        这个是拦截本项目下的所有请求  , /test 表示拦截 项目/test  路径的所有请求-->
        <url-pattern>/jpg/*</url-pattern>
    </filter-mapping>

</web-app>

在这里插入图片描述

其实可以看出,在使用多个过滤器的时候,谁在前是根据web.xml配置文件中<filter-mapping\>前就先运行。

而根据 testFilterstestFilters1前面,画一个图:

在这里插入图片描述

所以总结:

  • 执行下一个filter过滤器(如果有filter)
  • 执行目标资源(如果没有filter)

同时还有一个补充点那就是:

  • 所有的filter和目标资源默认都是执行在同一个线程中。
  • 多个filter共同执行的时候,他们使用的是同一个request对象。

路径配置补充

  • 精确匹配

    <url-pattern>/jpg/gu.png</url-pattern>
    

    只会过滤http://localhost:8080/javaweb/jpg/gu.png,其它的地址不会过滤。

  • 目标匹配

    <url-pattern>/jpg/*</url-pattern>
    

    这个会过滤:以 http://localhost:8080/javaweb/jpg/ 开始的所有url ,其它的地址不会过滤。

  • 后缀匹配

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

    过滤以do结尾的请求地址,还有一点要注意那就是在* 前不要有/.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340