• Servlet高级Fliter(过滤器)&Listener(监听器)


    “别小看任何人,越不起眼的人。往往会做些让人想不到的事。"你好我是梦阳辰,快来和我一起学习吧!

    01.Filter概述

    Filter和Listener是Servlet规范中的两个高级特性,不同于Servlet,他们不用于处理客户端请求。

    Filter用于对request,response对象进行修改。
    Filter被称作过滤器,其基本功能就是对Servlet容器调用Servlet的过程进行拦截,从而在Servlet进行响应处理前后实现一些特殊的功能。这就好比现实中的污水净化设备,它可以看作一个过滤器,专门用于过滤污水杂质。

    当浏览器访问服务器中的目标资源时,会被Filter拦截,在Filter中进行预处理操作,然后再将请求转发给目标资源。

    当服务器接收到这个请求后会对其进行响应,在服务器处理响应的过程中,也需要先将响应结果发送给过滤器,在过滤器中对响应结果进行处理后,才会发送给客户端。

    过滤器的作用:
    一般完成通用性的操作。
    比如:登录验证,判断用户是否登录;统一编码处理,敏感字符处理等。

    其实Filter过滤器就是实现了javax.servlet.Filter接口的类,在javax.servlet.Filter定义了三个方法。

    Listener用于对context,session,request事件进行监听。

    02.Filter快速入门

    步骤:
    1.定义一个类,实现接口javax.servlet.Filter。

    2.复写方法

    3.配置拦截路径
    3.1.web.xml配置
    3.2.注解配置
    javax.servlet.Filter定义了三个方法

    @WebFilter("/*")//拦截所有资源
    public class FilterTest1 implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            //初始化过滤器,在Web程序加载的时候调用,配置初始化参数
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.print("我是过滤器!");
    
            //是否放行,即转发到请求资源
            filterChain.doFilter(servletRequest,servletResponse);
        }
    
        @Override
        public void destroy() {
            //用于释放被Filter打开的资源,当Web服务器卸载Filter对象之前被调用
        }
    }
    

    web.xml配置
    取消注解配置,使用web.xml配置。

     <filter>
            <filter-name>FilterTest1</filter-name>
            <filter-class>filter.FilterTest1</filter-class>
        </filter>
        
        <filter-mapping>
            <filter-name>FilterTest1</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    

    03.Filter深入

    过滤器的流程:

    @WebFilter("/*")
    public class FilterTest2 implements Filter {
        public void destroy() {
        }
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
            //用于拦截用户的请求,如果和当前过滤器的拦截路径匹配,此方法会被调用
            //对request对象请求消息增强
            System.out.println("我被执行了request!");
    
            chain.doFilter(req, resp);
    
            //对response对象的响应消息增强
            System.out.println("我被又执行了response!");
        }
    
        public void init(FilterConfig config) throws ServletException {
    
        }
    
    }
    
    

    拦截路径的配置:
    具体资源路径:/index.jsp 只有访问index.jsp资源时,过滤器才会被执行。

    2.拦截目录:/user/* 访问/uer下的所有资源时,过滤器都会被执行。

    3.后缀名拦截:*.jsp 访问所有后缀名为jsp资源时,过滤器执行。

    4.拦截所有资源:/*
    拦截方式的配置:

    资源被访问的方式:
    请求转发过滤器不会被执行。
    1.注解配置,可以配置多个值
    设置dispatcherTypes属性

    REQUEST:默认值,浏览器直接请求资源
    FORWARD:转发访问资源
    INCLUDE:包含访问资源
    ERROR:错误跳转资源
    ASYNC:异步访问资源
    

    2.web.xml注释

    //浏览器直接请求资源时,会被执行,转发不会
    @WebFilter(value = "/*",dispatcherTypes = DispatcherType.REQUEST)
    public class FilterTest3 implements Filter {
        public void destroy() {
        }
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
            System.out.println("我被执行啦!");
            chain.doFilter(req, resp);
        }
    
        public void init(FilterConfig config) throws ServletException {
    
        }
    
    }
    
    	@WebFilter(value = "/*",
    	dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})
    
    <filter>
            <filter-name>FilterTest1</filter-name>
            <filter-class>filter.FilterTest1</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>FilterTest1</filter-name>
            <url-pattern>/*</url-pattern>
            <dispatcher>FORWARD</dispatcher>
        </filter-mapping>
    

    过滤器链(多个过滤器):
    在这里插入图片描述

    执行顺序
    先执行过滤器1,再执行过滤器2,回来先执行过滤器2,再执行过滤器1。

    怎么判断过滤器谁在前面:
    1.注解配置
    按照类名的字符串比较规则,较小的先执行。
    如:AFilter,BFilter
    AFilter就先执行。

    2.web.xml配置:

    <filter-mapping>
    

    谁定义在上面,谁就先执行。

    04.Filter案例

    案例一:登录验证
    1.访问某些资源,验证其是否登录

    2.如果登录了,则直接放行。

    3.如果没有登录,则跳转到登录页面,提示,“你尚未登录,请先登录”。
    在这里插入图片描述

    /**
     * 登录验证的过滤器
     */
    @WebFilter("/*")//除了登录相关资源外(如login.jsp)
    public class FilterTest4 implements Filter {
        public void destroy() {
        }
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
            //1.强转
            HttpServletRequest request = (HttpServletRequest)req;
            //2.获取资源请求路径
            String uri = request.getRequestURI();
            //排除登录相关资源,css/js/fonts等
            if(uri.contains("/login.jsp")||uri.contains("/loginServlet")||uri.contains("/css/")||uri.contains("/js/")){
                //用户就是像登录,放行
                chain.doFilter(req, resp);
            }else{
                //不包含,需要验证用户是否登录
                //3.从获取session中获取user
                Object user = request.getSession().getAttribute("user");
                if(user!=null){
                    //登录了,放行
                    chain.doFilter(req, resp);
                }else{
                    //没有登录,跳转到登录页面
                    request.setAttribute("login_msg","你为登录,请先登录!");
                    request.getRequestDispatcher("/login.jsp");
                }
            }
    
        }
    
        public void init(FilterConfig config) throws ServletException {
    
        }
    
    }
    

    案例二:敏感词汇的过滤
    分析:
    在这里插入图片描述
    案例需要对request对象进行增强。

    那如进行增强呢?
    增强对象的功能
    设计模式:一些通用的解决固定问题的方式。
    装饰模式:

    代理模式:
    概念:
    1.真实对象:被代理的对象。
    2.代理对象
    3.代理模式:代理对象代理真实对象,达到增强真实对象的目的。
    实现方式:
    1.静态代理
    在一个类文件描述代理模式。

    2.动态代理
    在内存中形成代理类(在内存中动态生成)。
    在这里插入图片描述
    注:请先看以下动态代理相关知识再看案例二的实现
    案例二实现:
    1.对requset对象进行增强,增强获取参数相关方法。
    2.放行,传递代理对象。
    代码实现:

    /**
     * 敏感词汇过滤器
     */
    @WebFilter("/*")
    public class FilterSensitiveWords implements Filter {
        public void destroy() {
        }
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
            //创建代理对象,增强getParameter方法
            ServletRequest proxy_req=(ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //增强getParameter方法
                    //判断是否是该方法
                    if(method.getName().equals("getParameter")){
                        //增强返回值
                        //获取返回值
                        String value = (String)method.invoke(req,args);
                        if(value!=null){
                            for(String str:list){
                                if(value.contains(str)){
                                    value = value.replaceAll(str,"**");
                                }
                            }
                        }
                        return value;
                    }
                    return method.invoke(req,args);
                }
            });
            //2.放行
            chain.doFilter(proxy_req, resp);
        }
        private List<String> list = new ArrayList<>();//敏感词汇
        public void init(FilterConfig config) throws ServletException {
    
            try {
                //1.加载配置文件(获取文件的真实路径)
                ServletContext servletContext = config.getServletContext();
                String realPath = servletContext.getRealPath("/WEB-INF/classes/SensitiveWords.txt");
                //2.读取文件
                BufferedReader br = new BufferedReader(new FileReader(realPath));
                //3.将文件的每一行加载到list中
                String line =null;
                while ((line = br.readLine())!=null){
                    list.add(line);
                }
                br.close();
                System.out.println(list);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    
    

    测试的servlet:

    @WebServlet("/ServletSensitiveWordsTest")
    public class ServletSensitiveWordsTest extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String name = request.getParameter("name");
            String msg =request.getParameter("msg");
            System.out.println(name+":"+msg);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
        }
    }
    
    

    结果:
    在这里插入图片描述
    重点:注意路径问题:
    SensitiveWords在src源文件目录下。
    //1.加载配置文件(获取文件的真实路径)
    ServletContext servletContext = config.getServletContext();
    String realPath = servletContext.getRealPath
    ("/WEB-INF/classes/SensitiveWords.txt");

    05.动态代理

    实现步骤:
    1.代理对象和真实对象实现相同的接口。

    2.代理对象= Proxy.newProxyInstance();

    3.使用代理对象调用方法。

    4.增强方法。
    增强方式:
    1.增强参数列表。

    2.增强返回值类型。

    3.增强方法体执行逻辑。
    练习理解:

    package proxy;
    
    public interface SaleComputer {
        public String sale(double money);
        public void show();
    }
    
    
    /**
     * 真实类
     */
    public class ASUS implements SaleComputer{
        @Override
        public String sale(double money) {
            System.out.println("花了"+money+"拍下一台电脑!");
            return "ASUS";
        }
    
        @Override
        public void show() {
            System.out.println("展示电脑!");
        }
    }
    
    public class ProxyTest {
        public static void main(String[] args) {
            //创建真实对象
            ASUS asus1 = new ASUS();
            //动态代理增强ASUS对象
            /*
            三个参数:
            1.类加载器:真实对象.getClass().getClassLoader()
            2.接口数组:真实对象.getClass().getInterfaces()
            3.处理器:new InvocationHandler()
             */
            SaleComputer proxy_asus=(SaleComputer) Proxy.newProxyInstance(asus1.getClass().getClassLoader(), asus1.getClass().getInterfaces(), new InvocationHandler() {
                /**
                 * 代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
                 * @param proxy 代理对象
                 * @param method 代理对象调用的方法被封装成对象
                 * @param args 代理对象调用方法时,传递的实际参数
                 * @return
                 * @throws Throwable
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    /*System.out.println("该方法执行了...");
                    System.out.println(method.getName());*/
                    //使用真实对象调用该方法
                   /* Object obj = method.invoke(asus1,args);*/
    
                    //增强参数;判断是否时sale方法
                    if(method.getName().equals("sale")){
                        //增强参数
                        double money = (double)args[0];
                        money*=0.8;
                        //使用真实对象调用该方法
                        String  obj = (String) method.invoke(asus1,money);
    
                        //增强返回值类型
    
                        return  obj+"_鼠标垫";
                    }else {
                        Object obj = method.invoke(asus1,args);
                        return obj;
                    }
    
                }
            });
    
            //3.调用方法
            String computer = proxy_asus.sale(9000);
            System.out.println(computer);
        }
    }
    

    06.Listener概述

    概念:web的三大组件之一。
    事件监听机制
    程序开发中,经常需要对某些事件进行监听,如鼠标单击事件,监听键盘按下事件等,此时就需要监听器。

    事件:用户的一个操作,如点击按钮…

    事件源:产生事件的对象。

    监听器:负责监听发生在事件源上的事件。

    注册监听:将事件,事件源,监听器绑定在一起。当事件源上发生某个事件后,执行监听器代码。

    ServletContextListener:监听ServletContext对象的创建和销毁。

    //Servlet对象被销毁前会调用此方法
    void contextDestroyed(ServletContextEvent sce) 
    
    //ServletContext对象被创建后会调用该方法。
    void contextInitialized(ServletContextEvent sce)   
    

    07.ServletContextListener

    步骤:
    1.定义一个类实现ServletContextListener接口。

    2.复写方法。

    3.配置
    1.web.xml

    <listener>
            <listener-class>listener/ServletContextListenerTest1</listener-class>
        </listener>
    

    指定初始化参数:

    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/classes/applicationContext.xml</param-value>
        </context-param>
    

    2.注解配置

    @WebListener
    
    @WebListener
    public class ServletContextListenerTest1 implements ServletContextListener {
        //监听ServletContext创建,ServletContext对象服务器启动自动创建
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            //加载资源文件
            //1.获取ServletContext对象
            ServletContext servletContext = sce.getServletContext();
            //2.加载资源文件
            String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
            //3.获取真实路径
            String realPath = servletContext.getRealPath(contextConfigLocation);
            //4.加载进内存
            try {
                FileInputStream fis = new FileInputStream(realPath);
                System.out.println(fis);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        //在服务器关闭后,ServletContext对象被销毁。当服务器正常关闭后该方法被调用
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
    
        }
    }
    

    一切事无法追求完美,唯有追求尽力而为。这样心无压力,出来的结果反而会更好。

    在这里插入图片描述

    以梦为马,不负韶华。
  • 相关阅读:
    个人期末总结
    团队冲刺第二阶段10
    团队冲刺第二阶段9
    团队冲刺第二阶段8
    团队冲刺第二阶段7
    团队冲刺第二阶段6
    数据分析之例题
    数据分析之数据操作
    数据分析之Matplotlib可视化
    数据分析之Pandas
  • 原文地址:https://www.cnblogs.com/huangjiahuan1314520/p/14026206.html
Copyright © 2020-2023  润新知