美文网首页
06_过滤器(Filter)

06_过滤器(Filter)

作者: 渐进逾 | 来源:发表于2019-09-29 18:29 被阅读0次

过滤器

作用

拦截请求与响应


image.png
优点

解决代码冗余,如果每个资源都需要处理同一个操作,那么这个处理操作就可以放在过滤器集中处理。

应用场景

1.解决post提交中文乱码应用场景
2.登录权限控制

开发方式

1.配置XML文件
2.注解(推荐)

方式1-手动XML配置实现过滤器

实现步骤:

  1. 创建一个目标资源Demo1Servlet处理请求与响应
  2. 创建一个类Demo1Filter并实现Filter接口,重写拦截请求与响应的方法doFilter
  3. 在web.xml中配置过滤器拦截目标资源url(因为拦截资源,每个资源都是通过url访问的)
  4. 部署项目测试运行,观察是否进行拦截请求与响应

代码实现×3:
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(name = "_01Demo1Servlet", urlPatterns = "/_01Demo1Servlet")
public class _01Demo1Servlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

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

        //输出一句信息
        System.out.println("执行了_01Demo1Servlet代码");
    }
}

过滤器Filter:

import javax.servlet.*;
import java.io.IOException;

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

    }

    //doFilter是拦截请求与响应的方法
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {

        //1.拦截请求
        System.out.println("==执行了_01Demo1Filter拦截请求的代码==");

        //2.放行,给目标资源去执行【有这句代码就放行,没有就不放行,不放行导致目标资源不执行】
        filterChain.doFilter(request,response);//本质就是转发跳转到目标资源

        //3.拦截响应
        System.out.println("==执行了_01Demo1Filter拦截响应的代码==");
    }

    @Override
    public void destroy() {

    }
}

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_4_0.xsd"
         version="4.0">

    <!--目标:建立Demo1Filter拦截Demo1Servlet
        1.定义过滤器全名,使用<filter>标签
        2.给这个过滤器配置拦截的url,(url就是Demo1Servlet的访问路径),使用<filter-mapping>标签
    -->
    <filter>
        <filter-name>_01Demo1Filter</filter-name>
        <filter-class>com.itheima.filter._01Demo1Filter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>_01Demo1Filter</filter-name>
        <url-pattern>/_01Demo1Servlet</url-pattern>
    </filter-mapping>
</web-app>

访问地址:
http://localhost:8080/day29_01_filter_war_exploded/_01Demo1Servlet

tips:
1.实现过滤器的接口
javax.servlet.Filter
2.过滤器拦截请求与响应的方法
doFilter方法

方式2-模板向导注解实现过滤器

实现步骤:

  1. 创建一个Demo2Servlet处理请求与响应
  2. 根据模板向导创建过滤器,重写doFilter方法进行拦截请求与响应
  3. 设置注解配置拦截的资源地址

过滤器Filter代码:

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

/*
* @WebFilter 用于配置过滤器的注解
* filterName = "_02Demo2Filter", 功能与xml中<filter-name>标签功能一样,可有可无
* urlPatterns = "/_02Demo1Servlet",功能与xml中<url-pattern>标签功能一样,必须有参数
* */
@WebFilter(filterName = "_02Demo2Filter",urlPatterns = "/_02Demo2Servlet")
public class _02Demo2Filter implements Filter {
    public void destroy() {
    }

    //重写拦截请求与响应的方法
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //1.拦截请求
        System.out.println("==执行了_02Demo2Filter拦截请求的代码==");

        //2.放行,给目标资源去执行
        filterChain.doFilter(request,response);

        //3.拦截响应
        System.out.println("==执行了_02Demo2Filter拦截响应的代码==");
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

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(name = "_02Demo2Servlet", urlPatterns = "/_02Demo2Servlet")
public class _02Demo2Servlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

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

        //输出一句信息
        System.out.println("执行了_02Demo2Servlet代码");
    }
}

tips:
1.注解实现代码

