java web中的拦截器、过滤器和监听器

手记 专栏收录该内容
17 篇文章 0 订阅

目录

 

介绍一下

过滤器实现

拦截器实现

Servlet监听器实现


介绍一下

1、过滤器和拦截器(只针对Servlet的Filter接口和SpringMVC的HandlerInterceptor接口,不针对其它实现方式,手撸服务器的大神再见)

过滤器和拦截器都是将客户端的请求进行拦截处理,然后将请求转交给下一资源。其处理方式如下图所示。

拦截器和过滤都能实现相同的功能,那么具体差别在哪里呢? 

(现在网上很多都是相互摘抄,错误一大堆,感觉没有营养,所以谈谈自己的使用看法,不谈实现)

a、过滤器依赖web容器实现,拦截器依赖mvc框架实现,也就导致其作用顺序是不同的,另外就是过滤器的作用域应该是包裹拦截器的(即过滤器在拦截器之前执行(亲自验证))。另外Filter接口提供了init()方法和destroy()方法,相对来说想在web容器初始化和销毁的时候实现一些业务逻辑,过滤器相对简单一些。

它们之间体现的一个包裹关系如下图所示(图是复制的,谢谢原图作者)。

https://images2017.cnblogs.com/blog/330611/201710/330611-20171023144517066-24770749.png

b、在现在Spring大行其道的情况下,过滤器和拦截器都可以交给IoC管理,从而使用依赖注入(很多文章说不行,是错误的,但是在过滤器的init()和destroy()方法中避免使用依赖注入,因为IoC的生命周期和web容器的生命周期是不一样的,总之,避免在IoC没有初始化之前去使用IoC)。在SpringMVC中封装的拦截器灵活性更强,使用更加容易,优先考虑拦截器。

注意

Filter接口中使用的是javax.servlet.ServletRequest和javax.servlet.ServletResponse,HandlerInterceptor接口中使用的是javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse。

HttpServletRequest继承自ServletRequest,HttpServletResponse继承自ServletResponse。当然HttpServletRequest和HttpServletResponse功能更加强大。

在Filter中是可以将ServletRequest和ServletResponse强转成HttpServletRequest和HttpServletResponse的。

都知道,向上转型是绝对安全的,而向下转型不一定安全。这里能这么做,是因为它们都是接口,要获取一个接口的实例,只能实例化它们的实现类。在tomcat中,只有一个实现类,分别是由org.apache.catalina.connector.RequestFacade和org.apache.catalina.connector.ResponseFacade去实现。

2、监听器(这里主指Servlet监听器)

在Servlet中已经定义好了一些事件,监听器主要作用于监听Servlet的有效事件。作用是监听由于Web应用中状态改变而引起的Servlet容器产生的相应事件,然后接受并处理这些事件。

过滤器实现

为了方便,在SpringBoot项目中实现。

1、实现Filter接口

//@Order(value=1) 用于多个Filter指定过滤器顺序
@WebFilter(filterName="myFilter1", urlPatterns= {"/*"})//标记过滤器,拦截所有请求
public class MyFilter1 implements Filter {
	
	/**
	 * 	过滤器初始化方法,该方法在过滤器初始化时调用(即容器加载时)
	 * 	@param filterConfig  FilterConfig也是接口对象 由Servlet容器实现,主要
	 * 			用于获取过滤器中的配置信息,其常用方法声明如下:
	 * 			String getFilterName 获取过滤器名字
	 * 			ServletContext getServletContext() 获取Servlet上下文
	 * 			String getInitParameter(String name) 获取过滤器的初始化参数值
	 * 			Enumeration getInitParameterNames() 获取过滤器的所有初始化参数
	 * */
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		//TODO 没有业务逻辑则不写相应的实现
	}

	/**
	 * 	对请求进行过滤处理(也就是主要实现过滤功能的方法)
	 * 	@param chain FilterChain接口也是由Servlet容器实现。
	 * 			其只有一个方法,如下:
	 * 			void doFilter(ServletRequest request, ServletResponse response)
	 * 			该方法用于将过滤后的请求传递给下一个过滤器。如果是最后一个过滤器,则将请求转交给目标资源。
     * @param request ServletRequest可强转为HttpServletRequest ,其都由Servlet实现
	 * @param response ServletResponse可强转为HttpServletResponse,因为其都由Servlet实现
	 * */
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		//TODO 具体的过滤逻辑实现--比如登录权限验证、字符编码过滤等
		
		/*
		 * 	将请求转交给下一过滤器或其它目标资源
		 * 	注:如果没有调用此方法,则请求会在此处终止(也不会响应客户端)。
		 * 	可以直接使用response直接响应客户端(比如在权限验证不通过的时候)。
		 * */
		chain.doFilter(request, response);
	}

	/**
	 * 	过滤器销毁方法,以便释放资源(即关闭容器时调用)
	 * */
	@Override
	public void destroy() {
		//TODO 没有业务逻辑则不写相应的实现
	}
}

