博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

拦截器定义

1.Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并做相应的处理。例如通过拦截器可以进行权限验证、判断用户是否已登录等。
2. 执行先后顺序:Filter前处理 --> Interceptor前处理 --> controller--> Interceptor后处理 --> Filter后处理
3. HandlerInterceptor 的功能跟过滤器类似,但是提供更精细的的控制能力:在request被响应之前(preHandle)、request被响应之后(postHandle)、视图渲染之前以及request全部结束之后(afterCompletion)。
4. Filter 的 doFilter(ServletRequest request,ServletResponse response,FilterChain chain):实现过滤功能,该方法就是对每个请求及响应增加的额外处理。该方法可以实现对用户请求进行预处理(ServletRequest request),也可实现对服务器响应进行后处理(ServletResponse response)—它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理

编写步骤

1.在spring中通过实现 HandlerInterceptor接口,然后重写preHandle(),postHandle(),afterCompletion(); preHandle()方法:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行;当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。  postHandle()方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。 afterCompletion()方法:该方法在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作 2. 实现javax.servlet.Filter 接口,然后重写doFilter()方法,。

例如实现记录请求url

public class LogFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(LogFilter.class);
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("----项目启动----");
    }
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //拦截请求
        String reqPath = ((HttpServletRequest)servletRequest).getServletPath();
        if(!(reqPath.contains(".js") || reqPath.contains(".css"))){
            logger.info("----请求url:"+reqPath+"----");
        }
        //拦截继续传递
        filterChain.doFilter(servletRequest,servletResponse);
    }
    
    @Override
    public void destroy() {
        logger.info("----项目关闭----");
    }
}

例如判断用户是否登录,ThreadLocal 用来存储用户信息

思路:拦截所有请求(排除静态资源请求),然后获取登录信息是否有效,无效就重定向到登录页面,有效继续传递。
/**
 * @author ngLee
 * @version 1.0
 * @Desc 如果用户信息存在,就不拦截请求
 * @date 2021/3/25 22:05
 */
@Component
public class AuthIntercepteror implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       //获取用户信息,session里面取
        User user = UserContext.getUser();
        if(user == null){
            String target = URLEncoder.encode(request.getRequestURI(),"UTF-8");
            String reqType = request.getMethod();
            if("GET".equalsIgnoreCase(reqType)){
                response.sendRedirect("/account/login.vw?target="+target);
            }else {
                response.sendRedirect("/account/login.vw");
            }
        }
        return false;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        
    }
}

/**
 * @author ngLee
 * @version 1.0
 * @Desc 如果用户信息存在,就不拦截请求
 * 用户信息不存在,重定向到登录页面
 * @date 2021/3/25 22:05
 */
@Component
public class AuthIntercepteror implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        User user = UserContext.getUser();
        
        if(user == null){
            String target = URLEncoder.encode(request.getRequestURI(),"UTF-8");
            String reqType = request.getMethod();
            if("GET".equalsIgnoreCase(reqType)){
                response.sendRedirect("/account/login.vw?target="+target);
            }else {
                response.sendRedirect("/account/login.vw");
            }
        }
        return false;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    }
}

//存储用户信息 公用
public class UserContext {
    public static ThreadLocal<User> USER_LOCAL = new ThreadLocal<>();
    
    /**
     * @desc 存储用户
     * @author ngLee
     * @date 2021/3/25 21:56
     */
    public static void setUser(User user){
        USER_LOCAL.set(user);
    }
    
    public static User getUser(){
        return  USER_LOCAL.get();
    }
    
    public static void remove(){
        USER_LOCAL.remove();
    }
}

将实现的拦截器 配置到项目中,才能起作用

注意:拦截器的执行是有一定顺序的,该顺序与我们拦截器的注册顺序有关,例如上问实现的两个拦截器,工作顺序应该是AuthIntercepter拦截请求,判断是否有用户信息,有信息则放到当前线程进行存储,然后存储的信息供AuthIntercepteror使用,然后根据请求的方式,进行重定向。流程图如下

将拦截器进行注册,实现WebMvcConfigurer 接口,重写addInterceptors()方法

/**
 * @author ngLee
 * @version 1.0
 * @Desc
 * @date 2021/3/25 22:17
 */
@Configuration
public class WebMvcConf implements WebMvcConfigurer {

    @Autowired
    private AuthIntercepter authIntercepter;
    @Autowired
    private AuthIntercepteror authIntercepteror;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //所有请求
        registry.addInterceptor(authIntercepter).excludePathPatterns("/static").addPathPatterns("/**");
        //涉及到个人信息需要登录
        registry.addInterceptor(authIntercepteror).addPathPatterns("/account/profile**");
    }
}