Filter过滤器(超详细)

1.Filter ?什么是过滤器

  1. Filter 过滤器它是 JavaWeb 的三大组件之一。
    三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器
  2. Filter 过滤器它是 JavaEE 的规范。也就是接口
  3. Filter 过滤器它的作用是:拦截请求,过滤响应。

拦截请求常见的应用场景有:
1.权限检查 2.日记操作 3.事务管理 ……等等

2.Filter 初体验

要求:在你的 web 工程下,有一个 admin 目录。这个 admin 目录下的所有资源(html 页面、jpg 图片、jsp 文件…等等)都必须是用户登录之后才允许访问。

思考:根据之前我们学过内容。我们知道,用户登录之后都会把用户登录的信息保存到 Session 域中。所以要检查用户是否登录,可以判断 Session 中否包含有用户登录的信息,即可!!!

a.jsp:

<body>
    <%
        Object user = session.getAttribute("user");
        // 如果 user = null; 说明 user 还没有登陆
        if (user == null) {
            request.getRequestDispatcher("/login.jsp").forward(request,response);
            return;     // 一般请求转发后,就不允许再执行任何代码,这里就直接return了
        }
    %>
    我是 a.jsp 文件
</body>

但是在 html 页面当中应该怎么写呢? 需要使用 Filter 过滤器

Filter 的工作流程图:

在这里插入图片描述

Filter 过滤器的使用步骤:

​ 1.编写一个类去实现 Filter 接口
​ 2.实现过滤方法 doFilter()
​ 3.到 web.xml 中去配置 Filter 的拦截路径

AdminFilter.java(继承了Filter类):

/**
 * doFilter 方法,专门用来拦截请求,可以做权限检查
 * @param servletRequest
 * @param servletResponse
 * @param filterChain
 * @throws IOException
 * @throws ServletException
 */
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    HttpSession session = httpServletRequest.getSession();
    Object user = session.getAttribute("user");
    // 如果 user = null; 说明 user 还没有登陆
    if (user == null) {
    
    
        httpServletRequest.getRequestDispatcher("/login.jsp").forward(httpServletRequest,servletResponse);
        return;     // 一般请求转发后,就不允许再执行任何代码,这里就直接return了
    } else {
    
    
        // 让程序继续往下访问用户的目标资源
        filterChain.doFilter(servletRequest,servletResponse);
    }
}

这时候已经有权限检查代码了,但是还不知道要去哪检查,这时候需要去 xml 配置一下检查什么。

<!--filter标签用于配置一个Filter过滤器-->
<filter>
    <!--给 filter 起一个别名-->
    <filter-name>Adminfilter</filter-name>
    <!--配置 filter 全类名-->
    <filter-class>com.filter.AdminFilter</filter-class>
