参考博文
拦截器(interceptor):在一个请求进行中的时候,你想干预它的进展,甚至控制是否终止。这是拦截器做的事。
过滤器(Filter):当有一堆东西,只希望选择符合的东西。定义这些要求的工具,就是过滤器。
监听器(Listener):一个事件发生后,只希望获取这些事个事件发生的细节,而不去干预这个事件的执行过程,这就用到监听器
拦截器(interceptor):依赖于web框架,基于Java的反射机制,属于AOP的一种应用。一个拦截器实例在一个controller生命周期内可以多次调用。只能拦截Controller的请求。
是在面向切面编程的就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。
过滤器(Filter):依赖于Servlet容器,基于函数回掉,可以对几乎所有请求过滤,一个过滤器实例只能在容器初使化调用一次。
是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符.
监听器(Listener):web监听器是Servlet中的特殊的类,用于监听web的特定事件,随web应用启动而启动,只初始化一次。
Java的监听器,也是系统级别的监听。监听器随web应用的启动而启动。Java的监听器在c/s模式里面经常用到,它
会对特定的事件产生产生一个处理。监听在很多模式下用到,比如说观察者模式,就是一个使用监听器来实现的,在比如统计网站的在线人数。
过滤器 | 监听器 | 拦截器 | |
---|---|---|---|
关注的点 | web请求 | 系统级别参数、对象 | 部分web请求 |
如何实现 | 函数回调 | 事件 | java反射机制 |
应用场景 | 设置字符编码,url级别权限访问,过滤敏感词汇,压缩响应信息 | 统计网站在线人数,清除过期的 | |
是否依赖servlet容器 | 依赖 | 不依赖 | |
servlet提供的支持 | filter | ServletContextListener,HttpSessionListener | |
spring提供支持 | HandlerInterceptorAdapter,HandlerInterceptor | ||
级别 | 系统 | 系统 | 非系统 |
监听器,过滤器,拦截器
SpringBoot通过实现HandlerInterceptor接口实现拦截器,通过实现WebMvcConfigurer接口实现一个配置类,在配置类中注入拦截器,最后再通过@Configuration注解注入配置。
HandlerInterceptor
重写三个方法
preHandle 在请求处理之前进行调用(Controller方法调用之前)
postHandle 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
afterCompletion 整个请求结束之后被调用,也就是在DispatchServlet渲染了对应的视图之后执行(主要用于进行资源清理工作)
package com.geekmice.springbootselfexercise.interceptor;
import com.geekmice.springbootselfexercise.domain.UserDomain;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Objects;
/**
* @BelongsProject: spring-boot-self-exercise
* @BelongsPackage: com.geekmice.springbootselfexercise.interceptor
* @Author: pingmingbo
* @CreateTime: 2023-09-12 13:35
* @Description: 登录拦截器
* @Version: 1.0
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("登录拦截器前置处理");
HttpSession session = request.getSession();
UserDomain user = (UserDomain) session.getAttribute("user");
if (Objects.nonNull(user)) {
log.info("当前用户已登录,继续后面流程");
return true;
}else{
log.info("未登录,请登录");
response.sendRedirect(request.getContextPath() + "/user/login");
throw new IllegalArgumentException("未登录,请登录");
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("request : [{}]", request);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("request : [{}]", request);
}
}
package com.geekmice.springbootselfexercise.config;
import com.geekmice.springbootselfexercise.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @BelongsProject: spring-boot-self-exercise
* @BelongsPackage: com.geekmice.springbootselfexercise.config
* @Author: pingmingbo
* @CreateTime: 2023-09-12 13:47
* @Description: 配置拦截器
* @Version: 1.0
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getLoginInterceptor())
.addPathPatterns("/**");
}
@Bean
public LoginInterceptor getLoginInterceptor(){
return new LoginInterceptor();
}
}
使用过滤器很简单,只需要实现Filter类,然后重写它的3个方法即可。
init方法:程序启动调用Filter的init()方法(永远只调用一次);在容器中创建当前过滤器的时候自动调用这个方法。
destory方法:程序停止调用Filter的destroy()方法(永远只调用一次);在容器中销毁当前过滤器的时候自动调用这个方法。
doFilter方法:doFilter()方法每次的访问请求如果符合拦截条件都会调用(程序第一次运行,会在servlet调用init()方法以后调用;不管第几次,都在调用doGet(),doPost()方法之前)。这个方法有3个参数,分别是ServletRequest、ServletResponse和FilterChain可以从参数中获取HttpServletReguest和HttpServletResponse对象进行相应的处理操作。
package com.geekmice.springbootselfexercise;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
@MapperScan("com.geekmice.springbootselfexercise.dao")
public class SpringBootSelfExerciseApplication {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(SpringBootSelfExerciseApplication.class);
springApplication.run(args);
}
}
package com.geekmice.springbootselfexercise.filter;
import com.geekmice.springbootselfexercise.param.MyRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @BelongsProject: spring-boot-self-exercise
* @BelongsPackage: com.geekmice.springbootselfexercise.filter
* @Author: pingmingbo
* @CreateTime: 2023-09-05 09:27
* @Description: 修改分页参数默认值
* @Version: 1.0
*/
@Configuration
@Slf4j
@WebFilter(filterName = "authFilter", urlPatterns = {"/tzArea"})
public class InitValueFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("过滤器开始初始化 : [{}]" , filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String pageSize = httpServletRequest.getParameter("pageSize");
String pageNum = httpServletRequest.getParameter("pageNum");
if(StringUtils.isAnyBlank(pageSize,pageNum)){
pageSize="11";
pageNum="1";
Map<String,Object> map = new HashMap(16);
map.put("pageSize", pageSize);
map.put("pageNum", pageNum);
MyRequestWrapper myRequestWrapper = new MyRequestWrapper(httpServletRequest, map);
chain.doFilter(myRequestWrapper, response);
}
}
@Override
public void destroy() {
log.info("过滤器销毁");
}
}
web监听器是一种 Servlet 中特殊的类,它们能帮助开发者监听 web 中特定的事件,比如 ServletContext, HttpSession, ServletRequest的创建和销毁;变量的创建、销毁和修改等。可以在某些动作前后增加处理,实现监控。
package com.geekmice.springbootselfexercise.event;
import com.geekmice.springbootselfexercise.domain.UserDomain;
import org.springframework.context.ApplicationEvent;
/**
* @BelongsProject: spring-boot-self-exercise
* @BelongsPackage: com.geekmice.springbootselfexercise.event
* @Author: pingmingbo
* @CreateTime: 2023-09-12 15:17
* @Description: 自定义事件
* @Version: 1.0
*/
public class MyEvent extends ApplicationEvent {
private UserDomain userDomain;
public MyEvent(Object source, UserDomain userDomain) {
super(source);
this.userDomain = userDomain;
}
public UserDomain getUserDomain() {
return userDomain;
}
public void setUserDomain(UserDomain userDomain) {
this.userDomain = userDomain;
}
}
package com.geekmice.springbootselfexercise.listener;
import com.geekmice.springbootselfexercise.domain.UserDomain;
import com.geekmice.springbootselfexercise.event.MyEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* @BelongsProject: spring-boot-self-exercise
* @BelongsPackage: com.geekmice.springbootselfexercise.listener
* @Author: pingmingbo
* @CreateTime: 2023-09-12 15:20
* @Description: 自定义监听器,监听事件
* @Version: 1.0
*/
@Slf4j
@Component
public class MyListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
// 获取事件中信息
UserDomain userDomain = event.getUserDomain();
// 用于逻辑处理
log.info("userDomain : [{}]", userDomain);
}
}
package com.geekmice.springbootselfexercise.service.impl;
import com.geekmice.springbootselfexercise.domain.UserDomain;
import com.geekmice.springbootselfexercise.event.MyEvent;
import com.geekmice.springbootselfexercise.service.EventService;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @BelongsProject: spring-boot-self-exercise
* @BelongsPackage: com.geekmice.springbootselfexercise.service.impl
* @Author: pingmingbo
* @CreateTime: 2023-09-12 15:25
* @Description: 测试发布事件
* @Version: 1.0
*/
@Service
public class EventServiceImpl implements EventService {
@Resource
private ApplicationContext applicationContext;
@Override
public void publishEvent() {
UserDomain user = UserDomain.builder().userName("pmb").build();
// 发布事件
MyEvent myEvent = new MyEvent(this, user);
applicationContext.publishEvent(myEvent);
return;
}
}