0
点赞
收藏
分享

微信扫一扫

SpringMVC-拦截器

程序员知识圈 2022-04-16 阅读 56
后端java

一、介绍
(1)SpringMVC的拦截器用于拦截控制器方法的执行。
(2)要使用拦截器需要实现HandlerInterceptor接口。
(3)拦截器需要在SpringMVC的配置文件中配置。
(4)拦截器中的三个方法preHandler()、postHandle()、afterCompletion(),分别在控制器方法执行前、控制器方法执行后、渲染后执行。

二、源码分析

(1)拦截器中三个方法的执行顺序为preHandler()、postHandle()、afterCompletion()

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

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

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
					//在执行handle()方法前,也就是执行控制器方法前,
					//先执行配置好的拦截器中的preHandle()方法
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
					//执行控制器方法
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    //控制器方法执行后,执行配置好的拦截器中的postHandle()方法
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
				//该方法内部会执行视图渲染,渲染完毕则执行配置好的拦截器中的afterCompletion()方法,具体分析见下文
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }

(2)processDispatchResult()方法

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
        boolean errorView = false;
        if (exception != null) {
            if (exception instanceof ModelAndViewDefiningException) {
                this.logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException)exception).getModelAndView();
            } else {
                Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
                mv = this.processHandlerException(request, response, handler, exception);
                errorView = mv != null;
            }
        }

        if (mv != null && !mv.wasCleared()) {
        	//进行视图渲染
            this.render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        } else if (this.logger.isTraceEnabled()) {
            this.logger.trace("No view rendering, null ModelAndView returned.");
        }

        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
            	//执行配置好的拦截器中的afterCompletion()方法
                mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
            }

        }
    }

(3)applyPreHandle()方法

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
			//按拦截器在配置文件中的配置顺序遍历
            for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
                HandlerInterceptor interceptor = interceptors[i];
                //如果拦截器中的preHandle()方法返回false,
                //则直接执行triggerAfterCompletion()方法,然后跳出DispatcherServlet,
                //注意,不一定执行triggerAfterCompletion()中的所有配置好的拦截器的afterCompletion()方法,
                //跟循环中的interceptorIndex有关
                if (!interceptor.preHandle(request, response, this.handler)) {
                    this.triggerAfterCompletion(request, response, (Exception)null);
                    return false;
                }
            }
        }

        return true;
    }

(4)applyPostHandle()方法

    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
        	//该方法只会在所有配置好的拦截器中的preHandle()方法均返回true后执行,
        	//会倒序执行所有配置好的拦截器中的postHandle()方法
            for(int i = interceptors.length - 1; i >= 0; --i) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }

    }

(5)triggerAfterCompletion()方法

    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
        	//一直执行到最后一个preHandle()方法返回true的拦截器的afterCompletion()方法
            for(int i = this.interceptorIndex; i >= 0; --i) {
                HandlerInterceptor interceptor = interceptors[i];

                try {
                    interceptor.afterCompletion(request, response, this.handler, ex);
                } catch (Throwable var8) {
                    logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
                }
            }
        }

    }

三、项目测试
(1)编写拦截器FirstInterceptor、SecondInterceptor

public class FirstInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor...preHandle");
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor...postHandle");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("FirstInterceptor...afterCompletion");
    }
}
public class SecondInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("SecondInterceptor...preHandle");
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("SecondInterceptor...postHandle");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("SecondInterceptor...afterCompletion");
    }
}

(2)编写SpringMVC-config.xml,配置拦截器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.wsh.controller"></context:component-scan>
    <!--    配置Thymeleaf视图解析器-->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <!--视图解析器优先级-->
        <property name="order" value="1"/>
        <!--解析视图用的编码-->
        <property name="characterEncoding" value="UTF-8"/>
        <!--视图解析器模板引擎-->
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!--视图前缀-->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!--视图后缀-->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
    <mvc:interceptors>
        <bean class="com.wsh.interceptor.FirstInterceptor"></bean>
        <bean class="com.wsh.interceptor.SecondInterceptor"></bean>
    </mvc:interceptors>
</beans>

(3)创建Controller类

@Controller
public class MyController {

    @RequestMapping(value = {"/**"})
    @ResponseBody
    public String hello(){
        return "hello";
    }

}

(4)运行
在这里插入图片描述
在这里插入图片描述

四、配置选项
(1)在<mvc:interceptors>标签中,如果拦截器用bean或ref标签配置,则对所有请求有效。

    <mvc:interceptors>
        <bean class="com.wsh.interceptor.FirstInterceptor"></bean>
        <bean class="com.wsh.interceptor.SecondInterceptor"></bean>
    </mvc:interceptors>

(2)在<mvc:interceptors>标签中,如果拦截器用<mvc:interceptor>标签配置,则可以自定义对哪些请求有效。

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.wsh.interceptor.FirstInterceptor"></bean>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/abc"/>
            <bean class="com.wsh.interceptor.SecondInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
举报

相关推荐

0 条评论