</filter>
<!--配置 filter 过滤器的拦截路径-->
<filter-mapping>
    <!--表示当前的拦截路径给哪个filter过滤器使用-->
    <filter-name>Adminfilter</filter-name>
    <!--配置拦截路径
    / 表示请求地址为: http://ip:port/工程路径/ 映射到 IDEA 的 web 目录
    /admin/* 表示请求地址为 http://ip:port/工程路径/admin/*  (admin 下的全部)
    -->
    <url-pattern>/admin/*</url-pattern>
</filter-mapping>

完整的用户登录和权限检查:

login.jsp:

<body>
    这是登陆页面:login.jsp 页面 <br>
    <form action="http://localhost:8080/15_filter/loginServlet" method="get">
        用户名:<input type="text" name="username"/> <br>
        密码:<input type="password" name="password"/> <br>
        <input type="submit" />
    </form>
</body>

LoginServlet.java:

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
    resp.setContentType("text/html; charset=UTF-8");    //解决响应乱码

    String username = req.getParameter("username");
    String password = req.getParameter("password");
    if ("wzg168".equals(username) && "123456".equals(password)) {
    
    
        req.getSession().setAttribute("user",username);
        resp.getWriter().write("登录 成功!!!");
    } else {
    
    
        req.getRequestDispatcher("/login.jsp").forward(req,resp);
    }
}

3.Filter 的生命周期

Filter 的生命周期包含几个方法

  1. 构造器方法

  2. init 初始化方法
    第 1,2 步,在 web 工程启动的时候执行(Filter 已经创建)
    在这里插入图片描述

  3. doFilter 过滤方法
    第 3 步,每次拦截到请求,就会执行(访问 admin 目录下的 a.jsp 页面,访问一次,拦截一次请求)
    在这里插入图片描述

  4. destroy 销毁
    第 4 步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)
    在这里插入图片描述

4.FilterConfig 类

FilterConfig 类见名知义,它是 Filter 过滤器的配置文件类。
Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置息。

FilterConfig 类的作用是获取 filter 过滤器的配置内容

  1. 获取 Filter 的名称 filter-name 的内容
  2. 获取在 Filter 中 wen.xml 配置的 init-param 初始化参数
  3. 获取 ServletContext 对象
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    
        System.out.println("2.Filter 初始化方法 init(FilterConfig filterConfig)");

//        1. 获取 Filter 的名称 filter-name 的内容 (web-xml 中配置的名称)
        System.out.println("filter-name:" + filterConfig.getFilterName());
//        2. 获取在 web.xml 中配置的 init-param 初始化参数
        System.out.println("初始化参数username的值是:" + filterConfig.getInitParameter("username"));
        System.out.println("初始化参数url的值是:" + filterConfig.getInitParameter("url"));
//        3. 获取 ServletContext 对象
        System.out.println(filterConfig.getServletContext());

    }

5.FilterChain 过滤器链

Filter 过滤器
Chain 链,链条
FilterChain 就是过滤器链(多个过滤器如何一起工作)

FilterChain.doFilter() 方法的作用:

​ 1.执行下一个Filter过滤器(如果有Filter)
​ 2.执行目标资源

Filter过滤器的执行细节:

在这里插入图片描述

Filter1.java:

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    
    System.out.println("Filter1前置代码");
    filterChain.doFilter(servletRequest,servletResponse);
    System.out.println("Filter1后置代码");
}

Filter2.java:

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    
    System.out.println("Filter2前置代码");
    filterChain.doFilter(servletRequest,servletResponse);
    System.out.println("Filter2后置代码");
}

target.jsp:

<body>
    <%
        System.out.println("target.jsp页面执行了");
    %>
</body>

web.xml:

<filter>
    <filter-name>Filter1</filter-name>
    <filter-class>com.filter.Filter1</filter-class>
</filter>
<filter-mapping>
    <filter-name>Filter1</filter-name>
    <url-pattern>/target.jsp</url-pattern>
</filter-mapping>
<filter>
    <filter-name>Filter2</filter-name>
    <filter-class>com.filter.Filter2</filter-class>
</filter>
<filter-mapping>
    <filter-name>Filter2</filter-name>
    <url-pattern>/target.jsp</url-pattern>
</filter-mapping>

访问 target.jsp:
在这里插入图片描述

可见其执行顺序。

另外,要是在 xml 中,把 Filter2 放在 Filter1 上面,就会先执行 Filter2,再执行 Filter1。也就是说:在多个 Filter 过滤器执行的时候,他们的优先顺序是由他们在 web.xml 中从上到下配置的顺序决定的!

补充:
多个Filter过滤器执行的特点:

  1. 所有filter和目标资源默认都执行同一个线程中
  2. 多个Filter过滤器同时执行的时候,他们都要使用同一个Request对象

补充1演示:在 Filter1 和 Filter2 的 filterChain.doFilter(servletRequest,servletResponse); 的前后,都使用 Thread.currentThread().getName() 获取线程名,另外 target.jsp 页面中也使用 Thread.currentThread().getName() 获取线程名,运行结果显示:

在这里插入图片描述

访问:http://localhost:8080/15_filter/target.jsp
结果显示,线程相同。

补充2演示:在 Filter1 和 Filter2 的 filterChain.doFilter(servletRequest,servletResponse); 的前后,都使用servletRequest.getParameter(“username”) 获取 request 对象的 name,target.jsp 中使用 request.getParameter(“username”) 获取 request 对象的 name,运行结果显示:
在这里插入图片描述

访问:http://localhost:8080/15_filter/target.jsp?username=12345
结果显示, request 对象相同。

6.Filter 的拦截路径

–精确匹配

<filter-mapping>
    <filter-name>Filter2</filter-name>
    <url-pattern>/target.jsp</url-pattern>  <!--精确匹配-->
</filter-mapping>

以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/target.jsp

–目录匹配

<filter-mapping>
    <filter-name>Adminfilter</filter-name>
    <url-pattern>/admin/*</url-pattern> <!--目录匹配-->
</filter-mapping>

以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/admin/*

–后缀名匹配

<filter-mapping>
    <filter-name>Filter2</filter-name>
    <url-pattern>*.html</url-pattern>  <!--后缀名匹配-->
</filter-mapping>

以上配置的路径,表示请求地址必须以.html 结尾才会拦截到

<filter-mapping>
    <filter-name>Filter2</filter-name>
    <url-pattern>*.do</url-pattern>  <!--后缀名匹配-->
</filter-mapping>

以上配置的路径,表示请求地址必须以.do 结尾才会拦截到

<filter-mapping>
    <filter-name>Filter2</filter-name>
    <url-pattern>*.action</url-pattern>  <!--后缀名匹配-->
</filter-mapping>

以上配置的路径,表示请求地址必须以.action 结尾才会拦截到

<filter-name>Filter2</filter-name>
<url-pattern>*.do</url-pattern>  <!--后缀名匹配-->
```

以上配置的路径,表示请求地址必须以.do 结尾才会拦截到

<filter-mapping>
    <filter-name>Filter2</filter-name>
    <url-pattern>*.action</url-pattern>  <!--后缀名匹配-->
</filter-mapping>

以上配置的路径,表示请求地址必须以.action 结尾才会拦截到

Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在(只看后缀名是否等于,不关心后缀名在现实中是否真的存在)!!!

猜你喜欢

转载自blog.csdn.net/weixin_45024585/article/details/112749271