美文网首页
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)

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