JavaWeb 三大组件之 过滤器 Filter

JavaWeb 三大组件之 过滤器 Filter

1.官方文档

链接:https://pan.baidu.com/s/1Hk8Aq8Nk9_P1ucmaP4g3qA 
提取码:5kni 

2.Filter 过滤器说明

1.为啥要过滤器-需求示意图

●一图胜千言

image-20220319181528564

2.过滤器介绍

1.Filter 过滤器它是 JavaWeb 的三大组件之一(Servlet 程序、Listener 监听器、Filter 过滤器)
2.Filter 过滤器是 JavaEE 的规范,是接口

image-20220319181657875

3.Filter 过滤器它的作用是:拦截请求,过滤响应。
4.应用场景

●权限检查
●日记操作
●事务管理

3.Filter 过滤器基本原理

●一图胜千言

image-20220319181759832

4.Filter 过滤器快速入门

●需求: 在 web 工程下,有后台管理目录 manage,要求该目录下所有资源(html、图片、jsp 、Servlet 等)用户登录后才能访问

login.jsp

image-20220319225024141

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

admin.jsp

image-20220319225048436

<%@ 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="https://b3logfile.com/file/2022/03/solo-fetchupload-5441944809022457584-df2dfcd5.png" height="300"/>

</body>

</html>

代码实现

LoginCheckServlet

@WebServlet(name = "LoginCheckServlet",urlPatterns ={"/loginCheckServlet"})
public class LoginCheckServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if("llp".equals(username) && "123".equals(password)){
            User user = new User(username,password);
            HttpSession session = request.getSession();
            session.setAttribute("user",user);
            //登录成功跳转到admin.jsp
            //注意请求转发并不会经过过滤器,但admin.jsp中的静态资源会经过过滤器,回顾之前内容每一个静态资源浏览器都会发起一个请求
            request.getRequestDispatcher("/manage/admin.jsp").forward(request,response);
        }else {
            //登录失败跳转到login.jsp
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}

ManageFilter

/**
 * 1. filter在web项目启动时, 由tomcat 来创建filter实例, 只会创建一个
 * 2. 会调用filter默认的无参构造器, 同时会调用 init方法, 只会调用一次
 * 3. 在创建filter实例时,同时会创建一个FilterConfig对象,并通过init方法传入
 * 4. 通过FilterConfig对象,程序员可以获取该filter的相关配置信息
 * 5. 当一个http请求和该filter的的url-patter匹配时,就会调用doFilter方法
 * 6. 在调用doFilter方法时,tomcat会同时创建ServletRequest 和 ServletResponse 和 FilterChain对象
 * , 并通过doFilter传入.
 * 7. 如果后面的请求目标资源(jsp,servlet..) 会使用到request,和 response,那么会继续传递
 * 8. javaweb - ssm - springboot , 有 浏览器和 web服务器(tomcat)参与, 而这两个部分不是我们写的
 */
public class ManageFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("ManageFilter init()被调用。。。");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpSession session = httpServletRequest.getSession();
        User user = (User)session.getAttribute("user");
        if(user!=null){
            //filterChain.doFilter(servletRequest, servletResponse)
            //1. 继续访问目标资源url
            //2. servletRequest 和 servletResponse 对象会传递给目标资源/文件
            //3. filter传递的两个对象(servletRequest,servletResponse),再后面的servlet/jsp 是同一个对象(指的是在一次http请求)
            System.out.println("servletRequest=" + servletRequest);
            System.out.println("日志信息==");
            System.out.println("访问的用户名=" + user.getUsername());
            System.out.println("访问的url=" + httpServletRequest.getRequestURL());
            System.out.println("访问的IP=" + httpServletRequest.getRemoteAddr());
            //用户登录成功过,直接放行
            filterChain.doFilter(servletRequest, servletResponse);
        }else {
            //用户尚未登录或者未成功过,跳转到登录页面
            //重定向方式
//            HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;
//            httpServletResponse.sendRedirect("/filter/login.jsp");
            //转发
            httpServletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
        }
    }

    @Override
    public void destroy() {
        System.out.println("ManageFilter destroy()被调用。。。");
    }
}

web.xml

