Java-1115

Filter:过滤器

  1. 概念:

    1. web过滤器:拦截浏览器的请求,完成一些特殊功能。
    2. 过滤器作用:一般用于完成通过的操作。(例如帮助服务器检查一些字段是否携带,比如访问界面的时候需要带token,否则返回登录界面)
  2. 快速入门:

    1. 步骤:
      1. 定义一个类,实现接口Filter
      2. 复写方法
      3. 配置拦截路径(定义访问什么资源的时候,过滤器生效),两种配置方法
        1. Web.xml
        2. 注解 @WebFilter( )我们需要配置里面的urlPatten这个属性,这个属性等于value,所以可以省略不写。
          1. @WebFilter(“/*”) 代表访问所有资源的时候都会拦截
  3. 过滤器细节:

    1. web.xml配置

      <filter>
          <filter-name>demo1</filter-name>
          <filter-class>com.emnets.java1115.Filter.FilterDemo1</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>demo1</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      
    2. 过滤器的执行流程

      1. doFilter方法中:req就是请求参数,

        1. 首先执行chain.doFilter(req,resp)方法之前的代码,可能会有一些对req参数的校验,如果通过就放行
        2. chain.doFilter(req,resp) 这个方法是放行方法,就是让服务器去处理请求
        3. 执行完放行后会回到chain.doFilter(req,resp)这个方法的下一行代码继续执行。
        //  对request对象的请求消息增强
        System.out.println("filterDemo2...");
        //  放行
        chain.doFilter(request, response);
        //  对response对象的响应消息增强
        System.out.println("filterDemo2 executing!");
        
    3. 过滤器生命周期方法

      1. init方法:服务器启动后会创建Filter对象,然后调用init方法,服务器自动完成(仅执行一次)用于加载资源
      2. doFilter方法:每一次请求被拦截资源时会执行,方法内包含拦截的逻辑
      3. destroy方法:服务器关闭之后。Filter对象被销毁。如果服务器正常关闭,则会执行destroy(仅执行一次)释放资源
    4. 过滤器的配置详解(两种配置)

      1. 拦截路径配置:

        1. “/*”:拦截所有资源
        2. “/资源”:具体资源路径,只有访问资源时过滤器才会执行,使用较少。
        3. “/user/*”:目录拦截,访问user目录下的所有资源时,过滤器都会执行。
        4. “*.jsp”:后追拦截,访问所有后缀名为jsp的资源时,过滤器都会拦截。
      2. 拦截方式配置:资源访问的方式(直接请求、转发是两种不同的方式)

        1. 注解配置:设置dispatcherTypes的属性

          1. REQUEST:默认值,浏览器直接请求资源(重要)
          2. FORWARD:转发访问资源(重要)
          3. INCLUDE:包含访问资源
          4. ERROR:错误跳转资源
          5. ASYNC:异步访问资源
        2. 注解配置多个值:

          1. @WebFilter(value = "/*",dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})
            
        3. web.xml配置方式:

          1.    <filter>
                    <filter-name>demo1</filter-name>
                    <filter-class>com.emnets.java1115.Filter.FilterDemo1</filter-class>
                </filter>
                <filter-mapping>
                    <filter-name>demo1</filter-name>
                    <url-pattern>/*</url-pattern>
                    <dispatcher>FORWARD</dispatcher>
                    <dispatcher>REQUEST</dispatcher>
                </filter-mapping>
            
        4. 思考题:如果同时配置了请求和转发的过滤,那么一次请求触发的转发会触发几次过滤器

          1. 答案:2次 ,请求和转发分别都会触发过滤器
          2. 理解:虽然是一次请求,但是在服务器内部进行了跳转,每次切换资源都会触发过滤器
    5. 过滤器链(配置多个过滤器)

      1. 执行顺序 :如果有两个过滤器:f1 和 f2
        1. f1执行
        2. f2执行
        3. 资源执行
        4. f2回来执行
        5. f1回来执行
      2. 过滤器设计的先后顺序:
        1. 注解配置:按照类名的字符串比较规则比较,值小的先执行,
          1. 例如:AFilter 和 BFilter比较,A先执行
        2. web.xml配置:<filter-mapping> 谁定义在上面,谁先执行
    6. 案例一:登录验证

      1. 步骤:
        1. 排除登录相关的资源,
          1. 是:直接放行
          2. 不是:判断是否已经登录
            1. 未登录:
            2. 已登录:
      @Override
      public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
      
          //  0.强制转换
          HttpServletRequest request = (HttpServletRequest)req;
          
          //  1.获取请求资源的请求路径
          String requestURI = request.getRequestURI();
      
          //  2.判断是否包含登录相关
          //  2.1 同时还要注意排除各种css/js/图片/验证码等资源
          if(requestURI.contains("/login.jsp")||requestURI.contains("/loginServlet")
                  ||requestURI.contains("/css/*")||requestURI.contains("/js/*")||requestURI.contains("/checkCodeServlet")){
              //  放行登录
              chain.doFilter(req, resp);
          }else {
              //  3.session获取
              Object user = request.getSession().getAttribute("user");
              if(user!=null){
                  //  已经登录了 ,放行
                  chain.doFilter(req, resp);
              }else {
                  //  跳转登录
                  request.setAttribute("login_msg","您尚未登录");
                  request.getRequestDispatcher("/login.jsp").forward(request,resp);
              }
          }
      
      }
      
    7. 代理模式:

      1. 理解:在运行期间,对象中方法的动态拦截,在拦截前后执行功能操作,而原有对象不改变

      2. 概念:

        1. 真实对象:被代理的对象
        2. 代理对象:
        3. 代理模式:代理对象去代理真实对象,达到增强真是对象功能的目的
      3. 实现方式:(区别在于代理对象的生成方式)

        1. 静态代理:由一个类文件描述代理模式
        2. 动态代理:在内存中形成代理类(看不到一个真正的类文件,会在内存中动态生成)
          1. 实现步骤:
            1. 代理对象和真实对象实现相同的接口
            2. 代理对象 = Proxy.newProxyInstance( );进行代理对象的获取
            3. 使用代理对象调用方法。
            4. 增强方法
        3. 动态代理代码:
        public class ProxyTest {
        
            /**
             *
             * @param args
             */
            public static void main(String[] args) {
                //  1.创建真实对象
                Lenovo lenovo = new Lenovo();
        
                /**
                 *   2.动态代理增强lenovo对象
                 *   三个参数:
                 *      1.类加载器 : 真实对象.getClass().getClassLoader()
                 *      2.接口数组 : 真实对象.getClass().getInterfaces()
                 *      3.处理器   :
                 */
                SaleComputer proxy_lenovo = (SaleComputer)Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
                    /**
                     * 代理逻辑编写的方法:代理对象调用的所有方法,都会触发该方法执行。
                     * 增强代码的逻辑就会在这个方法中执行
                     * @param proxy 代理对象,就是指proxy_lenovo这个对象,一般不用
                     * @param method 代理对象调用的方法会封装成对象,变成参数传递进来
                     * @param args 代理对象调用方法时,传递的实际参数,封装进args,这里面就会有8000这种参数
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("该方法执行了.....");
                        System.out.println(method.getName());
                        return null;
                    }
                });
        
                //  3.调用方法
                String  computer = proxy_lenovo.sale(8000);
                System.out.println(computer);
            }
        }
        
      4. invoke方法的写法

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
               //  相当于使用真实对象调用该方法
               Object obj = method.invoke(lenovo, args);
        
               //  思考:方法应该如何增强
        
               //  这个返回值就是调用了方法后接收的返回值,会根据操作方法的不同而完全不同。
               return obj;
        }
        
      5. 方法增强方式:

        1. 增强参数列表

          @Override
                      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                          
                          //  首先判断方法是否是需要增强的方法
                          if(method.getName().equals("sale")){
                              //  1.增强参数
                              double money = (double) args[0];
                              money *= 0.85;
                              Object obj = method.invoke(lenovo, money);
                              return obj;
                          }else {
                              
                              //  相当于使用真实对象调用该方法
                              Object obj = method.invoke(lenovo, args);
          
                              //  这个返回值就是调用了方法后接收的返回值,会根据操作方法的不同而完全不同。
                              return obj;
                          }
          
                      }
          
        2. 增强返回值类型

           @Override
                      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          
                          //  首先判断方法是否是需要增强的方法
                          if(method.getName().equals("sale")){
                              //  1.增强返回值
                              double money = (double) args[0];
                              money *= 0.85;
                              String obj = (String)method.invoke(lenovo, money);
                              return obj+"_鼠标垫";
                          }else {
                              //  相当于使用真实对象调用该方法
                              Object obj = method.invoke(lenovo, args);
                              //  这个返回值就是调用了方法后接收的返回值,会根据操作方法的不同而完全不同。
                              return obj;
                          }
                      }
          
        3. 增强方法体执行逻辑

          @Override
                      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          
                          //  首先判断方法是否是需要增强的方法
                          if(method.getName().equals("sale")){
                              //  1.增强返回值
                              double money = (double) args[0];
                              money *= 0.85;
                              System.out.println("专车接你....");
                              String obj = (String)method.invoke(lenovo, money);
                              System.out.println("免费送货....");
                              return obj+"_鼠标垫";
                          }else {
                              //  相当于使用真实对象调用该方法
                              Object obj = method.invoke(lenovo, args);
                              //  这个返回值就是调用了方法后接收的返回值,会根据操作方法的不同而完全不同。
                              return obj;
                          }
                      }
          
    8. 案例二:过滤敏感词汇

      1. 需求:
        1. 对录入数据的敏感词汇进行过滤
        2. 敏感词汇为“笨蛋”、“坏蛋”
        3. 如果是敏感词汇,替换为“***”
      2. 分析:
        1. 对request对象的getParameter方法进行增强,增强获取参数相关方法
        2. 放行。传递代理对象
      /**
       * 敏感词汇过滤器
       */
      
      @WebFilter("/*")
      public class SensitiveWordsFilter implements Filter {
      
          private List<String> list = new ArrayList<String>();    //  敏感词汇
      
          public void init(FilterConfig config) throws ServletException {
      
              try {
                  //  加载文件,获取文件真实路径
                  ServletContext servletContext = config.getServletContext();
                  String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
                  //  读取文件
                  BufferedReader br = new BufferedReader(new FileReader(realPath));
                  //  将文件的每一行数据添加到list中
                  String line = null;
                  while ((line = br.readLine())!=null){
                      list.add(line);
                  }
      
                  br.close();
                  System.out.println(list);
      
              } catch (Exception e){
                  e.printStackTrace();
              }
      
          }
      
          public void destroy() {
          }
      
          @Override
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
      
              //  1.创建代理对象,增强getParameter方法
              ServletRequest proxy_req = (ServletRequest)Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
                  @Override
                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      
                      if(method.getName().equals("getParameter")){
                          //  增强返回值
                          //  获取返回值,对返回值进行过滤
                          String value = (String)method.invoke(request, args);
                          if(value!=null){
                              for(String str:list){
                                  if(value.contains(str)){
                                      value = value.replaceAll(str,"***");
                                  }   // if
                              }   //for
      
                          }// if
                          return value;
                      }
                      return method.invoke(request,args);
                  }
              });
      
              //  2.放行,传递代理对象
      
      
              chain.doFilter(proxy_req, response);
          }
      }
      

      为了测试编写了一个servlet一起运行:

      @WebServlet("/testServlet")
      public class TestServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              this.doPost(request, response);
          }
      
          @Override
          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);
      
          }
      }
      
    9. 补充了对getParameterMap方法的增强:

      @Override
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
      
              //  1.创建代理对象,增强getParameter方法
              ServletRequest proxy_req = (ServletRequest)Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
                  @Override
                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      
                      if(method.getName().equals("getParameter")){
                          //  增强返回值
                          //  获取返回值,对返回值进行过滤
                          String value = (String)method.invoke(request, args);
                          if(value!=null){
                              for(String str:list){
                                  if(value.contains(str)){
                                      value = value.replaceAll(str,"***");
                                  }   // if
                              }   //for
      
                          }// if
                          return value;
                      }else if(method.getName().equals("getParameterMap")){
                          Map<String, String[]> parameterMap = (Map<String, String[]>)method.invoke(request,args);
                          if(!parameterMap.isEmpty()){
                              // 遍历参数列表
                              for(String[] p_value: parameterMap.values()){
                                  //  判断是否有子参数
                                  if(p_value.length>0){
                                      //  遍历子参数
                                      for(int i=0;i<p_value.length;i++){
                                          //  遍历敏感词汇
                                          for(String str:list){
                                              //  判断是否含有敏感词汇
                                              if(p_value[i].contains(str)){
                                                  //  有则替换
                                                  p_value[i] = p_value[i].replaceAll(str,"***");
                                              }
                                          }
                                      }
                                  }
                              }
                          }
                          return parameterMap;
                      }
                      return method.invoke(request,args);
                  }
              });
      
              //  2.放行,传递代理对象
      
      
              chain.doFilter(proxy_req, response);
          }
      

