上篇文章我们学习了 Session 认证和 Token 认证,这篇我们来学习一下过滤器和拦截器,过滤器和拦截器在日常项目中经常会用到。
一、过滤器
1.1、理论概念
过滤器 Filter 是 JavaWeb 三大组件(Servlet、Filter、Listener)之一,过滤器主要是拦截资源的请求,进而实现一些特殊的处理。
作用:设置字符集、控制权限、登陆检查、敏感字符处理等。
Filter 过滤器随着 Web 应用启动而启动,只初始化一次
init(FilterConfig):
初始化接口,在用户自定义的 Filter 初始化的时候被调用。doFilter(ServletRequest,ServletResponse,FilterChain):
每个用户的请求进来时都会调用此方法,通过调用 FilterChain.doFilter 可以将请求继续传递下去。destroy:
当 Filter 对象被销毁时,调用此方法。
实现过滤器 Filter 步骤:
- 定义类,实现 Filter 接口,重写其方法。
- 配置过滤器
1.2、SpringBoot集成过滤器
①、使用 @Component
配置过滤器
新建一个 SpringBoot 项目,在 Filter 包新建 TestFilter 实现类,并在实现类中实现 doFilter方法,并且实现类使用 @Component 修饰。
package com.duan.filter;
import javax.servlet.*;
import java.io.IOException;/*** @author db* @version 1.0* @description TestFilter* @since 2023/12/20*/
@Component
public class TestFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("通过@Component方式配置过滤器");chain.doFilter(request,response);}
}
启动项目,通过 postman 访问 login 接口,查看结果。
②、使用 @Configuration
配置过滤器
首先在 Filter 包新建 TestFilter2 实现类,并在实现类中实现 doFilter 方法,然后需要一个 @Configuration 配置类,在配置类使用 @Bean 手动注入 FilterRegistrationBean 类。
用 FilterRegistrationBean 类设置自定义的 Filter 实现类和一些设置项;
package com.duan.filter;import javax.servlet.*;
import java.io.IOException;/*** @author db* @version 1.0* @description TestFilter2* @since 2023/12/20*/
public class TestFilter2 implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("使用@Configration配置过滤器");chain.doFilter(request,response);}
}
过滤器配置类代码如下
package com.duan.config;import com.duan.filter.TestFilter2;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.List;/*** @author db* @version 1.0* @description FilterConfig* @since 2023/12/20*/
@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<TestFilter2> testFilter2(){FilterRegistrationBean<TestFilter2> filterFilterRegistrationBean = new FilterRegistrationBean<>();filterFilterRegistrationBean.setEnabled(true); // 是否启动注入过滤器filterFilterRegistrationBean.setFilter(new TestFilter2()); // 设置过滤器filterFilterRegistrationBean.setOrder(1); // 设置过滤器顺序 数字越小越靠前filterFilterRegistrationBean.setName("TestFilter2"); // 设置过滤器名字List<String> urlPatterns = new ArrayList<>();urlPatterns.add("/*");filterFilterRegistrationBean.setUrlPatterns(urlPatterns); // 设置要过滤的路径return filterFilterRegistrationBean;}
}
启动项目,通过 postman 调用 login 接口,查看结果。
③、使用@WebFilter
和@ServletComponentScan
配置过滤器
在 Filter 包新建 LoginFilter,在实现类上使用 @WebFilter 注解,在启动类上使用 @ServletComponentScan 注解设置扫描路径。
代码实现如下:
package com.duan.Filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @author db* @version 1.0* @description LoginFilter*/@WebFilter(urlPatterns = "/*")
public class LoginFilter implements Filter {// 拦截方法,只要资源请求被拦截到,就一定会调用此方法@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("拦截方法执行了");// chain.doFilter(request,response);}}
启动类上添加 @ServletComponentScan 注解
package com.duan;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;/*** @author db* @version 1.0* @description FilterApplication*/
@ServletComponentScan
@SpringBootApplication
public class FilterApplication {public static void main(String[] args) {SpringApplication.run(FilterApplication.class);}
}
通过 postman 调用 login 接口,发现 filter 会拦截 login 请求。
修改 loginFilter 代码
package com.duan.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @author db* @version 1.0* @description LoginFilter* @since 2023/12/19*/@WebFilter(urlPatterns = "/*")
public class LoginFilter implements Filter {// 拦截方法,只要资源请求被拦截到,就一定会调用此方法@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("拦截方法执行,拦截了请求");System.out.println("放行前逻辑+++++++");chain.doFilter(request,response);System.out.println("放行后逻辑——————");}
}
在通过 postman 调用 login 方法,
查看控制台输出
二、拦截器
2.1、理论概念
概念:是一种动态拦截方法调用的机制,类似于过滤器。在Spring中动态拦截控制器中方法的执行。
作用:在调用目标方法前后执行相关操作,进行增强。如:日志记录、权限检查、性能监控等。
实现拦截器步骤:
- 首先定义一个拦截器,在该拦截器类上使用 @Component 注解,实现 HandlerInterceptor 接口,并重写所有方法。
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):
目标方法执行前调用 true 放行。postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):
目标方法执行后调用。afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):
请求处理后调用。
- 将创建的拦截器加入到 SpringBoot 的配置文件中。
2.2、SpringBoot 集成拦截器
①、新建一个 SpringBoot 项目,在 handler 包新建 LoginInterceptor 实现类,并在实现类中实现 preHandle、postHandle、afterCompletion 方法,并且在该类上使用 @Component 注解。
package com.duan.handler;import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** @author db* @version 1.0* @description LoginInterceptor* @since 2023/12/20*/
@Component
public class LoginInterceptor implements HandlerInterceptor {// 目标方法执行前调用 true:放行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {System.out.println("preHandle");return true;}// 目标方法执行后调用@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");}// 请求处理后调用@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("Completion...");}
}
②、在 config 包下新建 LoginInterceptorConfig 配置类,在类中配置拦截器。
package com.duan.config;import com.duan.handler.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @author db* @version 1.0* @description LoginInterceptorConfig 注册拦截器* @since 2023/12/20*/
@Configuration
public class LoginInterceptorConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry){registry.addInterceptor(loginInterceptor).addPathPatterns("/**");}
}
③、通过 postman 调用 login 接口,发现过滤器会过滤 login 请求。
三、总结
过滤器和拦截器区别:
过滤器(Filter) | 拦截器(Interceptor) | |
调用方 | Filter 被Server(Tomcat)调用 | 被Spring调用 |
实现方式 | 基于函数回调 | 基于Java反射 |
定义位置 | 是在java.servlet包下 | 接口HandlerInterceptor定义在org.springframework.web.servlet包下 |
作用位置 | Filter只在Servlet前后起作用 | 拦截器可以在方法前后、异常抛出前后等 |
拦截器和过滤器同时存在时执行流程如下图所示:
代码仓库链接:https://gitee.com/duan138/practice-code/tree/dev/
下一篇文章我们使用过滤器和拦截器实现基于 Token 认证的登录功能。
改变你能改变的,接受你不能改变的,关注公众号:程序员康康,一起成长,共同进步。