2、在启动类上加上Servlet注解扫描

@SpringBootApplication
@ServletComponentScan//Servlet注解扫描
public class App {

	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

拦截器实现

为了方便,在SpringBoot项目中实现。

1、实现HandlerInterceptor接口

/**
 * 	可将其标记为Spring的组件
 * 	或在注册拦截器的时候利用构造方法传递其它Spring的组件(如其它Service层或Dao层)
 * */
//@Order(value=1)//用于多个拦截器指定执行顺序
public class MyHandlerInterceptor1 implements HandlerInterceptor {

	/**
	 *  <p>该方法就是进行拦截处理的,将在Controller方法处理之前调用
	 *  <p>该方法返回True时拦截器才会继续往下执行,返回false则会结束整个请求
	 *  <p>可以直接使用response或全局异常拦截直接响应客户端
	 * */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// TODO 具体的拦截逻辑 --比如登录权限校验、非法敏感字符校验等
		//根据不同的逻辑返回boolean类型即可  也可直接使用response或全局异常拦截直接响应客户端
		return HandlerInterceptor.super.preHandle(request, response, handler);
	}

	/**
	 *  <p>该方法将在处理请求完成后(即Controller方法调用之后)视图渲染之前的处理操作
	 *  <p>该方法只能在当前类的preHandle()方法返回true时才会执行
	 * */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO 没有相关业务逻辑 则不用重写此方法
		HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
	}

	/**
	 * <p>该方法将在整个请求和相应动作完成之后执行(即视图渲染之后)
	 * <p>该方法只能在当前类的preHandle()方法返回true时才会执行
	 * */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO 没有相关业务逻辑 则不用重写此方法
		HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
	}
}

2、注册拦截器,实现WebMvcConfigurer接口。

@Configuration
public class InterceptConfig implements WebMvcConfigurer {

	@Override
    public void addInterceptors(InterceptorRegistry registry) {
		//注册拦截器 可利用构造方法传递一些参数
		registry.addInterceptor(new MyHandlerInterceptor1())
				//拦截所有请求
                .addPathPatterns("/**");
                //还可排除一些静态资源请求拦截
                //.excludePathPatterns(null);
}

Servlet监听器实现

1、实现Servlet中定义的监听器接口,如ServletContextListener(Servlet还定义了其它监听器)

/**
 * <p>Servlet监听器
 * <p>@WebListener注解只有一个属性 用于描述这个监听器 可以默认不要
 * */
@WebListener(value = "监听Servlet上下文的创建和删除")
public class MyListener implements ServletContextListener {

	/**
	 * <p>通知正在收听的对象,应用程序已经被加载及初始化
	 * */
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		//TODO 没有相应的业务逻辑 则不写实现
	}

	/**
	 * <p>通知正在收听的对象,应用程序已经被销毁(即关闭)
	 * */
	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		//TODO 没有相应的业务逻辑 则不写实现
	}
}

2、在启动类上加上Servlet注解扫描

@SpringBootApplication
@ServletComponentScan//Servlet注解扫描
public class App {

	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

3、Servlet其它监听器

Servlet监听器的功能就是监听由于Web应用中状态改变而引起的Servlet容器产生的相应事件,

比如利用HttpSessionBindingListener统计在线人数

除了上述的ServletContextListener,还有以下监听器(共8个)。如下表所示:

Servlet上下文监听ServletContextListener 主要监听Servlet上下文的创建和删除
ServletContextAttributeListener主要监听Servlet上下文属性的增加、删除和修改
HTTP会话监听HttpSessionListener主要监听HTTP会话创建和销毁
HttpSessionActivationListener实现监听HTTP会话active和passivate
HttpSessionAttributeListener实现监听HTTP会话中属性的设置请求
HttpSessionBindingListener实现监听HTTP会话中对象的绑定信息
Servlet请求监听ServletRequestListener实现监听客户端的请求
ServletRequestAttributeListener实现讲台客户端请求属性变化

ServletContextAttributeListener

public class MyListener2 implements ServletContextAttributeListener {

