1. 过滤器Filter

1.1 Filter概念

  • 过滤器: 过筛子,符合条件的过去,不符合条件不能过去.

  • 生活比喻: 安检,检查安全的人与物才可以通过放行

  • 程序: 客户端需要访问服务器的目标资源,在客户端和服务器资源之间设置过滤器, 符合要求放行

2. Filter的入门程序

  • 需求:

    • 浏览器要访问HelloServlet
    • 途径过滤期MyFilter, 若MyFilter放行,可执行访问到HelloServlet; 若不放行,无法访问HelloServlet
  • 执行图解:
    在这里插入图片描述

  • 实现步骤:

    1. 编写Servlet, 在web.xml配置Servlet访问路径
    2. 编写Filter,定义类, 实现接口Filter, 实现接口中抽象方法, 在web.xml配置Filter的访问过滤路径
代码: HelloServlet

public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //控制台打印
        System.out.println("HelloServlet 执行了");
        //浏览器响应
        response.getWriter().println("Hello Servlet");
    }

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

代码: MyFilter

public class MyFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("MyFilter 执行了");

        //执行过滤后放行, 进行后续的请求访问
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}
代码: web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <!--配置servlet-->
    <filter>
        <filter-name>my</filter-name>
        <filter-class>com.itheima.filter.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>my</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--配置Servlet-->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.itheima.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

</web-app>

3. Filter的生命周期

  • 过滤器对象的创建,是Tomcat服务器启动

    • init(FilterConfig config)过滤器对象被创建的时候调用,FilterConfig 对象tomcat引擎创建
  • 过滤器执行过滤的方法,过滤被访问资源的时候,必须是被过滤器过滤器的资源

    • doFilter(request,response)
  • 过滤器对象销毁的方法,销毁之前调用,服务器关闭

    • destroy()
    package cn.itcast.web.filter;
    
    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    
    /**
     * 1 创建类 实现Filter接口
     * 2 在web.xml中注册
     * 3 在web.xml中映射拦截的路径
     */
    public class Filter1 implements Filter {
        String encoding;
    
        public Filter1() {
            System.out.println("======= 1 执行Filter1的构造方法... ...");
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("======= 2 执行Filter1的初始化 init 方法... ...");
            encoding = filterConfig.getInitParameter("encoding");
            System.out.println("编码集: " + encoding);
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("======= 3 执行Filter1的执行过滤 doFilter 方法... ... 编码集:" + encoding);
            // 因为父类不能调用子类的方法,所以向下转型
            HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
            String uri = httpServletRequest.getRequestURI();
            System.out.println("执行过滤器1 ... ... 访问的路径: " + uri);
    
            // 允许访问目标资源 : 放行
            filterChain.doFilter(servletRequest, servletResponse);
    
            //System.out.println("放行之后执行... ...");
        }
    
        @Override
        public void destroy() {
            System.out.println("======= 4 执行Filter1的销毁 destroy 方法... ...");
    
        }
    }
    

4. Filter的url-pattern配置

  • 完全匹配
<!-- 
    过滤资源,只有hello
    绝对匹配 <url-pattern>/hello</url-pattern>
    只能过滤指定的资源
-->
<url-pattern>/hello</url-pattern>
  • 目录匹配
