Java教程

【JavaWeb】Filter过滤器 的使用

本文主要是介绍【JavaWeb】Filter过滤器 的使用,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

    • Fiter是什么:
    • Filter基本配置
      • 四种匹配模式
            • 1. 精确匹配
            • 2. 模糊匹配
            • 3. 扩展名匹配
            • 4. 匹配Servlet名称
    • Filter的基本作用
    • 用 Filter 解决中文乱码问题案例:
        • 一个小问题:用户发送了request,被filter拦住设置了字符集后,Servlet为什么能通过request得到不乱码的汉字内容,这是为什么
    • Filter生命周期
    • 如果有多个Filter,构成了过滤器链,那么其各自的执行顺序又是怎么样的


Fiter是什么:

Filter:一个实现了特殊接口(Filter)的Java类. 实现对请求资源(jsp,servlet,html,)的过滤的功能. 过滤器是一个运行在服务器的程序, 优先于请求资源(Servlet或者jsp,html)之前执行. 过滤器是javaweb技术中最为实用的技术之一

简而言之,就是在Servlet之前接收到用户发送的request,然后我们可以检查参数,对编码等等进行初始化的设置,比如判断用户是否有权限查看该网站的该网址下的内容…

Filter基本配置

配置Filter需要在 web.xml中声明,下面是一个模板

    <filter>
        <filter-name>Filter01</filter-name>
        <filter-class>com.example.demo.Filter01</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter01</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

代表作为开发者,我们创建这个Filter的全类名,目的是在运行web应用的时候,web应用容器可以发现这个Filter
代表该Filter 所过滤的网址。什么意思呢,还记得我们创建Servlet需要写的声明和这个很类似吗

对于

    <servlet>
        <servlet-name>Servlet1</servlet-name>
        <servlet-class>com.example.demo.Servlet1</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Servlet1</servlet-name>
        <url-pattern>/Servlet</url-pattern>
    </servlet-mapping>

对于上面的代码,表示用户创建web应用的Servlet的全类名
而代表其所对应的url,从上面这个模板可以看到它的,其对应的完整url地址应该是服务器url+标签内的值
在这里插入图片描述那么结果应该是http://localhost:8080/demo_war/Servlet1
那么再回到上面说到的,每个Setvlet都有一个对应的url,而Filter它的代表的是所过滤的url,其完整地址也是服务器的URL+此标签的值。

四种匹配模式

Filter并不是专用于过滤某个Servlet,我们可以通过配置,来自定义其所拦截的请求,联系实际。比如说淘宝,你打开淘宝网站,并没有强制你不登陆无法访问商品,而是你购买的时候必须要登录。当用户仅仅是浏览时,通过过滤器可以被放行,但是用户没有登录想要购买时,就无法放行此请求给支付模块,而是强制用户登录才能进入支付模块

1. 精确匹配

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

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

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

上述例子表示要拦截映射路径为/demo01的这个资源

2. 模糊匹配

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

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

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

    <!-- 模糊匹配:前杠后星 -->
    <!--
        /user/demo01
        /user/demo02
        /user/demo03
		/demo04
    -->
    <url-pattern>/user/*</url-pattern>
</filter-mapping>

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

3. 扩展名匹配
<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>

上述例子表示拦截所有以.png结尾的请求

4. 匹配Servlet名称
<filter-mapping>
    <filter-name>Target05Filter</filter-name>

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

Filter的基本作用

Filter的作用是对目标资源(Servlet,jsp)进行过滤,其应用场景有: 登录权限检查,解决网站乱码,过滤敏感字符等等

例如:如果一个电商web,我们想使用加入购物车功能必须要判断用户是否登录,如果没有filter的话,就需要在servlet中进行大量的无用的测试代码,非常影响效率。

这时fitler 就出现了,我们在filter-mapping中的url-partern中指定要过滤的文件(可以多个url-partern),设置后,那么在访问该servlet之前,就需要通过一个filter的检测,我们可以在该处检测一些变量和权限,如果可通过就使用chain.doFilter(req,res)


用 Filter 解决中文乱码问题案例:

实现请求在到底目标Servlet之前解决请求参数乱码问题

  1. 创建一个Servlet,并在web.xml中编写servlet配置
    假如是右键自动生成的Servlet,则不用手动在 web.xml中配置
<servlet>
    <servlet-name>servletDemo01</servlet-name>
    <servlet-class>com.ggzx.ServletDemo01</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servletDemo01</servlet-name>
    <!--这里是-->
    <url-pattern>/ServletDemo01</url-pattern>
</servlet-mapping>
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 日期2022-2-6 09:28
 * @author ggzx
 */
 @WebServlet(name = "ServletDemo01", value = "/hello-servlet")
