zoukankan      html  css  js  c++  java
  • Java Web-Filter and listener

    Java Web-Filter and listener

    Filter:过滤器

    概述

    拦截请求,完成一些特殊的功能。

    过滤器的作用:

    1. 一般用于完成通用的一些操作,例如登录验证(通过session来判断访问是否登录,在未登录之前拦截资源访问请求并强制要求登录)、统一编码处理(统一设置request.setCharacterEncoding("utf-8"))、敏感字符的过滤(例如脏话替换为星号)

    快速入门

    1. 步骤:

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

        注意,有多个包中有Filter接口,我们要的是javax.servlet包下的

      2. 复写对应的方法

      3. 配置拦截路径

        1. 通过web.xml配置
        2. 通过注解配置
    2. 示例:

      package com.jiading.filter;
      
      import javax.servlet.*;
      import javax.servlet.annotation.WebFilter;
      import java.io.IOException;
      @WebFilter("/*")//配置的是urlPattern,对当前目录下的所有资源都添加filter
      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() {
      
          }
      }
      

      如果使用web.xml配置:

      如果要使用web.xml进行配置,我们当然先要为项目配置一个web.xml。

      配置过程和配置servlet很像

      <filter>
      	<filter-name>demo1</filter-name>
          <filter-class>com.jiading.filter.FilterDemo1</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>demo1</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-maping>
      

    细节

    1. 过滤器执行流程

      filter对于一次访问的request和response都要检查一遍

      放行代码之前的代码是对于request的检查

      放行代码之后的代码是对于response的检查

    2. 过滤器生命周期方法

      filter对象在服务器启动后就创建,然后调用init方法

      在服务器关闭时,filter对象被销毁。如果是正常关闭服务器,则会执行destory方法

      每一次请求被拦截时,doFilter方法都被执行

    3. 过滤器配置详解

      1. 拦截路径的配置

        1. 具体资源路径:例如/index.jsp
        2. 拦截目录:例如/user/*
        3. 后缀名拦截:*.jsp
        4. 拦截所有资源:例如/*
      2. 拦截方式的配置

        指的是资源被访问的方式,例如浏览器直接访问、重定向、转发等

        拦截方法的配置同样有两种方法:注解配置和web.xml配置

        1. 注解配置

          设置@WebFilter的dispatcherTypes属性,有五种可能属性

          1. REQUEST,默认值,拦截浏览器直接请求的资源
          2. FORWARD,拦截转发访问
          3. INCLUDE,拦截包含访问资源
          4. ERROR,拦截错误跳转(errorPage)
          5. ASYNC,拦截异步访问资源
        2. web.xml配置

          <filter-mapping>标签下设置<dispatcher>子标签

    4. 过滤器链(配置多个过滤器)

      对于一条访问,可以配置多个过滤器,形成所谓的“过滤器链”

      执行顺序:过滤器1-》过滤器2-》资源访问-》过滤器2-》过滤器1

      当拦截路径有重叠时,确定过滤器先后顺序:

      1. 注解配置

        按照类名的字符串比较规则来比较,值小的先执行,例如一个叫A,一个叫B,那么A就先执行。

      2. web.xml配置

        哪个<filter-mapping>定义在上边,谁就先执行

    5. 举例

    权限控制(登录验证)

    1. 判断是否是与登录相关的资源。如果是,则直接放行;反之则拦截,判断是否已经登录,也就是session里面是否有user

      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
          //1.强制转换
          HttpServletRequest request=(HttpServletRequest)req;
          //2.获取资源请求路径
          String url=request.getRequestURI();
          //3.判断是否包含登录相关资源路径
          if(uri.contains("/login.jsp")||uri.contains("/loginServlet")||uri.contains(<登录页面需要的图片、验证码、CSS等资源>)){
              //证明用户此时的请求就是想要登录,直接放行
              chain.doFilter(req,resp);
          }else{
              //验证用户是否登录,从session中获取user
              request.getSession().getAttribute("user");
              if(user!=null)//说明用户已经登录了
                  chain.doFilter(req,resp);
              else{
                  //跳转登录页面
                  request.setAttribute("login_msg","您尚未登录,请登录");
                  request.getRequestDispatcher("/login.jsp").forward(request,resp);
              }
          }
      }
      
    2. 敏感词汇过滤

      对request对象进行增强,采用设计模式来完成,有23中Java设计模式。装饰模式、代理模式都可以用来增强对象的功能。这里我们选择代理模式的动态代理。

      关于代理模式、装饰模式,可以看我的这篇博文

      代理模式:

      1. 概念

        真实对象:被代理的对象

        代理对象

        代理模式:代理对象来通过代理的方式来增强真实对象的功能

      2. 实现方式

        • 静态代理:有一个类文件描述代理模式
        • 动态代理:在内存中形成代理类

        动态代理用的比较多,这里我们就使用动态代理

      3. 实现步骤

        1. 代理对象和真实对象实现相同的接口

        2. 实例化真实对象

        3. 使用Proxy.newProxyInstance(classLoader,Class,InvocationHandler)来获取代理对象

          classLoader:被代理对象的类加载器

          Class:数组,真实对象实现的接口

          InvocationHandler:一般通过匿名内部类创建该对象

        4. 使用代理对象来调用方法(因为实现了相同的接口,所以可以直接调用代理对象)

        5. 增强方法

          1. 增强参数列表
          2. 增强返回值类型
          3. 增强方法体执行逻辑
      4. 示例:示例程序见我的这篇博文

      5. 实现:

        我们使用过滤器对除登录页面之外的所有页面进行过滤,在过滤器内对ServletRequest对象进行代理,该代理对象对getParameters等获取用户输入参数的方法进行增强:通过遍历敏感词数组检查用户输入参数是否包括敏感词(敏感词数组在init()方法中已经加载到了内存中,保存在过滤器对象内),如果包含,就将敏感词进行替换后返回。

        这样,如果服务器要调用该对象的getParameters()、getParameterMap()、getParameterValue()等方法来获取用户输入的值时,就会因为方法名被拦截下来,拆包、替换。

        因为服务器在通信中只需要获取用户传入的参数,也就是request中的参数,所以凭方法名就可以有效拦截

        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{
                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);
            }
            
        })
        

    Listener:监听器

    概念

    Web三大组件之一

    • 事件的监听机制
    1. 事件:都懂得
    2. 事件源:事件发生的对象
    3. 监听器:一段代码或者一个对象
    4. 注册监听:将事件、事件源、监听器绑定在一起。当时间源上发生某个事件后,执行监听器代码
    • ServletContextListener

      是一个接口,没有对应的实现类,需要自己写

      方法:

      1. void contextInitialized(ServletContext sce),初始化
      2. void contextDestroyed(ServletContext sce),销毁时调用

      这部分用的不多,是略讲的:

      步骤:

      1. 定义一个类来实现该接口

      2. 复写方法

      3. 配置:web.xml或者注解

        • web.xml

          <listener>
          	<listener-class>com.jiading.filter.Listener</listener-class>
          </listener>
          
        • 注解

          @WebListener
          

      示例:

      Listener.java

      import javax.servlet.ServletContext;
      import javax.servlet.ServletContextEvent;
      import javax.servlet.ServletContextListener;
      import java.io.FileInputStream;
      import java.io.FileNotFoundException;
      
      public class Listener implements ServletContextListener {
          /*
          在服务器启动后自动创建,用来监听ServletContext对象(也是服务器启动时自动创建)
           */
          @Override
          public void contextInitialized(ServletContextEvent servletContextEvent) {
              //一般用来加载资源文件:
              //1.加载ServletContext对象
              ServletContext servletContext = servletContextEvent.getServletContext();
              //2.加载资源文件
              String initParameter = servletContext.getInitParameter("contextConfigLocation");
              //3.获取真实路径
              String realPath = servletContext.getRealPath(initParameter);
              //4.加载资源文件进内存
              try {
                  FileInputStream fis=new FileInputStream(realPath);
              } catch (FileNotFoundException e) {
                  e.printStackTrace();
              }
              //我们可以在web.xml中指定初始化信息,详见web.xml
              System.out.println("ServletContextListener被创建了");
          }
      
          @Override
          public void contextDestroyed(ServletContextEvent servletContextEvent) {
              System.out.println("ServletContextListener被销毁了");
          }
      

      在web.xml中可以创建ServletContext的参数:

          <context-param>
              <param-name>contextConfigLocation</param-name>
              <param-value>/test.xml</param-value>
          </context-param>
      

    真正使用时,监听器一般是框架写好的,一般使用的时候会配置就可以了

  • 相关阅读:
    <--------------------------常用的API方法------------------------------>
    <--------------------------构造方法------------------------------>
    <--------------------------Java多态如何使用------------------------------>
    <--------------------------Java接口如何使用------------------------------>
    <--------------------------Java继承及抽象类------------------------------>
    Eclipse工具的设置
    Java数组逆序排列
    Java打印九九乘法表及倒打九九乘法表
    Java打印水仙花数
    Java实现选择排序以及冒泡排序
  • 原文地址:https://www.cnblogs.com/jiading/p/12029888.html
Copyright © 2011-2022 走看看