<filter>
    <filter-name>ManageFilter</filter-name>
    <filter-class>com.llp.filter.ManageFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ManageFilter</filter-name>
    <url-pattern>/manage/*</url-pattern>
</filter-mapping>

5.Filter 过滤器 url-pattern

使用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 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在

6.Filter 过滤器生命周期

●Filter 生命周期图解

image-20220319230822336

7.FilterConfig

image-20220319232555881

●FilterConfig 说明
1.FilterConfig 是 Filter 过滤器的配置类
2.Tomcat 每次创建 Filter 的时候,也会创建一个 FilterConfig 对象,这里包含了 Filter 配置文件的配置信息。
3.FilterConfig 对象作用是获取 filter 过滤器的配置内容

●应用实例 FilterConfig_.java

需求:ip网段在127.0的就进行封杀

public class FilterConfig_ implements Filter {
  private String ip;

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
      String filterName = filterConfig.getFilterName();
      System.out.println("filter名称: " + filterName);
      Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
      while (initParameterNames.hasMoreElements()) {
          String element = initParameterNames.nextElement();
          System.out.println(element);
          if ("ip".equals(element)) {
              ip = filterConfig.getInitParameter("ip");
          }
      }
      Enumeration<String> contextInitParams = filterConfig.getServletContext().getInitParameterNames();
      while (contextInitParams.hasMoreElements()) {
          System.out.println(contextInitParams.nextElement());
      }
      System.out.println("FilterConfig_ filterConfig()被调用。。。");
  }

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
      System.out.println("FilterConfig_ doFilter()被调用。。。");
      HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
      String remoteAddr = httpServletRequest.getRemoteAddr();
      System.out.println("remoteAddr: "+remoteAddr);
      if(remoteAddr.contains(ip)){
          System.out.println("ip被封杀");
          httpServletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
          return;
      }
      filterChain.doFilter(servletRequest, servletResponse);
  }

  @Override
  public void destroy() {
      System.out.println("FilterConfig_ destroy()被调用。。。");
  }
}

web.xml

    <filter>
        <filter-name>FilterConfig</filter-name>
        <filter-class>com.llp.filter.FilterConfig_</filter-class>
        <init-param>
            <param-name>ip</param-name>
            <param-value>127.0</param-value>
        </init-param>
        <init-param>
            <param-name>port</param-name>
            <param-value>8888</param-value>
        </init-param>
        <init-param>
            <param-name>email</param-name>
            <param-value>llp@123.com</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>FilterConfig</filter-name>
        <url-pattern>/abc/*</url-pattern>
    </filter-mapping>

8.FilterChain 过滤器链

1.一句话: FilterChain: 在处理某些复杂业务时,一个过滤器不够,可以设计多个过滤器共同完成过滤任务,形成过滤器链。

2.基本原理示意图

先执行哪一个过滤器根据web.xml的配置和先后顺序来决定

image-20220320144513601

3.应用实例

注意:A过滤器和B过滤器的执行顺序;

1.首先根据web.xml来进行匹配

2.当浏览器发起http请求时,A过滤和B过滤器都匹配上时会根据web.xml的先后顺序来执行(参考LinkedList的数据结构)

需求:演示过滤器链的使用

image-20220320151653915

hi.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>hi 我是guKong~</h1>
</body>
</html>

AFilter

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

    }

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

    @Override
    public void destroy() {

    }
}

web.xml

   <filter>
        <filter-name>AFilter</filter-name>
        <filter-class>com.llp.filter.AFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AFilter</filter-name>
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>

BFilter

@WebFilter(filterName = "BFilter",urlPatterns = {"/admin/*"})
public class BFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("执行BFilter前置代码 ");
        System.out.println("BFilter filterChain.doFilter(servletRequest,servletResponse)放行");
        chain.doFilter(req,resp);
        System.out.println("执行BFilter后置代码");
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

测试效果

image-20220320152730567

9.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 过滤器后置代码 -> 返回给浏览器页面/数据

10.Filter 作业练习

●需求分析: 使用过滤器, 完成如下要求

1)点击发表评论页面 topic.jsp, 可以在showTopic.jsp 显示评论内容
2)如果发表的评论内容,有关键字比如 “苹果” “香蕉”, 就返回topic.jsp, 并提示有禁用词
3)要求发表评论到 showTopic.jsp 时,经过过滤器的处理
4)禁用词, 配置在过滤器, 在启动项目时动态的获取, 注意处理中文

思路

image-20220320170110109

topic.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>发表对阿凡达电影评论</h1>
过滤词: 苹果, 香蕉 ${errorInfo}
<form method="post" action="<%=request.getContextPath()%>/topic/showTopic.jsp">
    用户: <input type="text" name="username"><br/>
    评论: <textarea rows="10" name="content" cols="20"></textarea><br/>
    <input type="submit" value="发表评论">
</form>
</body>
</html>

showTopic.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>你发表的评论是</h1>
评论内容: <%=request.getParameter("content")%>
</body>
</html>

TopicFilter

public class TopicFilter implements Filter {

    //属性-> 存放禁用词
    private String[] forbiddenWords = null;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //获取禁用词
        String forbiddenword = filterConfig.getInitParameter("forbiddenword");
        forbiddenWords = forbiddenword.split(",");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        //解决从topic.jsp 提交的中文乱码问题
        servletRequest.setCharacterEncoding("utf-8");

        //判断评论是不是有禁用词
        String content = servletRequest.getParameter("content");
        //循环遍历一把,看看有没有禁用词
        for (String forbiddenWord : forbiddenWords) {//java基础
            if (content.contains(forbiddenWord)) {
                //返回topic.jsp
                servletRequest.setAttribute("errorInfo", "你输入的有禁用词");
                servletRequest.getRequestDispatcher("/topic.jsp")
                        .forward(servletRequest, servletResponse);
                return;//返回
            }
        }

        //继续到目标
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

测试效果

image-20220320170028191

image-20220320170044719

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值