public class ServletDemo01 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        System.out.println("ServletDemo01接收到了一个请求..."+username);
    }
}

前端界面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <form action="hello-servlet" method="post">
        用户名<input type="text" name="username"/><br/>
        <input type="submit"/>
    </form>
</body>
</html>

现在来看没有使用Filter来设置字符集的情况
在这里插入图片描述在这里插入图片描述 在这里插入图片描述在这里插入图片描述
这里是Servlet直接接收到的参数,可以看见,在接收到汉字的参数,其实是有问题的。
下面来配置使用Filter:
web.xml

    <filter>
        <filter-name>Filter01</filter-name>
        <filter-class>com.example.demo.Filter01</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter01</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
public class Filter01 implements Filter {
    @Override
    public void destroy() {
        
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //解决请求参数的乱码
        HttpServletRequest request = (HttpServletRequest) req;
        request.setCharacterEncoding("UTF-8");

        //每次有请求被当前filter接收到的时候,就会执行doFilter进行过滤处理
        System.out.println("EncodingFilter接收到了一个请求...");

        //这句代码表示放行
        chain.doFilter(req, resp);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        
    }
}

我们配置的Filter会自动过滤web.xml中/*所表示的路径下的所有Servlet。当用户发送表单后,首先被Filter拦截,在执行了解决请求参数乱码的问题后再将请求放给Servlet,再使用了这样一个设置编码的Filter之后,就不需要在每个Servlet中设置编码了。

一个小问题:用户发送了request,被filter拦住设置了字符集后,Servlet为什么能通过request得到不乱码的汉字内容,这是为什么

来看一下Servlet中的doget方法

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        System.out.println("ServletDemo01接收到了一个请求..."+username);
    }

来看一下Filter中的doget方法

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

可以看见,他们两个同名的参数(类型不同)request,这是用户传过来的请求,里面包含了很多的用户信息,我们在Filter中设置的request和Servlet的 request 可能继承同一个接口,或者这两个接口就有继承关系
在这里插入图片描述通过查找源码可以看见,HttpServletRequest 继承 ServletRequest,用户发来的 request 经过 Filter 时,继承的是父接口 ServletRequest,在Filter之中对 request 进行处理后,进入到 Servlet 时,继承的接口是 HttpServletRequest ,子接口的功能肯定是多于父接口的,所以在上面的 Filter 的 doFilter 中, HttpServletRequest request = (HttpServletRequest) req;
执行了这段代码,直接将功能少的 ServletRequest 强转成了功能更多的HttpServletRequest ,然后再执行 chain.doFilter(req, resp);
执行这段代码之后,就会将request请求发给Servlet

总结这个问题:即filter和servlet方法中的 req都是同一个对象。Filter中的请求对象是ServletRequest对象,而Servelet中的是HttpServletRequset对象,说明在过滤后发生了强转,其中HttpServletRequest转换成ServletRequest对象,子接口HttpServletRequest比父接口ServletRequest,功能更多,所以强转的时候不会有问题

Filter生命周期

生命周期阶段执行时机生命周期方法
创建对象Web应用启动时init方法,通常在该方法中做初始化工作
拦截请求接收到匹配的请求doFilter方法,通常在该方法中执行拦截过滤
销毁Web应用卸载前destroy方法,通常在该方法中执行资源释放

如果有多个Filter,构成了过滤器链,那么其各自的执行顺序又是怎么样的

此部分内容参考【SpringMVC】Filter过滤器、AOP切面类、Interceptors拦截器各自的执行顺序中的多个过滤器部分

这篇关于【JavaWeb】Filter过滤器 的使用的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!