	/**
	 * <p>当有对象加入Application范围时,通知正在收听的对象
	 * */
	@Override
	public void attributeAdded(ServletContextAttributeEvent scae) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>当有对象从Application范围中移除,通知正在收听的对象
	 * */
	@Override
	public void attributeRemoved(ServletContextAttributeEvent scae) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>挡在Application的范围有对象取代另一个对象时,通知正在收听的对象
	 * */
	@Override
	public void attributeReplaced(ServletContextAttributeEvent scae) {
		// TODO Auto-generated method stub
	}
}

HttpSessionListener

public class MyListener2 implements HttpSessionListener {

	/**
	 * <p>通知正在收听的对象,session已经被加载及初始化
	 * */
	@Override
	public void sessionCreated(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>通知正在收听的对象,session已经被载出销毁
	 * @param se HttpSessionEvent的主要方法是getSession(),可以使用
	 * 	该方法回传一个session对象
	 * */
	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}
}

HttpSessionActivationListener

public class MyListener2 implements HttpSessionActivationListener {

	/**
	 * <p>通知正在收听的对象,它的session已经被变为无效状态
	 * */
	@Override
	public void sessionWillPassivate(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>通知正在收听的对象,它的session已经变为有效状态
	 * */
	@Override
	public void sessionDidActivate(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}
}

HttpSessionAttributeListener

public class MyListener2 implements HttpSessionAttributeListener {

	/**
	 * <p>当有对象加入session范围时,通知正在收听的对象
	 * */
	@Override
	public void attributeAdded(HttpSessionBindingEvent se) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>当有对象从session范围移除时,通知正在收听的对象
	 * @param se HttpSessionBindingEvent类主要有3个方法
	 * getName()、getSession()、getValues()
	 * */
	@Override
	public void attributeRemoved(HttpSessionBindingEvent se) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>当在session的范围有对象取代另一个对象时,通知正在收听的对象
	 * */
	@Override
	public void attributeReplaced(HttpSessionBindingEvent se) {
		// TODO Auto-generated method stub
	}
}

HttpSessionBindingListener

public class MyListener2 implements HttpSessionBindingListener {

	/**
	 * <p>当有对象加入session范围时会被自动调用
	 * */
	@Override
	public void valueBound(HttpSessionBindingEvent event) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>当有对象从session的范围内移除时会被自动调用
	 * */
	@Override
	public void valueUnbound(HttpSessionBindingEvent event) {
		// TODO Auto-generated method stub
	}
}

ServletRequestListener

public class MyListener2 implements ServletRequestListener {

	/**
	 * <p>通知正在收听的对象,ServletRequest已经被加载及初始化
	 * */
	@Override
	public void requestInitialized(ServletRequestEvent sre) {
		// TODO Auto-generated method stub
	}
	
	/**
	 * <p>通知正在收听的对象,ServletRequest已经被载出销毁
	 * */
	@Override
	public void requestDestroyed(ServletRequestEvent sre) {
		// TODO Auto-generated method stub
	}
}

ServletRequestAttributeListener

public class MyListener2 implements ServletRequestAttributeListener {

	/**
	 * <p>当有对象加入request范围时,通知正在收听的对象
	 * */
	@Override
	public void attributeAdded(ServletRequestAttributeEvent srae) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>当有对象从request范围移除时,通知正在收听的对象
	 * */
	@Override
	public void attributeRemoved(ServletRequestAttributeEvent srae) {
		// TODO Auto-generated method stub
	}

	/**
	 * <p>当在request范围内有对象取代另一个对象时,通知正在收听的对象
	 * */
	@Override
	public void attributeReplaced(ServletRequestAttributeEvent srae) {
		// TODO Auto-generated method stub
	}
}

 

 

 

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:创作都市 设计师:CSDN官方博客 返回首页

打赏作者

Zepal

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值