JavaWebFilter过滤器 的使用

Posted 写Bug的渣渣高

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWebFilter过滤器 的使用相关的知识,希望对你有一定的参考价值。

文章目录


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拦截器各自的执行顺序中的多个过滤器部分

以上是关于JavaWebFilter过滤器 的使用的主要内容,如果未能解决你的问题,请参考以下文章

用jquery做一个大查询和过滤,还是做更多的小查询更好?

如何在过滤/收集代码中使用等待运行代码

rbind tbl 和 df 给出过滤器错误

在 Django 中选择更多过滤器

如何通过后端基于过滤器获取计数

SQL部分解析