过滤器与拦截器详解
过滤器 和 拦截器的 6个区别,别再傻傻分不清了
拦截器(Interceptor)和过滤器(Filter)的执行顺序和区别
- 过滤器
依赖于servlet容器,实现基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤 *** 作,获取我们想要获取的数据,过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换等等 *** 作,便于代码重用,不必每个servlet中进行冗余 *** 作。
Filter随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。 - 拦截器详解
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,拦截器可以调用IOC容器中的各种依赖,而过滤器不能,因此可以使用Spring的依赖注入进行一些业务 *** 作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。 - 两者的本质区别
拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调。从灵活性上说拦截器功能更强大些,Filter能做的事情,都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor。不过还是根据不同情况选择合适的。
@WebFilter(urlPatterns = "/api/v1/pri/*", filterName = "loginFilter")
//@WebFilter 标记一个类为filter,被spring进行扫描
public class LoginFilter implements Filter {
//新建一个Filter类,implements Filter,并实现对应的接口
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init LoginFilter======");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter LoginFilter======");
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String token = req.getHeader("token");
if(StringUtils.isEmpty(token)){
token = req.getParameter("token");
}
if(StringUtils.isEmpty(token)){
return;
}else {
//判断token是否合法
User user = UserServiceImpl.sessionMap.get(token);
if(user!=null){
//控制chain.doFilter的方法的调用,来实现是否通过放行
filterChain.doFilter(servletRequest,servletResponse);
}
}
}
@Override
public void destroy() {
System.out.println("destroy LoginFilter======");
}
}
@RestController
@RequestMapping("api/v1/pri/order")
public class VideoOrderController {
@RequestMapping("save")
public JsonData saveOrder(){
return JsonData.buildSuccess("下单成功");
}
}
步骤:
- 启动类里面增加 @ServletComponentScan,进行扫描
- 新建一个Filter类,implements Filter,并实现对应的接口
- @WebFilter 标记一个类为filter,被spring进行扫描
- urlPatterns:拦截规则,支持正则
- 控制chain.doFilter的方法的调用,来实现是否通过放行
- 不放行,web应用resp.sendRedirect(“/index.html”) 或者 返回json字符串
总结:
1.只有先登录拿到token,然后再看token对应的用户是否为空判断用户是否登录。
2.过滤器的urlPatterns = "/api/v1/pri/*"
和 下单controller @RequestMapping("api/v1/pri/order")
要一致
优化:如何使用状态码显示不同登录状态,对前端较友好?
- implements WebMvcConfigurer 并且对拦截器注册
@Configuration
class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getLoginInterceptor()).addPathPatterns("/api/v1/pri/**");
registry.addInterceptor(new TwoIntercepter()).addPathPatterns("/api/v1/pri/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
// 补充知识点
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(getLoginInterceptor()).addPathPatterns("/api/v1/pri/**","/api/v1/pri/user/**")
// .excludePathPatterns("/**/*.html","/**/*.js"); //配置不拦截某些路径;
// registry.addInterceptor(new TwoIntercepter()).addPathPatterns("/api/v1/pri/**")
// WebMvcConfigurer.super.addInterceptors(registry);
// }
@Bean
public LoginIntercepter getLoginInterceptor(){
return new LoginIntercepter();
}
}
- 自定义拦截器 HandlerInterceptor
class LoginIntercepter implements HandlerInterceptor {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//调用Controller某个方法之前
System.out.println("LoginIntercepter preHandle =====");
String token = request.getHeader("token");
if(StringUtils.isEmpty(token)){
token = request.getParameter("token");
}
if(!StringUtils.isEmpty(token)){
//判断token是否合法
User user = UserServiceImpl.sessionMap.get(token);
if(user!=null){
return true;
}else {
JsonData jsonData = JsonData.buildError("登录失败,token无效",-2);
String jsonStr = objectMapper.writeValueAsString(jsonData);
renderJson(response,jsonStr);
return false;
}
}else {
JsonData jsonData = JsonData.buildError("未登录",-3);
String jsonStr = objectMapper.writeValueAsString(jsonData);
renderJson(response,jsonStr);
return false;
}
//return HandlerInterceptor.super.preHandle(request,response,handler);
}
private void renderJson(HttpServletResponse response,String json){
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
try(PrintWriter writer = response.getWriter()){
writer.print(json);
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//Controller之后调用,视图渲染之前,如果控制器Controller出现了异常,则不会执行此方法
System.out.println("LoginIntercepter postHandle =====");
HandlerInterceptor.super.postHandle(request,response,handler,modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//不管有没有异常,这个afterCompletion都会被调用,用于资源清理
System.out.println("LoginIntercepter afterCompletion =====");
HandlerInterceptor.super.afterCompletion(request,response,handler,ex);
}
}
运行结果:
按照注册顺序进行拦截,先注册,先被拦截
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)