@WebFilter(fileName="过滤器名字",urlPatterns="拦截的资源路径")

2.注解配置与xml配置出现冲突,谁的优先级高?
xml优先级高于注解

过滤器执行流程(原理)

执行流程(时序图)


image.png

tips:
1.过滤器对象在服务器启动的时候创建,全局唯一。
2.过滤器对象在服务器关闭的时候销毁

过滤路径映射配置介绍

拦截路径配置方式有2种:
第一种:
精确匹配,配置的路径与资源访问的路径要一模一样就可以拦截
任何资源路径都是可以的
urlPatterns = "/img/3.jpg",
urlPatterns = "/index.jsp"

第二种:
模糊匹配,只能使用一个“”号通配符操作,代表0~多个字符
1.前缀匹配,匹配开头一致的
要求:以“/”开头,以"/
"结尾
例子:
/abc/,拦截资源访问路径以/abc开头的所有资源
/
,拦截所有资源
2.后缀匹配,匹配结尾一致的
要求:以“*”开头,以“.扩展名”方式结尾
例子:
*.action,拦截资源访问路径以.action为结尾的所有资源
*.do,拦截资源访问路径以.do为结尾的所有资源

注意:
1.urlPatterns = "/abc//abc",这是精确匹配
2.在过滤器里面可以使用“/”或“/
”,但是在Servlet里面不可以,否则静态资源无法访问

过滤器代码:

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


/*
* 路径的配置通过urlPatterns属性完成的,这个属性有2中写法
* 方式1:拦截一个路径,urlPatterns = "/url"
* 方式2:拦截多个路径,urlPatterns = {"/url1","/url2",...}
* */
@WebFilter(filterName = "_04URLFilter",urlPatterns = {
        //精确匹配
        "/img/6.jpg","/index.jsp","/index.html",
        //模糊匹配
        "/abc/*","*.do"
})
public class _04URLFilter implements Filter {
    public void destroy() {
    }

    //重写拦截请求与响应的方法
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //1.拦截请求
        System.out.println("==执行了_02Demo2Filter拦截请求的代码==");

        //2.放行,给目标资源去执行
        filterChain.doFilter(request,response);

        //3.拦截响应
        System.out.println("==执行了_02Demo2Filter拦截响应的代码==");
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

拦截方式

拦截方式介绍

拦截方式
是指过滤器根据浏览器访问的资源方式的不同进行不同的拦截。
浏览器访问资源方式
第一种:浏览器直接url访问目标资源(重定向也属于直接url访问资源)

第二种:浏览器访问一个资源服务器内部请求转发跳转到另一个目标资源

拦截方式就是根据不同访问资源的方式进行不同的拦截,默认过滤器只会拦截第一种直接url访问资源

拦截方式类型


image.png

注解方式拦截方式的语法


image.png
扩展web.xml配置过滤器修改拦截方式设置
image.png
过滤链

同一个资源可以被多个过滤器进行拦截强求与响应——过滤链

执行顺序分析


image.png

案例1-解决全站乱码

分析

项目应用程序乱码的地方:

  1. post提交中文请求
  2. response输出中文数据
实现步骤
  1. 准备一个表单数据提交post中文请求
  2. 新建一个EncodingServlet处理请求接收中文数据并使用response输出
  3. 创建一个过滤器EncodingFilter拦截所有资源解决全站乱码
Form.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="encoding" method="post">
    <input type="text" name="name"/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>
EncodingServlet代码
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(name = "_09EncodingServlet", urlPatterns = "/encoding")
public class _09EncodingServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

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

        //目标:接收数据并输出数据
        //1.获取post提交中文的数据
        String name = request.getParameter("name");

        //2.控制台打印接收的数据
        System.out.println(name);

