Filter过滤器与Listener监听器

Filter: 过滤器

1. 概念:
    * 生活中的过滤器: 净水器、空气净化器、土匪等..
    * web中的过滤器: 当访问服务器的资源时, 过滤器可以将请求拦截下来, 完成一些特殊的功能.
    * 过滤器的作用:
    		* 一般用于完成通用的操作.: 登录验证、统一编码处理、敏感字符过滤...
        
2. 快速入门:
	1. 步骤:
		1. 定义一个类, 实现接口Filter
        2. 复写方法
        3. 配置拦截路径
          	1. web.xml
          	2. 注解
    2. 代码:
		@WebFilter("/*") // 访问所有资源之前, 都会执行该过滤器
        public class FilterDemo1 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("filterDemo1被执行了...");

                // 放行
                filterChain.doFilter(servletRequest, servletResponse);
            }

            @Override
            public void destroy() {

            }
        }

	3. 过滤器细节:
		1. web.xml配置
          	<filter>
                <filter-name>demo2</filter-name>
                <filter-class>cn.xiaoge.web.filter.FilterDemo2</filter-class>
            </filter>

            <filter-mapping>
                <filter-name>demo2</filter-name>
                <!-- 拦截路径 -->
                <url-pattern>/demo3</url-pattern>
            </filter-mapping>
            
        2. 过滤器执行流程
            1. 执行过滤器
            2. 执行放行后的资源
            3. 回来执行过滤器放行代码下边的代码
        	4.:
                // 对request对象请求消息增强
                System.out.println("filterDemo3执行了....");

                // 放行
                chain.doFilter(req, resp);

                // 对response对象的响应消息增强
                System.out.println("filterDemo3回来了...");

                * 请求消息来, 执行放行上面的代码, 然后执行servlet, 当返回响应时执行放行下面的代码, 在返回给客户端.
              
        3. 过滤器生命周期方法
        	1. init: 在服务器启动后, 会创建Filter对象, 然后调用init方法. 只执行一次. 用于加载资源.
            2. doFilter: 每一次请求被拦截资源时, 会执行. 执行多次.
            3. destroy: 在服务器关闭后, Filter对象被销毁, 如果服务器是正常关闭, 则会执行destroy方法. 只执行一次. 用于释放资源.
            4. 代码:
				@WebFilter("/*")
                public class FilterDemo4 implements Filter {

                    /**
                     * 每一次请求被拦截资源时, 会执行. 执行多次
                     * @param req
                     * @param resp
                     * @param chain
                     * @throws ServletException
                     * @throws IOException
                     */
                    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
                        System.out.println("doFilter....");

                        // 放行
                        chain.doFilter(req, resp);
                    }

                    /**
                     * 在服务器启动后, 会创建Filter对象, 然后调用init方法. 只执行一次. 用于加载资源
                     * @param config
                     * @throws ServletException
                     */
                    public void init(FilterConfig config) throws ServletException {
                        System.out.println("init......");
                    }

                    /**
                     * 在服务器关闭后, Filter对象被销毁, 如果服务器是正常关闭, 则会执行destroy方法. 只执行一次. 用于释放资源
                     */
                    public void destroy() {
                        System.out.println("destroy....");
                    }

                }

                
        4. 过滤器配置详解
          	* 拦截路径配置:
				1. 具体的资源路径: /index.jsp	       只有访问index.jsp资源时, 过滤器才会被执行.									2. 拦截目录: /user/* 					      访问/user下的所偶遇资源时, 过滤器都会被执行.
				3. 后缀名拦截: *.jsp					        访问所有后缀名为jsp资源时, 过滤器都会被执行.
				4. 拦截所有资源: /*						       访问所有资源时, 过滤器都会被执行.
								
			* 拦截方式配置: 资源被访问的方式
				* 注解配置:
						* 设置dispatcherTypes属性
								1. REQUEST: 默认值. 浏览器直接请求资源
								2. FORWARD: 转发访问资源
								3. INCLUDE: 包含访问资源
								4. ERROR: 错误跳转资源
								5. ASYNC: 异步访问资源
						* 代码:
							// 浏览器直接请求资源时, 该过滤器会被执行
	                        // @WebFilter(value = "/index.jsp", dispatcherTypes = DispatcherType.REQUEST)
	
	                        // 只有转发访问index.jsp, 该过滤器才会被执行
	                        // @WebFilter(value = "/index.jsp", dispatcherTypes = DispatcherType.FORWARD)
	
	                        // 浏览器直接请求index.jsp或者转发访问index.jsp. 该过滤器才会被执行
	                        // @WebFilter(value = "/index.jsp", dispatcherTypes = {DispatcherType.FORWARD, DispatcherType.REQUEST})

				* web.xml配置:
						* 设置<dispatcher></dispatcher>标签即可
        

        5. 过滤器链(配置多个过滤器)
				* 执行顺序: 如果有两个过滤器: 过滤器1和过滤器2
						1. 过滤器1
						2. 过滤器2
						3. 资源执行
						4. 过滤器2
						5. 过滤器1

				* 过滤器先后顺序问题:
						1. 注解配置: 按照类名字符串比较规则比较, 值小的先执行
								*: AFilter 和 BFilter, AFilter就先执行了

						2. web.xml: <filter-mapping>谁定义在上边, 谁先执行
								
		
	4. 案例:
    	1. 登录验证:
    		* 代码:					
    			// 1. 强制转换
                HttpServletRequest request = (HttpServletRequest) req;
                HttpServletResponse response = (HttpServletResponse)resp;

                // 2. 获取资源请求路径
                String uri = request.getRequestURI(); // URI是获取短路径, URL获取全路径

                // 3. 判断是否包含登入相关路径, 要注意排除掉 css/js/图片/验证码等资源
                if (uri.contains("/login.jsp") || uri.contains("/loginServlet") || uri.contains("/css/") || uri.contains("/js/") || uri.contains("/fonts/") || uri.contains("/checkCodeServlet")) {
                    // 包含, 用户就是想登入, 放行
                    chain.doFilter(req, resp);
                } else {
                    // 不包含, 判断用户是否登入过
                    HttpSession session = request.getSession();
                    User user = (User)session.getAttribute("user");

                    if (user != null) {
                        // user有值, 登入了, 放行
                        chain.doFilter(req, resp);

                    } else {
                        // 没值, 没有登入, 跳转到登入页面
                        // 设置域
                        request.setAttribute("login_msg", "您尚未登入, 请登入");
                        request.getRequestDispatcher("/login.jsp").forward(request, response);
                    }

                }
    				
    				
    2. 敏感词汇过滤:
    		* 分析:
				1. 对request对象进行增强. 增强获取参数相关方法
				2. 放行. 传递代理对象
					
			* 增强对象的功能:
					* 设计模式: 一些通用的解决固定问题的方式
					1. 装饰模式
					2. 代理模式
							* 概念:
								1. 真实对象: 被代理的对象
								2. 代理对象:
								3. 代理模式: 代理对象代理真实对象, 达到增强真实对象功能的目的
									
							* 实现方式:
									1. 静态代理: 有一个类文件描述代理模式
									2. 动态代理: 在内存中形成代理类
											* 实现步骤:
													1. 代理对象和真实对象实现相同的接口
													2. 代理对象 = Proxy.newProxyInstance();
													3. 使用代理对象调用方法.
													4. 增强方法
													
											* 增强方式:
													1. 增强参数列表
													2. 增强返回值类型
													3. 增强方法体执行逻辑
					
    		* 代码:
    			package cn.xiaoge.web.filter;

                import javax.servlet.*;
                import javax.servlet.annotation.WebFilter;
                import javax.servlet.http.HttpServletRequest;
                import java.io.*;
                import java.lang.reflect.InvocationHandler;
                import java.lang.reflect.Method;
                import java.lang.reflect.Proxy;
                import java.util.ArrayList;
                import java.util.List;

                /**
                 * @Author: HWB
                 * @DateTime: 2020/2/11 下午3:50
                 * @Description: 敏感词汇过滤器
                 */
                @WebFilter("/*")
                public class SensitiveWordsFilter implements Filter {

                    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
                        // 1. 创建代理对象, 增强getParameter方法
                        /*
                        	newProxyInstance参数:
                        		第一个参数: 类加载器(它使用的和被代理对象是相同的类加载器)
                        		第二个参数: 代理对象要实现的接口字节码数组(代理对象要实现的接口: 和被代理对象实现相同的接口)
                        		第三个参数: 如何代理(它是增强的方法, 我们需要自己来提供.此处是一个InvocationHandler的接口, 我们需要写一个该接口的实现类.)
                        	
                        */
                        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 {

                                // 2. 增强获取参数方法, getParameter
                                if ("getParameter".equals(method.getName())) {
                                    // 增强返回值
                                    // 获取返回值
                                    String value = (String) method.invoke(req, args);

                                    // 如果获取用户输入的值不为null
                                    if(value != null) {
                                        for (String s : list) {
                                            // 遍历集合, 判断用户输入的值中是否包含敏感词
                                            if (value.contains(s)) {
                                                // 把字符串里面的敏感词转换成***
                                                value = value.replace(s, "***");
                                                System.out.println(value);
                                            }

                                        }
                                    }
                                    return value;
                                }

                                // 判断方法名是否是 getParameterMap

                                // 判断方法名是否是 getParameterValue

                                return method.invoke(req, args);


                            }
                        });

                        // 放行, 传递代理对象
                        chain.doFilter(proxy_req, resp);
                    }

                    // 存储敏感词汇
                    private List<String> list = new ArrayList<>();

                    public void init(FilterConfig config) throws ServletException {
                        /*
                            FilterConfig: 常用的4个方法
                                getFilterName 方法,返回 <filter-name> 元素的设置值。

                                getServletContext 方法,返回 FilterConfig 对象中所包装的 ServletContext 对象的引用。

                                getInitParameter 方法,用于返回在 web.xml 文件中为 Filter 所设置的某个名称的初始化的参数值。

                                getInitParameterNames 方法,返回一个 Enumeration 集合对象。
                         */


                        // 1. 获取文件真实路径
                        ServletContext servletContext = config.getServletContext();
                        String path = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");

                        // 2. 读取文件
                        BufferedReader br = null;

                        try {

                            br = new BufferedReader(new FileReader(path));

                            String line = "";

                            while((line = br.readLine()) != null) {
                                // 每次读取一行, 存到list中
                                list.add(line);
                            }

                            System.out.println(list);

                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            if (br != null) {
                                try {
                                    br.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }

                    public void destroy() {

                    }

                }
    						

Listener: 监听器

* 概念: web的三大组件之一.
  	* 事件监听机制
  			 * 事件: 一件事情
				 * 事件源: 事件发生的地方 
				 * 监听器: 一个对象
				 * 注册监听: 将事件、事件源、监听器绑定在一起. 当事件源上发生某个事件后, 执行监听器代码.
           
   	* ServletContextListener: 监听ServletContext对象的创建和销毁
      	 * 方法:
             * void contextDestroyed(ServletContextEvent sce): ServletContext对象被销毁之前会调用该方法
             * void contextInitalized(ServletContextEvent sce): ServletContext对象创建后会调用该方法
               
         * 步骤:
			  1. 定义一个类, 实现ServletContextListener接口
              2. 复写方法
              3. 配置
                	1. web.xml:
					  * 配置:
						    <listener>
                            	<listener-class>cn.xiaoge.web.listener.ContextLoaderListener</listener-class>
                        	</listener>
                                
                      * 指定初始化参数:
						  <context-param>
                              <param-name>contextConfigLocation</param-name>
                              <param-value>/WEB-INF/classes/applicationContext.xml</param-value>
                          </context-param>
                	2. 注解:
					  * @WebListener
                        
         * 代码:
			  package cn.xiaoge.web.listener;

              import javax.servlet.ServletContext;
              import javax.servlet.ServletContextEvent;
              import javax.servlet.ServletContextListener;
              import javax.servlet.annotation.WebListener;
              import java.io.FileInputStream;
              import java.io.FileNotFoundException;

              /**
               * @Author: HWB
               * @DateTime: 2020/2/11 下午5:47
               * @Description: Listener监听器
               */
              @WebListener
              public class ContextLoaderListener implements ServletContextListener {

                  /**
                   * 监听ServletContext对象创建的. ServletContext对象服务器启动后自动创建.
                   *
                   * 在服务器启动后自动调用
                   * @param servletContextEvent
                   */
                  @Override
                  public void contextInitialized(ServletContextEvent servletContextEvent) {
                      // 加载资源文件

                      // 1. 获取ServletContent对象
                      ServletContext servletContext = servletContextEvent.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();
                      }

                      System.out.println("ServletContext对象被创建.....");
                  }

                  /**
                   * 在服务器关闭后, ServletContext对象被销毁. 当服务器正常关闭后该方法被调用.
                   * @param servletContextEvent
                   */
                  @Override
                  public void contextDestroyed(ServletContextEvent servletContextEvent) {
                      System.out.println("ServletContext对象被销毁.....");
                  }
              }

发布了323 篇原创文章 · 获赞 104 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/zsx1314lovezyf/article/details/104267867