Servlet的过滤器

文章介绍了如何使用JavaServlet中的过滤器(Filter)进行登录验证和资源拦截。通过配置LoginCheckServlet处理登录请求,ManageFilter实现对/manage/*路径的过滤,检查用户是否已登录。过滤器的生命周期包括初始化、执行doFilter方法和销毁。此外,还讨论了FilterChain的概念,展示多个过滤器按顺序执行以及如何形成过滤器链。
摘要由CSDN通过智能技术生成

过滤器:

  • 使用传统的方式需要在每个页面进行验证
  • 造成代码的冗余功能重复麻烦
  • 过滤器【统计进行验证、鉴权、日志、事务】拦截请求、过滤响应

配置一个Servlet

package com.sparrow.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author: 诉衷情の麻雀
 * @Description: TODO
 * @DateTime: 2023/7/18 21:02
 **/
public class LoginCheckServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if("123456".equals(password)){
            req.getSession().setAttribute("username",username);
            req.getRequestDispatcher("/manage/admin.jsp").forward(req, resp);
        }else {
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        }
        System.out.println("LoginCheckServlet被调用了..");
    }
}

配置过滤器

public class ManageFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //当fTomcat创建filter后就会调用该方法,进行初始化
        System.out.println("ManageFilter init被调用...");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //每次调用该filter doFilter方法就会被调用
        System.out.println("ManageFilter doFilter被调用...");
        //在调用过滤器前,request对象已经被创建并封装
        //所以我们这里可以通过ServletRequest获取很多信息,比如访问url,session
        //比如访问的参数...就可以做事务管理 数据获取 日志管理等
        HttpSession session = ((HttpServletRequest) servletRequest).getSession();
        if (session.getAttribute("username") != null) {
            filterChain.doFilter(servletRequest, servletResponse);
        }else { //说明没有登录过..回到登录页面
            servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest, servletResponse);
        }
        filterChain.doFilter(servletRequest,servletResponse);
    }

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

在web目录下创建login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>管理后台登录</title>
</head>
<body>
<h1>管理后台登录</h1>
<form action="<%=request.getContextPath()%>/loginCheckServlet" method="post">
    用户名: <input type="text" name="username"/><br/><br/>
    密 码: <input type="password" name="password"><br/><br/>
    <input type="submit" value="用户登录"/>
</form>
</body>
</html>

在web目录下创建manage目录,在目录下创建admin.jsp再放一张图片

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>后台管理</title>
    <base href="<%=request.getContextPath()%>/manage/"/>
</head>
<body>
<h1>后台管理</h1>
<a href="#">用户列表</a>||<a href="#">添加用户</a>||<a href="#">删除用户</a>
<hr/>
<img src="3.png " height="300"/>
</body>
</html>

在这里插入图片描述

web.xml

    <!--Filter一般配置在最前面
    1.由tomcat管理和维护
    2.url-pattern就是当前请求的url 匹配的时候就会调用filter
    3./manage/* 第一个 / 解析成HTTP://ip:port/工程路径
    4.完整的路径使http://ip:port/工程路径/manage* 当请求的资源url满足该条件时就会调用filter
    -->
    <filter>
        <filter-name>ManageFilter</filter-name>
        <filter-class>com.sparrow.filter.ManageFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ManageFilter</filter-name>
        <url-pattern>/manage/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>LoginCheckServlet</servlet-name>
        <servlet-class>com.sparrow.servlet.LoginCheckServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginCheckServlet</servlet-name>
        <url-pattern>/loginCheckServlet</url-pattern>
    </servlet-mapping>

在这里插入图片描述
在这里插入图片描述

Filter过滤器url-pattern

  1. url-pattern:Filter的拦截路径,即浏览器在请求什么位置的资源时,过滤器会进行拦截过滤
  2. 精准匹配<url-pattern>/a.jsp</url-pattern>对应的请求地址http://ip[域名]:port/工程路径/a.jsp会拦截
  3. 目录匹配<url-pattern>/manage/*</url-pattern> 对应的请求地址http://ip[域名]:port/工程路径/manage/xx,即web工程manage目录下所有资源会拦截
  4. 后缀名匹配<url-pattern>*.jsp</url-pattern>后缀名可变,比如*.action *.do 等等对应的请求地址http://ip[域名]:port/工程路径/xx.jsp,后缀名名为.jsp请求会拦截
  5. Filter过滤器只关心请求的地址是否匹配,不关心请求的资源是否存在

Filter的生命周期

  1. Filter在web启动时,由tomcat来创建filter实例,只会创建一个
  2. 会调用filter默认的无参构造器,同时会调用init方法,只会调用一次
  3. 在创建filter实例时,同时会创建一个FilterConfig对象,并通过init方法传入
  4. 通过filterConfig对象,可以获取该filter的相关配置信息
  5. 当一个HTTP请求和该filter的url-pattern匹配时,就会调用doFilter方法
  6. 在调用doFilter方法,tomcat会同时创建ServletRequestServletResponseFilterChain对象,并通过doFilter传入
  7. 如果后面的请求目标资源(jsp,serlvet…)会使用到request和response,那么会继续传递

FilterConfig

public class SparrowFilterConfig implements Filter {

    private String ip; //从配置文件中获取ip
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //通过filterConfig获取相关的参数
        String filterName = filterConfig.getFilterName();
        ip = filterConfig.getInitParameter("ip");
        ServletContext servletContext = filterConfig.getServletContext();
        Enumeration<String> parameterNames = filterConfig.getInitParameterNames();
        while (parameterNames.hasMoreElements()) {
            System.out.println("名字=" + parameterNames.nextElement());
        }

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //通过forbidden ip来控制
        //先获取到访问ip
        String remoteAddr = servletRequest.getRemoteAddr();
        if (remoteAddr.contains(ip)) {
            System.out.println("封杀该IP");
            servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest, servletResponse);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

FilterChain过滤器链

  1. 多个Filter和目标资源在一次HTTP请求,在同一个线程中
  2. 当一个请求url和filter的url-pattern匹配时,才会被执行,如果有多个匹配上,就会顺序执行,形成一个filter调用链(底层可以使用一个数据结构搞定)
  3. 多个filter共同执行时,因为是一次HTTP请求,使用同一个request对象
  4. 多个filter执行顺序和web.xml配置顺序保持一致
  5. chain.doFilter(req,resp)方法 将执行下一个过滤器的doFilter方法,如果后面没有过滤器,则执行目标资源
  6. 注意执行过滤器链时,顺序是HTTP请求->A过滤器doFilter()->A过滤器前置代码->A过滤器chain.doFilter()->B过滤器doFilter()->B过滤器前置代码->B过滤器chain.doFilter()->目标文件->B过滤器后置代码->A过滤器后置代码->返回给浏览器页面/数据
public class AFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("AFilter~~~" + Thread.currentThread().getId());

        System.out.println("AFilter doFilter的前置代码");
        System.out.println("执行AFilter ");
        filterChain.doFilter(servletRequest, servletResponse);

        System.out.println("AFilter doFilter的后置代码");
    }
}

public class BFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("BFilter~~~" + Thread.currentThread().getId());
        System.out.println("BFilter doFilter的前置代码");
        System.out.println("执行BFilter ");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("BFilter doFilter的后置代码");
    }

}

    <filter>
        <filter-name>AFilter</filter-name>
        <filter-class>com.sparrow.filter.AFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AFilter</filter-name>
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>BFilter</filter-name>
        <filter-class>com.sparrow.filter.BFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>BFilter</filter-name>
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诉衷情の麻雀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值