        //3.输出中文数据到浏览器'
        response.getWriter().write(name);
    }
}
EncodingFilter代码
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
* 目标:拦截所有资源“/*”, 处理乱码
* */
@WebFilter(filterName = "_09EncodingFilter",urlPatterns = "/*")
public class _09EncodingFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //1.将req,resp父接口转换为子接口
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        //2.处理post提交中文乱码
        //获取提交数据的方法类型
        String method = request.getMethod();

        //判断提交数据访问为post请求才处理乱码
        if("post".equalsIgnoreCase(method)){
            request.setCharacterEncoding("utf8");
        }


        //3.处理response输出中文乱码
        response.setContentType("text/html;charset=utf8");

        //4.放行
        chain.doFilter(request, response);

    }

    public void init(FilterConfig config) throws ServletException {

    }

}

tips:
过滤器拦截所有资源:

urlPatterns="/*"

案例2-登录权限控制1-环境搭建与登录功能

需求


image.png
实现分析
  1. 创建一个项目
  2. 导入页面素材("资料\原型")
  3. 实现登录
搭建环境结构
image.png

LoginServlet代码:

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(name = "LoginServlet", urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

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

        /*目标:模拟处理登录功能*/

        //1.获取用户名与密码
        String user = request.getParameter("user");
        String password = request.getParameter("password");

        //2.判断用户名必须为admin,密码必须为123,代表登录成功
        if("admin".equals(user) && "123".equals(password)){
            //登录成功,将用户名写入session,以后用于判断是否登登录的依据
            request.getSession().setAttribute("loginUser",user);

            //登录成功后跳转/list.jsp
            response.sendRedirect(request.getContextPath()+"/list.jsp");

        }else {
            //3.校验失败,登录失败
            //将错误信息存储到请求域中
            request.setAttribute("errorMsg","用户名或密码错误");
            //转发跳转到登录页面,使用el显示错误信息
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }
}

案例2-登录权限控制2-实现登录控制

使用过滤器实现登录权限控制

过滤器代码
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*目标:拦截admin目录下资源的所有访问*/
@WebFilter(filterName = "LoginFilter",urlPatterns = "/admin/*")
public class LoginFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //1.将父接口转换为子接口
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        //2.获取session中的登录数据“loginUser”
        String loginUser = (String) request.getSession().getAttribute("loginUser");

        //3.判断登录数据是否有效,有效放行
        if(loginUser!=null){

            //放行
            chain.doFilter(request, response);

        }else {

            //4.无效返回登录页面
            response.sendRedirect(request.getContextPath()+"/login.jsp");
        }

    }

    public void init(FilterConfig config) throws ServletException {

    }

}

监听器

tomcat服务器内存数据(三大域对象)发生变化了,使用监听器在内存数据改变的时候做一些业务控制。

作用:获取域对象改变的时间点,让我们在对应的时间点进行业务逻辑控制

监听器分类
image.png
ServletContextListener介绍

获取域对象改变的时间点,让我们在对应的时间点进行业务逻辑控制

ServletContextListener监听对象创建与销毁

实现步骤——

  1. 创建一个类实现ServletContextListener接口,重写2个方法
  2. 配置注解将当前类交给服务器去管理

注解方式代码:

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/*
* servletContext对象什么时候创建?什么时候销毁?
* 答:servletContext对象是服务器启动时最早最先创建的对象,比过滤器早;服务器关闭的时候。
* */
@WebListener  //注解含义:将当前监听器类交给服务器管理
public class MyServletContextListener implements ServletContextListener {

    //当服务器创建servletContext上下文域对象的时候触发调用的方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("==servletContext对象被创建了==");
    }

    //当服务器销毁servletContext上下文域对象的时候触发调用的方法
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("==servletContext对象被销毁了==");
    }
}

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">
    
    <!--配置监听器-->
    <listener>
        <listener-class>com.itheima.listener.MyServletContextListener</listener-class>
    </listener>
</web-app>
ServletContextListener的作用
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.Timer;
import java.util.TimerTask;

