简介
- 过滤器:filter基于回调函数,我们需要实现的filter接口中doFilter方法就是回调函数,由于filter是基于servlet的所以,filter不能使用Spring 的容器,也不支持 @Value等Spring 标签
- 拦截器: interceptor拦截器则基于java本身的反射机制,java.lang.reflect,使用对象的代理模式。Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。要注意拦截器放的位置顺序。拦截器的机制基于aop 面向切面编程
- AOP:@Aspect与Interceptor的都是基于spring aop的实现,@Aspect粒度更细
顺序
请求->>过滤器->>拦截器-->Aspect->>拦截器->>过滤器->>响应
拦截规则越来越细致,执行顺序依次是过滤器、拦截器、切面。一般情况下数据被过滤的时机越早对服务的性能影响越小,因此我们在编写相对比较公用的代码时,优先考虑过滤器,然后是拦截器,最后是aop。
比如权限校验 :应该使用过滤器在最顶层做校验
日志记录:牵扯到业务逻辑完成前后的日志记录考虑到使用AOP实现
区别
1、拦截器是基于Java的反射机制,动态代理。过滤器是基于java的函数回调
2、拦截器不依赖于servlet容器,而过滤器依赖于servlet容器
3、拦截器只能对action请求起作用(controller层),过滤器几乎对所有的请求起作用(包括静态资源,图片等)
4、拦截器可以获取IOC容器中的各个bean,包括容器上下文。过滤器不行,在拦截器中注入一个service可以调用逻辑业务
5、在action生命周期中,拦截器可以被多次调用,过滤器只能在servlet溶初始化是调用一次
6、aop 和 拦截器一样,颗粒度更细,更灵活,可以专门基于方法
过滤器
过滤器拦截的是URL
Spring中自定义过滤器(Filter)一般只有一个方法,返回值是void,当请求到达web容器时,会探测当前请求地址是否配置有过滤器,有则调用该过滤器的方法(可能会有多个过滤器),然后才调用真实的业务逻辑,至此过滤器任务完成。过滤器并没有定义业务逻辑执行前、后等,仅仅是请求到达就执行。
特别注意:过滤器方法的入参有request,response,FilterChain,其中FilterChain是过滤器链,使用比较简单,而request,response则关联到请求流程,因此可以对请求参数做过滤和修改,同时FilterChain过滤链执行完,并且完成业务流程后,会返回到过滤器,此时也可以对请求的返回数据做处理。
拦截器
拦截器拦截的是URL
拦截器有三个方法,相对于过滤器更加细致,有被拦截逻辑执行前、后等。Spring中拦截器有三个方法分别表示如下
- preHandle 表示被拦截的URL对应的方法执行前的自定义处理
- postHandle 表示此时还未将modelAndView进行渲染,被拦截的URL对应的方法执行后的自定义处理,。
- afterCompletion:表示此时modelAndView已被渲染,执行拦截器的自定义处理。
AOP(面向切面)
面向切面拦截的是类的元数据(包、类、方法名、参数等)
AOP相对于拦截器更加细致,而且非常灵活,拦截器只能针对URL做拦截,而AOP针对具体的代码,能够实现更加复杂的业务逻辑。
1.过滤器实现
配置ip过滤器
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "SafeIpFilter", urlPatterns = {"/*"})
public class SafeIpFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String host = servletRequest.getServerName();
System.out.println(host);
System.out.println(servletRequest.getRemoteHost());
if (1 == 1) {
System.out.println("终止");
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
启动类中增加过滤器扫描注解
@SpringBootApplication
@EnableScheduling
@ServletComponentScan
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
2、拦截器实现
添加拦截器到webMvc
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private SafeIpInterceptor safeIpInterceptor;
/**
* 添加过滤器
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(safeIpInterceptor)
.addPathPatterns("/**");
}
}
实现拦截器逻辑
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class SafeIpInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(SafeIpInterceptor.class);
/**
* This implementation always returns {@code true}.
* 进入 Handler方法之前执行 、用于身份认证、身份授权、比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
* @param request
* @param response
* @param handler
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return super.preHandle(request, response, handler);
}
/**
* This implementation is empty.
* 进入Handler方法之后,返回modelAndView之前执行,应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
* @param request
* @param response
* @param handler
* @param modelAndView
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
/**
* This implementation is empty.
* 执行Handler完成执行此方法,应用场景:统一异常处理,统一日志处理
* @param request
* @param response
* @param handler
* @param ex
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
}
/**
* This implementation is empty.
*
* @param request
* @param response
* @param handler
*/
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
super.afterConcurrentHandlingStarted(request, response, handler);
}
}
此处可以参考:SpringBoot 通过拦截器验证Referer 防御CSRF攻击
3、AOP
此处可以参考:springboot-AOP