上篇文章我们学习了 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 {
@Override
public 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 {
@Override
public 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 {
@Bean
public 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 {
// 拦截方法,只要资源请求被拦截到,就一定会调用此方法
@Override
public 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 {
// 拦截方法,只要资源请求被拦截到,就一定会调用此方法
@Override
public 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:放行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("preHandle");
return true;
}
// 目标方法执行后调用
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
// 请求处理后调用
@Override
public 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 {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public 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 认证的登录功能。
改变你能改变的,接受你不能改变的,关注公众号:程序员康康,一起成长,共同进步。