/*
* servletContext对象什么时候创建?什么时候销毁?
* 答:servletContext对象是服务器启动时最早最先创建的对象,比过滤器早;服务器关闭的时候。
* */
@WebListener  //注解含义:将当前监听器类交给服务器管理
public class MyServletContextListener implements ServletContextListener {

    //当服务器创建servletContext上下文域对象的时候触发调用的方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("==servletContext对象被创建了==");

        /*
        * 获取到servletContext创建的时间点有什么用?ServletContextListener的作用?
        * 答:我们因为上下文域对象的创建是最早的时间点,通常可以做如下2个操作:
        *       1.加载自定义配置文件数据,spring框架的配置文件就是使用这个监听器进行加载的
        *       2.开启定时器任务运行
        *              定时器任务:按照指定的时间执行任务
        *              js的定时器语法:setInterval()或setTimeout()
        * */

        //目标:java的jdk定时器

        //1.创建定时器类Timer
        Timer timer = new Timer();

        //2.订制定时任务计划
        //方式1:timer.schedule(TimerTask,long,long);
        //       参数1:TimerTask,任务接口,编写任务代码
        //       参数2:long,设置距离第一次执行的毫秒数
        //       参数3:long,每一次执行的间隔毫秒数
        //方式2:timer.schedule(TimerTask,Date,long);
        //       参数1:TimerTask,任务接口,编写任务代码
        //       参数2:Date,设置第一次执行的时间
        //       参数3:long,每一次执行的间隔毫秒数

        /*需求:每3秒输出一次hello world*/
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        },0,3000);
    }

    //当服务器销毁servletContext上下文域对象的时候触发调用的方法
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("==servletContext对象被销毁了==");
    }
}

web项目的路径讲解

路径配置方式有2种
1.相对路径(静态页面上推荐,因为静态页面无法动态获取部署资源目录路径):
格式:url="相对资源路径"
含义:相对于当前的静态页面的路径
例子:<form action="login" method="post"> login是相对路径
2.全路径(服务器端java代码推荐):
格式1:url="/资源路径" 服务器内部使用,当前"/"代表当前项目内
例子:

request.getRequestDispatcher("/demo").forward(request,response);

格式2:url="/web项目资源部署目录名字/资源路径" 浏览器去执行,重定向和jsp使用
例子:

response.sendRedirect(request.getContextPath()+"/demo");
路径演示
image.png

过滤器和监听器(总结)

image.png

相关文章

  • 06_过滤器(Filter)

    过滤器 作用 拦截请求与响应 优点 解决代码冗余,如果每个资源都需要处理同一个操作,那么这个处理操作就可以放在过滤...

  • Spring系列之Filter and Interceptor

    一、Filter 过滤器 1. 什么是Filter 过滤器? Filter 的含义Filter 过滤器是一个对象 ...

  • java基础-day42-Filter、Listener和Bas

    Filter ,Listener和BaseServlet 1. Filter过滤器 1.1 Filter过滤器的配...

  • Spring Boot使用过滤器Filter

    Spring Boot使用过滤器Filter >> 过滤器Filter介绍Filter也称为过滤器,是处于客户端与...

  • Filter

    Java****中的****Filter****过滤器 Filter****简介 Filter也称之为过滤器,它是...

  • 22. 过滤器

    11 过滤器(Filter) 什么是过滤器(Filter) Filter:过滤器,用来过滤网站的数据; 处理中文乱...

  • Interceptor和Filter区别

    过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的...

  • Filter 过滤器

    Filter过滤器 是什么 Filter过滤器 有什么用 拦截 数据处理 统一控制 Filter过滤器 如何用 使...

  • Filter&Listener

    Filter过滤器 概念 Filter表示过滤器,是JavaWeb的三大组件之一,Servlet、Filter、L...

  • 设计模式之过滤器模式详解(附源代码)

    过滤器模式(Filter Pattern) 过滤器模式(Filter Pattern)或标准模式(Criteria...

网友评论

      本文标题:06_过滤器(Filter)

      本文链接:https://www.haomeiwen.com/subject/xnefectx.html