Filter & Listener

文章目录

    • [一 过滤器(Filter)](#一 过滤器(Filter))
      • [1 什么是过滤器](#1 什么是过滤器)
      • [2 为什么使用过滤器](#2 为什么使用过滤器)
      • [3 过滤器执行流程](#3 过滤器执行流程)
      • [4 过滤器的生命周期](#4 过滤器的生命周期)
      • [5 过滤器的注册](#5 过滤器的注册)
        • [5.1 XML方式](#5.1 XML方式)
        • [5.2 @WebFilter 注解方式](#5.2 @WebFilter 注解方式)
      • [6 FilterConfig](#6 FilterConfig)
      • [7 过滤器链](#7 过滤器链)
      • [8 过滤器应用](#8 过滤器应用)
    • [二 什么是监听器](#二 什么是监听器)
      • [1 监听器分类](#1 监听器分类)
      • [2 监听器使用](#2 监听器使用)
        • [2.1 监听对象的创建](#2.1 监听对象的创建)
        • [2.2 注册监听器](#2.2 注册监听器)
        • [2.3 监听对象中属性的变化](#2.3 监听对象中属性的变化)
      • [3 注册监听器](#3 注册监听器)
        • [3.1 XMl方式](#3.1 XMl方式)
        • [3.2 @WebListener注解方式](#3.2 @WebListener注解方式)
        • [3 应用](#3 应用)

一 过滤器(Filter)

1 什么是过滤器

通过Filter可以对web服务器管理的所有web资源,如JSP, Servlet, 静态图片文件或静态html 文件等进行拦截,从而实现一些特殊的功能。

Filter不能通过url直接访问

过滤器本身并不产生请求和响应对象,它只能提供过滤作用。

过滤器能够在web资源被调用之前检查request对象,修改request Header和request内容;在Servlet被调用之后检查response对象,修改response Header和response内容。

2 为什么使用过滤器

访问资源时,针对不同的资源可能会执行很多相同的逻辑操作,如编码的设置,登录权限的判断等,借助Filter中的代码复用,可以提高开发效率

3 过滤器执行流程

注意:过滤器并不是必须要将请求传递到下一个过滤器或目标资源,它可以自行对请求进行处理,并发送响应给客户端,也可以将请求转发或重定向到其他的 Web 资源。

4 过滤器的生命周期

1)创建和初始化阶段

​ Tomcat服务器启动时,如果应用中存在filter,会创建filter对象,并调用其初始化方法。filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象

2)拦截和过滤阶段

​ 通过chain.doFilter()进行实际的过滤操作,可以访问后续的资源,访问资源后,会回到doFilter方法中

3)销毁阶段

​ 当应用重新加载,或者关闭tomcat服务器时,会销毁filter对象

创建Filter对象

java 复制代码
public class FirstFilter implements Filter {

    /**
     * Default constructor. 
     */
    public FirstFilter() {
        // TODO Auto-generated constructor stub
    	System.out.println("first filter constructor");
    }

	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		// TODO Auto-generated method stub
		System.out.println("first filter destroy");
	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	// 核心方法,针对filter逻辑,写到该方法中
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		// place your code here
		System.out.println("first filter before");
		// 放行请求,如果有其他的filter,继续访问filter,如果没有,访问目标资源
		// 多个filter的访问顺序,由filter在web.xml中的注册顺序决定
		chain.doFilter(request, response);
		System.out.println("first filter after");
	}

	/**
	 * @see Filter#init(FilterConfig)
	 */
	// 一个filter对应一个FilterConfig对象
	public void init(FilterConfig fConfig) throws ServletException {
		// TODO Auto-generated method stub
		System.out.println("first filter init");
		
		// 获取filter的初始化参数
		String value = fConfig.getInitParameter("aaa");
		System.out.println(value);
		
	}

}

注册Filter

xml 复制代码
<filter>
    <display-name>FirstFilter</display-name>
    <filter-name>FirstFilter</filter-name>
    <filter-class>com.qianfeng.filter.FirstFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

5 过滤器的注册

5.1 XML方式

在web.xml中对Filter进行注册,设置拦截的资源,一般设置为"/*",对任意资源都进行过滤

xml 复制代码
<filter>
    <display-name>FirstFilter</display-name>
    <filter-name>FirstFilter</filter-name>
    <filter-class>com.qianfeng.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>FirstFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

用于注册过滤器

用于指定过滤器的注册名,该元素的内容不能为空。

用于指定过滤器的完整限定名(包名+类名)。

元素用于设置 Filter 负责拦截的资源。

用于设置 Filter 的注册名,该值必须在 元素的子元素 中声明过。

用于设置 Filter 拦截的请求路径。

5.2 @WebFilter 注解方式
属性名 描述
filterName 指定过滤器的 name 属性,等价于 。
urlPatterns 指定过滤器的 URL 匹配模式。等价于 标签。
value 该属性等价于 urlPatterns 属性,但是两者不能同时使用。
servletNames 指定过滤器将应用于哪些 Servlet。取值是 @WebServlet 中 filterName 属性的取值,或者 web.xml 中 的取值。
dispatcherTypes 指定过滤器拦截的资源被 Servlet 容器调用的方式。具体取值包括: ASYNC、ERROR、FORWARD、INCLUDE、REQUEST。
initParams 指定一组过滤器初始化参数,等价于 标签。
java 复制代码
@WebFilter(filterName = "LoginFilter", value = "/*")
public class LoginFilter implements Filter {
}

6 FilterConfig

方法 功能描述
String getInitParameter(String name) 根据初始化参数名 name,返回对应的初始化参数值。
Enumeration getInitParameterNames() 返回 Servlet 所有的初始化参数名的枚举集合,如果该 Servlet 没有初始化参数,则返回一个空的集合。
ServletContext getServletContext() 返回一个代表当前 Web 应用的 ServletContext 对象。
String getFilterName() 返回 Filter 的名字

7 过滤器链

在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链

在doFilter方法中,开发人员如果调用了chain.doFilter方法,web服务器会检查FilterChain对象中是否还有其他的filter,如果有,则调用依次调用其余的filter,如果没有,则调用访问的目标资源。

注意:

访问filter的先后顺序,由filter在web.xml中的注册顺序决定

通过 @WebFilter 注解配置的 Filter 过滤器,没有提供排序的属性,但是,多个过滤器默认按照过滤器类名升序的顺序执行。若需要对 Filter 过滤器进行排序,建议使用 web.xml 进行配置

8 过滤器应用

1) 统一编码

java 复制代码
public class EncodingFilter implements Filter {

    /**
     * Default constructor. 
     */
    public EncodingFilter() {
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		// TODO Auto-generated method stub
	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		// place your code here
		// 针对post方式的中文乱码
		request.setCharacterEncoding("utf-8");
		// 响应
		response.setContentType("text/html;charset=utf-8");
		
		// pass the request along the filter chain
		chain.doFilter(request, response);
	}

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		// TODO Auto-generated method stub
	}

}

2) 访问权限控制

有些资源需要登录后访问

java 复制代码
public class LoginFilter implements Filter {

	private String[] passArr = null;
    /**
     * Default constructor. 
     */
    public LoginFilter() {
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		// TODO Auto-generated method stub
	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		// place your code here

		// 因为类型原因,某些方法不能正常调用,需要强制转换
		HttpServletRequest req = (HttpServletRequest)request;
		HttpServletResponse res = (HttpServletResponse)response;
		
		// 获取请求的资源的路径
		String uri = req.getRequestURI();
		// 如果是和登录相关的资源,直接放行
		
		// 是否放行的状态
		boolean flag = false;
		if(passArr != null){
			for(String info : passArr){
				if(uri.contains(info)){
					flag =  true;
					break;
				}
			}
		}
		
		if(flag){
			chain.doFilter(request, response);
		}else{
			HttpSession session = req.getSession();
			String name = (String)session.getAttribute("loginName");
			// 已经登陆过
			if(name != null){
				chain.doFilter(request, response);
			}else{
				// 跳转到登录页面
				res.sendRedirect(req.getContextPath() + "/login.jsp");
			}
			
		}
		
		// 获取session对象,判断是否有登录状态,如果有,继续访问,如果没有,跳转到登录页面
		
		
	}

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		// TODO Auto-generated method stub
		String initParameter = fConfig.getInitParameter("passInfo");
		if(initParameter != null){
			passArr = initParameter.split(",");
		}
		
	}

}

二 什么是监听器

监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。

在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为ServletContext, HttpSession 和ServletRequest 这三个域对象,主要用来监听对象的创建、销毁、属性的变化

监听器的相关概念:

事件:方法调用、属性改变、状态改变等。

事件源:被监听的对象( 例如:request、session、servletContext)。

监听器:用于监听事件源对象 ,事件源对象状态的变化都会触发监听器。

注册监听器:将监听器与事件源进行绑定。

1 监听器分类

Servlet 规范中定义了 8 个监听器接口,可以用于监听 ServletContext、HttpSession 和 ServletRequest 对象的生命周期和属性变化事件。开发 Servlet 监听器需要实现相应的监听器接口并重写接口中的方法。

(1)监听对象创建/销毁的监听器接口

ServlectContxtListener

ServletRequestListener

HttpSessionListener

(2)监听对象属性变化的接口

监听属性的增删改

ServletContextAttributeListener

ServletRequestAttributeListener

HttpSessionAttributeListener

(3)其他session相关监听器接口

HttpSessionBindingListener 监听对象绑定到session的事件

HttpSessionActivationListener 监听HttpSession中对象的活化和钝化过程

2 监听器使用

2.1 监听对象的创建
java 复制代码
// 加载web应用时,创建对象
public class ContextListener implements ServletContextListener {

    /**
     * Default constructor. 
     */
    public ContextListener() {
        // TODO Auto-generated constructor stub
    	System.out.println("constructor");
    }

	/**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    // 销毁ServletContext对象,调用该方法
    public void contextDestroyed(ServletContextEvent arg0)  { 
         // TODO Auto-generated method stub
    	System.out.println("servletcontext destroy");
    }

	/**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    // 创建ServletContext对象,调用该方法
    public void contextInitialized(ServletContextEvent arg0)  { 
         // TODO Auto-generated method stub
    	System.out.println("servletcontext init");
    }
	
}
2.2 注册监听器
xml 复制代码
<listener>
  <listener-class>com.qfedu.listener.ContextListener</listener-class>
</listener>
2.3 监听对象中属性的变化
java 复制代码
public class SessionAttrListener implements HttpSessionAttributeListener {

    /**
     * Default constructor. 
     */
    public SessionAttrListener() {
        // TODO Auto-generated constructor stub
    }

	/**
     * @see HttpSessionAttributeListener#attributeAdded(HttpSessionBindingEvent)
     */
    public void attributeAdded(HttpSessionBindingEvent event)  { 
         // TODO Auto-generated method stub
    	
    	// 监测到添加的数据的信息
    	// 获取添加的属性的key值
    	System.out.println(event.getName());
    	// 获取添加的属性的value值
    	System.out.println(event.getValue());
    	
    }

	/**
     * @see HttpSessionAttributeListener#attributeRemoved(HttpSessionBindingEvent)
     */
    public void attributeRemoved(HttpSessionBindingEvent event)  { 
         // TODO Auto-generated method stub
    	
    	System.out.println("delete:" +event.getName());
    	System.out.println("delete:" +event.getValue());
    }

	/**
     * @see HttpSessionAttributeListener#attributeReplaced(HttpSessionBindingEvent)
     */
    // 修改数据时
    public void attributeReplaced(HttpSessionBindingEvent event)  { 
         // TODO Auto-generated method stub
    	// 修改前的数据
    	System.out.println("update:" + event.getName());
    	System.out.println("update:" + event.getValue());
    	
    	HttpSession session = event.getSession();
    	System.out.println("after update:" + session.getAttribute(event.getName()));
    	
    }
	
}

3 注册监听器

3.1 XMl方式
xml 复制代码
<listener>
  <listener-class>com.rr.listener.MyServletContextListener</listener-class>
</listener>
3.2 @WebListener注解方式
java 复制代码
@WebListener
public class MyListener implements ServletContextListener {
}
3 应用

通过listener,实现获取所有登录用户信息的功能

java 复制代码
package com.qfedu.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.util.ArrayList;
import java.util.List;

@WebListener
public class MyListener implements ServletContextListener, HttpSessionAttributeListener {

    public MyListener() {
    }

    // 监听到ServletContext创建后,新建一个用户列表,将列表放入ServletContext对象
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        /* This method is called when the servlet context is initialized(when the Web application is deployed). */
        // 用来存储登录的用户名
        List<String> userList = new ArrayList<>();
        // 将列表存入ServletContext对象中
        sce.getServletContext().setAttribute("userList", userList);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        /* This method is called when the servlet Context is undeployed or Application Server shuts down. */
    }

    // 当用户登录,将用户信息添加到用户列表中
    @Override
    public void attributeAdded(HttpSessionBindingEvent sbe) {
        /* This method is called when an attribute is added to a session. */
        String name = sbe.getName();
        // 说明是登录时添加的数据
        if (name.equals("loginInfo")) {
            ServletContext servletContext = sbe.getSession().getServletContext();
            List<String> userList = (List<String>) servletContext.getAttribute("userList");
            userList.add(sbe.getValue().toString());
        }
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent sbe) {
        /* This method is called when an attribute is removed from a session. */
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent sbe) {
        /* This method is called when an attribute is replaced in a session. */
    }
}
相关推荐
哎呦没18 分钟前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
编程、小哥哥1 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
IT学长编程2 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
莹雨潇潇2 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
杨哥带你写代码2 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
郭二哈3 小时前
C++——模板进阶、继承
java·服务器·c++
A尘埃3 小时前
SpringBoot的数据访问
java·spring boot·后端
yang-23073 小时前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端
沉登c3 小时前
幂等性接口实现
java·rpc
代码之光_19803 小时前
SpringBoot校园资料分享平台:设计与实现
java·spring boot·后端