zl程序教程

您现在的位置是:首页 >  Java

当前栏目

Servlet中的监听器和过滤器相关知识点整理

2023-03-14 22:55:06 时间

监听器和过滤器

过滤器的概念

概念:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能

过滤器的作用

作用: 一般用于完成通用的操作,例如: 登录验证,统一编码处理,敏感字符过滤

过滤器快速入门

步骤

  • 定义一个类,实现Filter接口
  • 复写方法
  • 配置拦截路径

1.web.xml方式配置 2.注解方式配置 3.过滤器的生命周期方法 4.过滤器配置详解 5.过滤器链

注解配置方式演示:

@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("过滤器被执行了");
        //放行---不然资源无法通过,到达浏览器显示
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
    }
}

xml配置演示

    <filter>
        <filter-name>demo1</filter-name>
        <filter-class>com.FL.flDemo2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>demo1</filter-name>
        <!--拦截所有资源路径-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

过滤器的执行流程

public class flDemo2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
       //对request对象请求消息增强
        System.out.println("第一次经过过滤器");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
        //回来的时候,不会重新执行do方法,而是执行放行下面的代码
        //对response对象的响应消息增强
        System.out.println("第二次经过过滤器");
    }

    @Override
    public void destroy() {

    }
}

回来的时候,不会重新执行do方法,而是执行放行下面的代码


doFilter方法: 每一次请求被拦截资源时,会执行,执行多次

init方法:服务器启动后,会创建Filter对象,然后调用init方法,只执行一次,用于加载资源

destroy方法:服务器关闭后,Filter对象被销毁时调用。如果服务器被正常关闭,则会指向destory方法,只执行一次,用于释放资源


拦截路径的配置

拦截目录指的是要访问指定资源时,自己设置的访问路径,访问路径通过注解或者xml配置文件设置—urlPattern


拦截方式的配置----资源被访问的方式

注解配置


xml配置

在标签内部放入如上五个选择其一即可完成设置


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

执行顺序

过滤器的先后顺序问题

字符串比较大小,是从第一个字符的大小开始比较


登录验证案例

注意:


过滤敏感词汇

分析: 需要对request对象进行增强

增强对象的功能

设计模式: 一些通用的解决问题的固定方式

1.装饰模式
2.代理模式
实现步骤

接口:

package test;

public interface ProxyInterface {
    void sale(int money);
    void show();
}

实现接口的真实类:

package test;

public class Proxy1 implements ProxyInterface{
    @Override
    public void sale(int money) {
        System.out.println("价钱为:"+money);
    }

    @Override
    public void show() {
        System.out.println("show方法的调用");
    }
}

测试主类:

public class main {
    public static void main(String[] args) {
        //动态代理增强proxy对象
        //第一个参数: 类加载器: 真实对象.class.getClassLoader()
        //第二个参数: 接口数组:真实对象.class.getInterfaces()
        //第三个参数: 处理器:InvocationHandler
        Proxy1 p=new Proxy1();
        //代理对象和真实对象实现相同接口
         ProxyInterface pi= (ProxyInterface) Proxy.newProxyInstance(p.getClass().getClassLoader(), p.getClass().getInterfaces(), new InvocationHandler() {
           /*
           * 代理逻辑编写的方法,代理对象调用的所有方法都会触发该方法执行
           * proxy: 代理对象---》pi
           * method: 代理对象调用的方法,被封装为的对象
           * args: 代理对象调用方式时,传递的实际参数
           * */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("invoke方法执行");
                System.out.println(method.getName());
                System.out.println(args[0]);
                return null;
            }
        });
         pi.sale(8000);
    }
}

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

调用有参方法:

        //动态代理增强proxy对象
        //第一个参数: 类加载器: 真实对象.class.getClassLoader()
        //第二个参数: 接口数组:真实对象.class.getInterfaces()
        //第三个参数: 处理器:InvocationHandler
        Proxy1 p=new Proxy1();
        //代理对象和真实对象实现相同接口
         ProxyInterface pi= (ProxyInterface) Proxy.newProxyInstance(p.getClass().getClassLoader(), p.getClass().getInterfaces(), new InvocationHandler() {
           /*
           * 代理逻辑编写的方法,代理对象调用的所有方法都会触发该方法执行
           * proxy: 代理对象---》pi
           * method: 代理对象调用的方法,被封装为的对象
           * args: 代理对象调用方式时,传递的实际参数
           * */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String s =(String)method.invoke(p, 8000);
                return s;
            }
        });
        String sale = pi.sale(8000);
        System.out.println(sale);

增强方式

接口:

public interface ProxyInterface {
    String sale(double money);
    void show();
}

被代理类:

public class Proxy1 implements ProxyInterface{
    @Override
    public String sale(double money) {
        System.out.println("花了"+money+"买联想电脑");
        return "联想电脑";
    }

    @Override
    public void show() {
        System.out.println("联想电脑展示...");
    }
}

测试主类:

public class main {
    public static void main(String[] args) {
        //动态代理增强proxy对象
        //第一个参数: 类加载器: 真实对象.class.getClassLoader()
        //第二个参数: 接口数组:真实对象.class.getInterfaces()
        //第三个参数: 处理器:InvocationHandler
        Proxy1 p=new Proxy1();
        //代理对象和真实对象实现相同接口
         ProxyInterface pi= (ProxyInterface) Proxy.newProxyInstance(p.getClass().getClassLoader(), p.getClass().getInterfaces(), new InvocationHandler() {
           /*
           * 代理逻辑编写的方法,代理对象调用的所有方法都会触发该方法执行
           * proxy: 代理对象---》pi
           * method: 代理对象调用的方法,被封装为的对象
           * args: 代理对象调用方式时,传递的实际参数
           * */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //1,增强参数
                //判断是否是sale方法
                if(method.getName().equals("sale"))
                  {
                      //1.增强参数---将调用方法时传入的参数值,变为百分之85,在传回
                      double money=(double)args[0];
                      money*=0.85;
                      //增强方法体的逻辑
                      System.out.println("免运费");
                      //使用真实对象调用方法
                      String obj = (String)method.invoke(p, money);
                      //2,增强返回值类型
                      return obj+"和赠送的鼠标垫和键盘";
                  }
                else
                {
                    String obj = (String)method.invoke(p, args);
                    return obj;
                }
            }
        });
        String sale = pi.sale(8000);
        System.out.println(sale);
    }
}


监听器—Listener

监听器机制


步骤

配置web.xml方式—注册监听

    <!--配置监听
     注册监听
    -->
    <listener>
        <listener-class>com.FL.Listener</listener-class>
    </listener>

注解配置,不需要指定路径—注册监听

@WebListener

监听器对于我们来说,多用来配置资源

演示:

Listener监听器对象:

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

}

web.xml中可以指定要导入的资源文件:

    <!--指定初始化参数信息-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/applicationContext.xml</param-value>
    </context-param>

生命周期监听器