SpringBoot实现拦截器、过滤器、监听器过程解析
这篇文章主要介绍了SpringBoot实现拦截器、过滤器、监听器过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
过滤器
过滤器简介
过滤器的英文名称为Filter,是Servlet技术中最实用的技术。如同它的名字一样,过滤器是处于客户端和服务器资源文件之间的一道过滤网,帮助我们过滤掉一些不符合要求的请求,通常用作Session校验,判断用户权限,如果不符合设定条件,则会被拦截到特殊的地址或者基于特殊的响应。
过滤器的使用
首先需要实现Filter接口然后重写它的三个方法
- init方法:在容器中创建当前过滤器的时候自动调用
- destory方法:在容器中销毁当前过滤器的时候自动调用
- doFilter方法:过滤的具体操作
我们先引入Maven依赖,其中lombok是用来避免每个文件创建Logger来打印日志
org.projectlombok lombok org.springframework.boot spring-boot-starter-web
我们首先实现接口,重写三个方法,对包含我们要求的四个请求予以放行,将其它请求拦截重定向至/online,只要在将MyFilter实例化后即可,我们在后面整合代码中一起给出。
importlombok.extern.log4j.Log4j2;
importorg.springframework.stereotype.Component;
importjavax.servlet.*;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjavax.servlet.http.HttpServletResponseWrapper;
importjava.io.IOException;
@Log4j2
publicclassMyFilterimplementsFilter{
@Override
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
log.info("初始化过滤器");
}
@Override
publicvoiddoFilter(ServletRequestservletRequest,ServletResponseresponse,FilterChainfilterChain)throwsIOException,ServletException{
HttpServletRequestrequest=(HttpServletRequest)servletRequest;
HttpServletResponseWrapperwrapper=newHttpServletResponseWrapper((HttpServletResponse)response);
StringrequestUri=request.getRequestURI();
log.info("请求地址是:"+requestUri);
if(requestUri.contains("/addSession")
||requestUri.contains("/removeSession")
||requestUri.contains("/online")
||requestUri.contains("/favicon.ico")){
filterChain.doFilter(servletRequest,response);
}else{
wrapper.sendRedirect("/online");
}
}
@Override
publicvoiddestroy(){
//在服务关闭时销毁
log.info("销毁过滤器");
}
}
拦截器
拦截器介绍
Java中的拦截器是动态拦截action调用的对象,然后提供了可以在action执行前后增加一些操作,也可以在action执行前停止操作,功能与过滤器类似,但是标准和实现方式不同。
- 登录认证:在一些应用中,可能会通过拦截器来验证用户的登录状态,如果没有登录或者登录失败,就会给用户一个友好的提示或者返回登录页面,当然大型项目中都不采用这种方式,都是调单点登录系统接口来验证用户。
- 记录系统日志:我们在常见应用中,通常要记录用户的请求信息,比如请求ip,方法执行时间等,通过这些记录可以监控系统的状况,以便于对系统进行信息监控、信息统计、计算PV、性能调优等。
- 通用处理:在应用程序中可能存在所有方法都要返回的信息,这是可以利用拦截器来实现,省去每个方法冗余重复的代码实现。
使用拦截器
我们需要实现HandlerInterceptor类,并且重写三个方法
- preHandle:在Controoler处理请求之前被调用,返回值是boolean类型,如果是true就进行下一步操作;若返回false,则证明不符合拦截条件,在失败的时候不会包含任何响应,此时需要调用对应的response返回对应响应。
- postHandler:在Controoler处理请求执行完成后、生成视图前执行,可以通过ModelAndView对视图进行处理,当然ModelAndView也可以设置为null。
- afterCompletion:在DispatcherServlet完全处理请求后被调用,通常用于记录消耗时间,也可以对一些资源进行处理。
importlombok.extern.log4j.Log4j2;
importorg.springframework.stereotype.Component;
importorg.springframework.web.servlet.HandlerInterceptor;
importorg.springframework.web.servlet.ModelAndView;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjavax.servlet.http.HttpSession;
@Log4j2
@Component
publicclassMyInterceptorimplementsHandlerInterceptor{
@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{
log.info("【MyInterceptor】调用了:{}",request.getRequestURI());
request.setAttribute("requestTime",System.currentTimeMillis());
returntrue;
}
@Override
publicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,
Objecthandler,ModelAndViewmodelAndView)throwsException{
if(!request.getRequestURI().contains("/online")){
HttpSessionsession=request.getSession();
StringsessionName=(String)session.getAttribute("name");
if("haixiang".equals(sessionName)){
log.info("【MyInterceptor】当前浏览器存在session:{}",sessionName);
}
}
}
@Override
publicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,
Objecthandler,Exceptionex)throwsException{
longduration=(System.currentTimeMillis()-(Long)request.getAttribute("requestTime"));
log.info("【MyInterceptor】[{}]调用耗时:{}ms",request.getRequestURI(),duration);
}
}
监听器
监听器简介
监听器通常用于监听Web应用程序中对象的创建、销毁等动作的发送,同时对监听的情况作出相应的处理,最常用于统计网站的在线人数、访问量等。
监听器大概分为以下几种:
- ServletContextListener:用来监听ServletContext属性的操作,比如新增、修改、删除。
- HttpSessionListener:用来监听Web应用种的Session对象,通常用于统计在线情况。
- ServletRequestListener:用来监听Request对象的属性操作。
监听器的使用
我们通过HttpSessionListener来统计当前在线人数、ip等信息,为了避免并发问题我们使用原子int来计数。
ServletContext,是一个全局的储存信息的空间,它的生命周期与Servlet容器也就是服务器保持一致,服务器关闭才销毁。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。因此我们这里用ServletContext来存储在线人数sessionCount最为合适。
我们下面来统计当前在线人数
importlombok.extern.log4j.Log4j2;
importjavax.servlet.http.HttpSessionEvent;
importjavax.servlet.http.HttpSessionListener;
importjava.util.concurrent.atomic.AtomicInteger;
@Log4j2
publicclassMyHttpSessionListenerimplementsHttpSessionListener{
publicstaticAtomicIntegeruserCount=newAtomicInteger(0);
@Override
publicsynchronizedvoidsessionCreated(HttpSessionEventse){
userCount.getAndIncrement();
se.getSession().getServletContext().setAttribute("sessionCount",userCount.get());
log.info("【在线人数】人数增加为:{}",userCount.get());
//此处可以在ServletContext域对象中为访问量计数,然后传入过滤器的销毁方法
//在销毁方法中调用数据库入库,因为过滤器生命周期与容器一致
}
@Override
publicsynchronizedvoidsessionDestroyed(HttpSessionEventse){
userCount.getAndDecrement();
se.getSession().getServletContext().setAttribute("sessionCount",userCount.get());
log.info("【在线人数】人数减少为:{}",userCount.get());
}
}
过滤器、拦截器、监听器注册
实例化三器
importcom.anqi.tool.sanqi.filter.MyFilter;
importcom.anqi.tool.sanqi.interceptor.MyInterceptor;
importcom.anqi.tool.sanqi.listener.MyHttpRequestListener;
importcom.anqi.tool.sanqi.listener.MyHttpSessionListener;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.boot.web.servlet.FilterRegistrationBean;
importorg.springframework.boot.web.servlet.ServletListenerRegistrationBean;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;
importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
publicclassWebConfigimplementsWebMvcConfigurer{
@Autowired
MyInterceptormyInterceptor;
@Override
publicvoidaddInterceptors(InterceptorRegistryregistry){
registry.addInterceptor(myInterceptor);
}
/**
*注册过滤器
*@return
*/
@Bean
publicFilterRegistrationBeanfilterRegistrationBean(){
FilterRegistrationBeanfilterRegistration=newFilterRegistrationBean();
filterRegistration.setFilter(newMyFilter());
filterRegistration.addUrlPatterns("/*");
returnfilterRegistration;
}
/**
*注册监听器
*@return
*/
@Bean
publicServletListenerRegistrationBeanregistrationBean(){
ServletListenerRegistrationBeanregistrationBean=newServletListenerRegistrationBean();
registrationBean.setListener(newMyHttpRequestListener());
registrationBean.setListener(newMyHttpSessionListener());
returnregistrationBean;
}
}
测试
importcom.anqi.tool.sanqi.listener.MyHttpSessionListener;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RestController;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpSession;
@RestController
publicclassTestController{
@GetMapping("addSession")
publicStringaddSession(HttpServletRequestrequest){
HttpSessionsession=request.getSession();
session.setAttribute("name","haixiang");
return"当前在线人数"+session.getServletContext().getAttribute("sessionCount")+"人";
}
@GetMapping("removeSession")
publicStringremoveSession(HttpServletRequestrequest){
HttpSessionsession=request.getSession();
session.invalidate();
return"当前在线人数"+session.getServletContext().getAttribute("sessionCount")+"人";
}
@GetMapping("online")
publicStringonline(){
return"当前在线人数"+MyHttpSessionListener.userCount.get()+"人";
}
}
以下是监听请求的监听器
importjavax.servlet.ServletRequestEvent;
importjavax.servlet.ServletRequestListener;
importjavax.servlet.http.HttpServletRequest;
publicclassMyHttpRequestListenerimplementsServletRequestListener{
@Override
publicvoidrequestDestroyed(ServletRequestEventsre){
System.out.println("request监听器被销毁");
}
@Override
publicvoidrequestInitialized(ServletRequestEventsre){
HttpServletRequestreq=(HttpServletRequest)sre.getServletRequest();
StringrequestURI=req.getRequestURI();
System.out.println(requestURI+"--"+"被调用");
}
}
拦截器与过滤器的区别
1.参考标准
- 过滤器是JavaEE的标准,依赖于Servlet容器,生命周期也与容器一致,利用这一特性可以在销毁时释放资源或者数据入库。
- 拦截器是SpringMVC中的内容,依赖于web框架,通常用于验证用户权限或者记录日志,但是这些功能也可以利用AOP来代替。
2.实现方式
- 过滤器是基于回调函数实现,无法注入ioc容器中的bean。
- 拦截器是基于反射来实现,因此拦截器中可以注入ioc容器中的bean,例如注入Redis的业务层来验证用户是否已经登录。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。