SpringMVC的拦截器介绍

拦截器是springmvc里面的,自定义可以通过实现HandlerInterceptor接口

public class CustomerInterceptor implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(CustomerInterceptor.class);
	
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        String sessionId = session.getId();
        UserCustomer userCustomer = (UserCustomer) request.getSession().getAttribute(sessionId);
        // 获取http请求方式
        String schnasme = request.getScheme();
        String serverbane = request.getServerName();
        int prot = request.getServerPort();
        String urlpath = schnasme+"://"+serverbane+":"+prot+"/";
        if(userCustomer == null){
            response.sendRedirect(urlpath);
            logger.info("已成功拦截并转发跳转");
            return false;
        }
        logger.info("合格不需要拦截,放行");
        return true;
    }

    @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 {

    }
}

把自定义的拦截器,放入到springmvc容器里面,一种方式在配置文件里面配置拦截器,

<mvc:interceptors path-matcher="xxx">  
        <mvc:interceptor>  
            <mvc:mapping path="xxx"/>  
            <mvc:exclude-mapping path="xxxx"/>  
            <bean class="xxxx"></bean>  
        </mvc:interceptor>  
        <bean class="com.lg.mvc.interceptor.LoginInterceptor" />  
    </mvc:interceptors>  

另外一种就是下面通过实现WebMvcConfigurer接口里面的addInterceptors方法。

public class CustomerMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 用于设置不需要拦截 的路径
        List<String> pathList = new ArrayList<>();
        pathList.add("/customer/login");
        pathList.add("/home");
        pathList.add("/login/lib/**");
        registry.addInterceptor((new CustomerInterceptor())).addPathPatterns("/**").excludePathPatterns(pathList);
    }

    /**
     * 允许跨域
     * Cors协议
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST","DELETE","PUT")
                .allowedHeaders("*")
                .allowCredentials(true).maxAge(3600);
    }
}

这样我们自定义配置的拦截器就生效了。

每次请求拦截器是如何生效的?

每次请求都会执行DispatcherServlet —》doService()—》doDispatch()

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				//重点1 这里执行interceptor的preHandle方法  
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				//这里执行处理函数  
				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				//重点2:这里执行interceptor的postHandle方法  
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			//重点3:这里执行interceptor的afterCompletion方法  
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		//重点4:当出现异常时,仍然执行afterCompletion方法  
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

通过上面的代码我们可以知道拦截器是封装在HandlerExecutionChain里面了。后续的执行也是通过遍历HandlerExecutionChain对象里面的HandlerInterceptor执行的,
我们自定义的是HandlerInterceptor 对象,但是封装到HandlerMapping里面的是MappedInterceptor对象MappedInterceptor类是HandlerInterceptor 的子类,而我们自定义的拦截器放入被封装到了MappedInterceptor.interceptor属性中了。
但是HandlerExecutionChain里面的interceptorList则是我们自定义的HandlerInterceptor 而不是MappedInterceptor。

public final class MappedInterceptor implements HandlerInterceptor {
	//拦截的路径集合
	@Nullable 
	private final String[] includePatterns;
	//放行的路径集合
	@Nullable
	private final String[] excludePatterns;
	//我们自定义的拦截器,被注入到了这里
	private final HandlerInterceptor interceptor;
	
	@Nullable
	private PathMatcher pathMatcher;

为什么要这么设置呢?

因为MappedInterceptor对象里面含有拦截路径和放行路径,可以在HandlerMapping里面生成HandlerExecutionChain对象确定添加哪些HandlerInterceptor 的时候;判断请求的url地址和includePatterns,excludePatterns比较,得出此请求是否需要被当前拦截器拦截,需要拦截的话,就把当前拦截器添MappedInterceptor的属性interceptor(我们自定义的拦截器)加到HandlerExecutionChain里面。

doDispatch方法里面重要的是 mappedHandler = getHandler(processedRequest); 获取到HandlerExecutionChain对象,这个对象里面封装了此次请求触发的所有拦截器集合和具体要执行的handler对象。
DispatcherServlet类型的方法


protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping hm : this.handlerMappings) {
				if (logger.isTraceEnabled()) {
					logger.trace(
							"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
				}
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

从上面的代码可以看到获取HandlerExecutionChain 是通过遍历handlerMappings,只要有一个handlerMapping产生HandlerExecutionChain ,就不在遍历的handlerMappings了。既然是由HandlerMapping来产生的HandlerExecutionChain,则它需要为每一个它所管辖的handler来装配HandlerInterceptor。所以HandlerMapping必然是mvc:interceptors标签内容的使用者。对于每个请求先找到对应的HandlerMapping,然后由这个handlerMapping来找到对应请求的handler,然后由handlerMapping自身的interceptor和这个handler来构建一个HandlerExecutionChain。
使用者:AbstractHandlerMapping,它的属性有:

    private PathMatcher pathMatcher = new AntPathMatcher();  
  
	private final List<Object> interceptors = new ArrayList<Object>();  
  
	private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();  
  
	private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();  

这里便可以看到,它所使用的默认的PathMatcher为AntPathMatcher

参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值