<!--
   目录匹配,过滤器中最常见
   /abc/*  过滤abc目录下的所有资源
   一次过滤一片资源
   过滤后台资源 /admin/*
-->
<url-pattern>/admin/*</url-pattern>
  • 后缀名匹配
<!-- 
  后缀名匹配,一般不使用
  *.jsp  访问所有jsp文件
-->
<url-pattern>*.jsp</url-pattern>

5. 注解配置Filter

@WebFilter(urlPatterns="/过滤资源")

@WebFilter("/*")
public class ChinaFilter implements Filter {
    //代码省略...
}
package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

// 方式一
//@WebFilter(urlPatterns = {"/hello.jsp", "/helloServlet"})

// 方式二
// @WebFilter(urlPatterns = {"/hello.jsp"})

// 方式三
// @WebFilter(urlPatterns = "/hello.jsp")

// 方式四
@WebFilter("/hello.jsp")
public class Filter3 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        // 因为父类不能调用子类的方法,所以向下转型
        HttpServletRequest httpServletRequest = (HttpServletRequest) req;
        String uri = httpServletRequest.getRequestURI();
        System.out.println("执行过滤器3 ... ... 访问的路径: " + uri);

        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

6. Filter 处理中文乱码

  • 需求:

​ 使用过滤器Filter, 处理所有请求的中文乱码

  • 代码: ChinaServlet
@WebServlet("/china")
public class ChinaServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        System.out.println("ChinaServlet , 获取请求参数 username = " + username);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • 代码: ChinaFilter
@WebFilter("/*")
public class ChinaFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //在过滤器中,设置request对象的编码表
        req.setCharacterEncoding("utf-8");
        //设置response缓冲区的编码表,通知浏览器的解码
        resp.setContentType("text/html;charset=utf-8");

        System.out.println("ChinaFilter执行了, 过滤中文,设置编码utf-8");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

    public void destroy() {
    }
}

7. 过滤器链 FilterChain的执行过程

Filter中的过滤器链 FilterChain: 由Tomcat引擎创建对象

作用: 维护过滤器执行顺序

在这里插入图片描述

小结: Servlet中doGet方法参数 request, response对象, 由Tomcat引擎创建, 经过多个过滤器一层层传递

8. 多个过滤器的先后执行顺序

  • web.xml配置:

    和配置文件的编写顺序决定运行的顺序,准确的说法是,根据mapping的顺序决定 (由上到下执行)

  • 注解开发

    注解开发没有配置文件

    按照类名的自然顺序决定: A-B-C

    如果存在配置文件,配置文件优先

9. 过滤器案例: 登录验证(权限校验)

  • 问题描述:在登录的时候,若登录成功会跳转到登录成功的页面,该页面有一个网址。若用户没有经过登录直接访问该网址,应该被拦截下来,让用户去登录。
  • 方法分析:
    • 在登录成功网址前加个过滤器,判断是否登录,若登录则可以放行,若没有,则跳转到登录页面并告知用户需要登录
    • 判断是否登录的方法:在登录Servlet中,若登录成功,将用户名放在session域中;在过滤器中从session域中取出用户名,若能取到,就证明已经登录了,放行。

代码

  • 登录页面
1. 访问项目的资源。验证其是否登录
2. 如果登录了,则直接放行。
3. 如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。

9.2 实现

  • 登录页面(非常丑,示例一下)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
    <div style="color: red;size: 10px">${message}</div>
    <form action="${pageContext.request.contextPath}/login" method="post">
        用户名:<input type="text" name="username"><br>
        密的码:<input type="password" name="password"><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

  • 登录成功页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>欢迎页面</title>
</head>
<body>
    <div style="font-size: 28px">欢迎登录</div>
</body>
</html>

  • LoginServlet
package servlet;

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

@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取表单提取的数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 判断是否 登录成功
        if (username.equals("tom") && password.equals("123")){
            //登录从成功,用户名存储在session中
            request.getSession().setAttribute("username",username);

            // 重定向,需要些web应用名称

            response.sendRedirect(request.getContextPath()+"/resource/welcome.jsp");

        }else {
            //登录失败,回到登录页面,告知用户
            request.setAttribute("message","登录失败,用户名或密码错误");
            request.getRequestDispatcher("/login.jsp").forward(request,response);

        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • 过滤器
package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/resource/*")
public class loginFilter implements Filter {
    /**
     * 登录的过滤: 不能直接访问登录成功页面,必须登录后才行
     *  所以要判断是否登录,若登录,正常放行
     *  若没有登录直接输入了登录成功页面的网址,那么就跳转到登录页面
     *  那么如何判断是否登录了呢?
     *  从session域中取出username
     *  为什么从session域中取呢,因为在登录Servlet中,登录成功后将用户名存储到了session中
     *  如果为空,就拦截(页面跳转到登录界面)
     *  如果不为空,走正常程序()
     */

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // servletRequest转成HttpServletRequest子接口
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        //servletResponse转成HttpServletResponse
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        // 获取session域中的username
        String username = (String)request.getSession().getAttribute("username");

        if (username == null){
            // 没有登录,退回到登录页面并告知用户
            request.getSession().setAttribute("message","请先登录");
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }else {
            // 检测到登录,放行
            filterChain.doFilter(request,response);

        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

9.3 验证

  • 没有登录时,访问登录成功页面:
    在这里插入图片描述
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