拦截器和过滤器
拦截器和过滤器
一、区别

1、过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
2、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。
3、过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射
4、Filter是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。
5、Filter的执行由Servlet容器回调完成,而拦截器通常通**过动态代理(反射)**的方式来执行。
6、Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。
过滤器和拦截器非常相似,但是它们有很大的区别
区别
- 过滤器可以修改request,而拦截器不能
- 过滤器需要在servlet容器中实现,拦截器可以适用于javaEE,javaSE等各种环境
- 拦截器可以调用IOC容器中的各种依赖,而过滤器不能
- 过滤器只能在请求的前后使用,而拦截器可以详细到每个方法
总的来说 过滤器就是筛选出你要的东西,比如requeset中你要的那部分,拦截器在做安全方面用的比较多,比如终止一些流程
提示
过滤器(Filter) :可以拿到原始的http请求,但是拿不到你请求的控制器和请求控制器中的方法的信息。
拦截器(Interceptor):可以拿到你请求的控制器和方法,却拿不到请求方法的参数。
切片(Aspect): 可以拿到方法的参数,但是却拿不到http请求和响应的对象
二、过滤器 Fileter
1、使用
入口函数
@ServletComponentScan //过滤器生效标记
@SpringBootApplication
public class TliasApplication {
public static void main(String[] args) {
SpringApplication.run(TliasApplication.class, args);
}
}
过滤器类
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//1、获取url
String url = req.getRequestURI().toString();
log.info("请求的url:{}", url);
//2、判断请求的url中是否包含login
if(url.contains("login")){
log.info("登录操作,放行");
filterChain.doFilter(servletRequest, servletResponse);
return;
}
//3、获取请求头中的令牌
String jwt = req.getHeader("token");
//4、判断令牌是否存在,如果不存在,返回错误(未登录)
if(!StringUtils.hasLength(jwt)){
log.info("请求头为空,返回错误结果,未登录");
Result error = Result.error("NOT_LOGIN");
//手动转换对象 -- json
String noLogin = JSONObject.toJSONString(error);
resp.getWriter().write(noLogin);
return;
}
//5、校验jwt令牌
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析令牌失败,返回未登录");
Result error = Result.error("NOT_LOGIN");
//手动转换对象 -- json fastjson包
String noLogin = JSONObject.toJSONString(error);
resp.getWriter().write(noLogin);
return;
}
//6、放行
log.info("令牌合法,放行");
filterChain.doFilter(servletRequest, servletResponse);
}
}
fastjson依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
注意
当有多个过滤器时,按照文件名执行 ---->过滤器链
2、应用场景
- 过滤敏感词汇(防止sql注入)
- 设置字符编码
- URL级别的权限访问控制
- 压缩响应信息
三、拦截器 Interceptor
1、使用
实现拦截器可以通过继承 HandlerInterceptorAdapter
类也可以通过实现HandlerInterceptor
这个接口。另外,如果preHandle
方法return true
,则继续后续处理。
拦截器类
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override //目标方法运行前运行,返回值为true放行
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
// return HandlerInterceptor.super.preHandle(request, response, handler);
System.out.println("preHandle 运行");
//1、获取url
String url = req.getRequestURI().toString();
log.info("请求的url:{}", url);
//2、判断请求的url中是否包含login
if(url.contains("login")){
log.info("登录操作,放行");
return true;
}
//3、获取请求头中的令牌
String jwt = req.getHeader("token");
//4、判断令牌是否存在,如果不存在,返回错误(未登录)
if(!StringUtils.hasLength(jwt)){
log.info("请求头为空,返回错误结果,未登录");
Result error = Result.error("NOT_LOGIN");
//手动转换对象 -- json
String noLogin = JSONObject.toJSONString(error);
resp.getWriter().write(noLogin);
return false;
}
//5、校验jwt令牌
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析令牌失败,返回未登录");
Result error = Result.error("NOT_LOGIN");
//手动转换对象 -- json
String noLogin = JSONObject.toJSONString(error);
resp.getWriter().write(noLogin);
return false;
}
//6、放行
log.info("令牌合法,放行");
return true;
}
@Override //目标资源方法运行之后运行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
System.out.println("postHandle 运行");
}
@Override //视图渲染完毕后运行,最后运行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
System.out.println("afterCompletion 运行");
}
}
配置类
继承了WebMVCConfigurerAdapter
,这里我们重写了addInterceptors
这个方法,进行拦截器的配置,主要配置项就两个,一个是指定拦截器,第二个是指定拦截的URL.
@Configuration //配置类
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
/*
* /* 一级路径 /login,/depts 不能/depts/1
* /** 任意级路径
* /depts/* /depts 下的一级路径
* */
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
}
拦截器不生效常见问题
- 是否有加@Configuration
- 拦截路径是否有问题
**
和*
- 拦截器最后路径一定要 “
/**
”, 如果是目录的话则是/*/
2、应用场景
拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:
- 登录验证,判断用户是否登录。
- 权限验证,判断用户是否有权限访问资源,如校验token
- 日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量。
- 处理cookie、本地化、国际化、主题等。
- 性能监控,监控请求处理时长等。
- 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现)