过滤器-拦截器(4.27-c)

过滤器-拦截器(4.27-c),第1张

过滤器与拦截器详解
过滤器 和 拦截器的 6个区别,别再傻傻分不清了
拦截器(Interceptor)和过滤器(Filter)的执行顺序和区别

1.背景知识
  • 过滤器
    依赖于servlet容器,实现基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤 *** 作,获取我们想要获取的数据,过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换等等 *** 作,便于代码重用,不必每个servlet中进行冗余 *** 作。
    Filter随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。
  • 拦截器详解
    依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,拦截器可以调用IOC容器中的各种依赖,而过滤器不能,因此可以使用Spring的依赖注入进行一些业务 *** 作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。
  • 两者的本质区别
    拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调。从灵活性上说拦截器功能更强大些,Filter能做的事情,都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor。不过还是根据不同情况选择合适的。
2.举例 2.1.过滤器
@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") 要一致

优化:如何使用状态码显示不同登录状态,对前端较友好?

2.2.拦截器
  • 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);
    }
}

运行结果:

按照注册顺序进行拦截,先注册,先被拦截

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/757626.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-01
下一篇 2022-05-01

发表评论

登录后才能评论

评论列表(0条)

保存