Filter 过滤器
Spring Boot的过滤器用于对数据进行过滤处理。通过Spring Boot的过滤器,程序开发人员不仅可以对用户通过URL地址发送的请求进行过滤处理(例如,过滤一些错误的请求或者请求中的敏感词等),而且可以对服务器返回的数据进行过滤处理(例如,压缩响应信息等)。
使用 FilterRegistrationBean类 实现过滤器
实现过滤器类
如果一个类实现了一个继承Filter 接口的类,那么这个类就可以做为自定义的过滤器。
Filter 接口一共有三个方法
1、init() 方法 初始化过滤器配置 有默认的init方法,可以不重写
2、doFilter() 方法 过滤器的具体行为,abstract 方法,需要自己实现
3、destroy() 方法 销毁过滤器 有默认的destroy方法,可以不重写
下面这段代码实现了一个过滤器类,此过滤器的作用是判断用户是否登录,若没有登录则用请求转发器,将请求转发至/login页面,浏览器的URL不会改变,只会改变当前页面的内容。
java 体验AI代码助手 代码解读复制代码public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
// 多态
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 从请求消息中获取用户信息
Object user = request.getSession().getAttribute("user");
if(user != null) {
// 如果用户不为空 则继续过滤器链的下一个过滤器。
filterChain.doFilter(request, servletResponse);
}
else{
// 如果用户为空则 使用请求转发器 将请求转发到`login`页面 给了两个参数,request 和 response 包含一个请求所有的信息
request.getRequestDispatcher("/login").forward(request, servletResponse);
}
}
}
配置过滤器类
实现了一个过滤器类后,还需要配置这个过滤器类
以下代码实现了配置过滤器, FilterConfig 是一个配置过滤器的类,类中的方法会注册过滤器,FilterConfig类的命名随意,这个类中的方法注册了一个 FilterRegistrationBean 对象,由Bean的相关概念可知,不管在那个地方,在Spring Boot 的生命周期的初始化阶段,只要一个FilterRegistrationBean 对象被注册了,那么这个过滤器就被配置好了。
观察代码, bean.setFilter 方法就是配置此过滤器中的具体过滤器,当前过滤器配置的过滤器就是上文中实现的过滤器。
一个类中可以实现许多过滤器,此即为 FilterConfig 类名的由来。
java 体验AI代码助手 代码解读复制代码@Configuration
public class FilterConfig {
//
@Bean
public FilterRegistrationBean getFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean<>();
bean.setFilter(new LoginFilter());
bean.addUrlPatterns("/main/*"); // 过滤 /main/* 下的所有子路径
bean.setName("loginfilter"); // 设置过滤器的名称
return bean;
}
}
使用 @WebFilter 实现过滤器
WebFilter 实现过滤器的原理与FilterRegistrationBean 实现原理相同,不过更简单,但是功能也更少,推荐使用第一种。
由上文可知,只要这个类实现了Filter接口并且将这个类在Spring Boot 生命周期的初始阶段注册即可实现过滤器。
@WebFilter 注解可以注册Bean,同时配置urlPatterns;
java 体验AI代码助手 代码解读复制代码/*
- 这是一个记录一个URL点击次数的过滤器,其中有一个context,这里面的count 记录了点击次数, 此点击次数与客户端无关
- 因此可以推断出,Spring Boot 的 context 是与具体的 URL 绑定的, 这个 URL 是在配置过滤器类时设置好的。
- 点击次数与Spring Boot 有关,因此,关闭Spring Boot context 中的数据会丢失, 需要记录在数据库中。
- */
@Component
@WebFilter(urlPatterns = "/user/click_count/")
public class CountFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 获取上下文
ServletContext context = filterConfig.getServletContext();
// 将count的值初始化为 0
// 这是会自己创建新的count 还是这个Filter 里面本来就有的
context.setAttribute("count", 0);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
ServletContext context = request.getServletContext();
Integer count = (Integer) context.getAttribute("count");
// 每一次请求都会经过过滤器, 每一次都会导致 count 加一
count = count + 1;
context.setAttribute("count", count);
filterChain.doFilter(servletRequest, servletResponse);
}
}
拦截器
拦截器可以在控制器类中的方法被执行前和被执行后对请求做一些处理。
拦截器可以形成链,如果链中的某一个节点断开,则整个链断开。
拦截器和过滤器的执行时间不同。
一个类如果实现了HandlerInterceptor接口,就能够实现自定义的拦截器
1、preHandle()方法
preHandle()方法会在控制器类中的方法被执行之前、对请求进行处理时被执行,preHandle()方法的语法如下:
2、postHandle()方法
postHandle()方法会在控制器类中的方法被执行之后、对请求进行处理时被执行,
3、afterCompletion()方法
afterCompletion()方法在整个请求结束之后被执行
创建一个拦截器
java 体验AI代码助手 代码解读复制代码
public class MyInterceptor implements HandlerInterceptor {
// 此函数是请求进入 controller 之前的处理程序 返回为真,请求正常进行,返回为假,则请求断开
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(handler instanceof HandlerMethod){
HandlerMethod method = (HandlerMethod)handler;
System.out.println("1、请求访问的方法是:" + method.getMethod().getName() + "()"); // 输出请求方法
Object value = request.getAttribute("value"); // 读取请求的某个属性,默认为null
System.out.println("执行方法前:value="+value);
return true;
}
return false;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
Object value = request.getAttribute("value");
System.out.println("2、执行方法后:value="+value);
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
request.removeAttribute("value");
System.out.println("3、整个请求都执行完毕,在此做一些资源释放工作");
}
}
注册拦截器
注册拦截器是通过 继承WebMvcConfigurer 接口并重写 addInterceptors 方法 实现的。
这里发现拦截器并没有像过滤器一样注册在Spring Boot 的Bean容器中, 而是与URL地址绑定,与URL请求处理函数一样。
java 体验AI代码助手 代码解读复制代码@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration regist = registry.addInterceptor(new MyInterceptor());
regist.addPathPatterns("/test/login"); // 拦截 /test/login
}
}
至此,拦截器创建并注册好了。
客户端请求通过拦截器流程。
进入 preHandler 程序
执行处理从此请求的 Controller 程序
进入 postHandler 程序
在客户端请求完成之后 执行 afterCompletion 程序
监听器
在开发Spring Boot项目的过程中,监听器用于监听并处理指定的事件。在一个Spring Boot项目中,可以包含一个或者多个监听器。如果一个Spring Boot项目包含多个监听器,那么这些监听器的类型既可以是相同的,也可以是不同的。
ServletRequestListener接口
ServletRequestListener接口可以监听请求的初始化与销毁
requestInitialized(ServletRequestEvent sre):请求初始化时触发。
requestDestroyed(ServletRequestEvent sre):请求被销毁时触发。
HttpSessionListener接口
HttpSessionListener接口可以监听session的创建与销毁
sessionCreated(HttpSessionEvent se):session已经被加载及初始化时触发。
sessionDestroyed(HttpSessionEvent se):session被销毁后触发。
ServletContextListener接口
ServletContextListener接口可以监听上下文的初始化与销毁.
contextInitialized(ServletContextEvent sce):上下文初始化时触发
contextDestroyed(ServletContextEvent sce):上下文被销毁时触发。
ServletRequestAttributeListener接口
ServletRequestAttributeListener接口可以监听请求属性发生的增、删、改事件.
attributeAdded(ServletRequestAttributeEvent srae):请求添加新属性时触发。
attributeRemoved(ServletRequestAttributeEvent srae):请求删除旧属性时触发。
attributeReplaced(ServletRequestAttributeEvent srae):请求修改旧属性时触发。
HttpSessionAttributeListener接口
HttpSessionAttributeListener接口可以监听session属性发生的增、删、改事件.
attributeAdded(HttpSessionBindingEvent se):session添加新属性时触发。
attributeRemoved(HttpSessionBindingEvent se):session删除旧属性时触发。
attributeReplaced(HttpSessionBindingEvent se):session修改旧属性时触发。
ServletContextAttributeListener接口
ServletContextAttributeListener接口可以监听上下文属性发生的增、删、改事件.
attributeAdded(ServletContextAttributeEvent scae):上下文添加新属性时触发。
attributeRemoved(ServletContextAttributeEvent scae):上下文删除旧属性时触发。
attributeReplaced(ServletContextAttributeEvent scae):上下文修改旧属性时触发。
HttpSessionBindingListener接口
HttpSessionBindingListener接口可以为开发者自定义的类添加session绑定监听,当session保存或移除此类的对象时触发此监听。
valueBound(HttpSessionBindingEvent event):当session通过setAttribute()方法保存对象时,触发该对象的此方法。
valueUnbound(HttpSessionBindingEvent event):当session通过removeAttribute()方法移除对象时,触发该对象的此方法。
HttpSessionActivationListener接口
HttpSessionActivationListener接口可以为开发者自定义的类添加序列化监听,当保存在session中的自定义类对象被序列化或反序列化时触发此监听。此监听通常会配合HttpSessionBindingListener监听一起使用。
sessionWillPassivate(HttpSessionEvent se):自定义对象被序列化之前触发。
sessionDidActivate(HttpSessionEvent se):自定义对象被反序列化之后触发。
对象变成字节序列的过程被称为序列化,例如将内存中的对象保存到硬盘文件中,这个过程也被称为passivate、钝化、持久化;字节序列变成对象的过程被称为反序列化,例如从文件中读取数据并封装成一个对象并保存在内存中,这个过程也被称为activate、活化。
自定义监听器,监听每一个前端请求的URL、IP和session id
session id是由服务器随机生成的,每个session的session id都不一样。但只要用户不关闭浏览器,用户的session id就不会改变。
java 体验AI代码助手 代码解读复制代码@Component
public class MyRequestListener implements ServletRequestListener {
public void requestInitialized(ServletRequestEvent sre) {
HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
String ip = request.getRemoteAddr();
String url = request.getRequestURI();
String sessionId = request.getSession().getId();
System.out.println("IP:"+ip);
System.out.println("url:"+url);
System.out.println("sessionId:"+sessionId);
}
public void requestDestroyed(ServletRequestEvent sre) {
HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
String sessionId = request.getSession().getId();
System.out.println("sessionId:"+sessionId + "的请求已销毁");
}
}