Listener:监听器

  1. 概念:web的三大组件之一。

    1. 事件监听机制:
      1. 事件 :一件事情
      2. 事件源 :事件发生的地方
      3. 监听器 :一个对象
      4. 注册监听:将事件、事件源、监听器绑定在一起。当事件源上发生某个事件后,执行监听器代码。
  2. ServletContextListener:监听ServletContext对象的创建和销毁

    1. void contextDestory(ServletContextEvent sce): servletContext对象被销毁前会调用
    2. void contextInitialized(ServletContextEvent sce):servletContext创建之后会调用该方法
  3. 步骤:

    1. 定义一个类,实现servletContextListener接口

    2. 复写方法

    3. 配置

      1. web.xml方式

         <listener>
                <listener-class>com.emnets.java1115.listener.ContextLoaderListener</listener-class>
            </listener>
        
      2. 注解方式

        @WebListener
        
  4. 代码:

    public class ContextLoaderListener implements ServletContextListener {
    
        /**
         * 监听servletContext对象创建。ServletContext对象服务器启动后自动创建。
         * @param sce
         */
        @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();
            }
    
            System.out.println("servletContext对象被创建了");
        }
    
    
        /**
         * 服务器关闭后,ServletContext对象被销毁,当服务器正常关闭后该方法被调用
         * @param sce
         */
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            System.out.println("ServletContext对象被销毁了");
        }
    }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值