zoukankan      html  css  js  c++  java
  • SpringMVC——自定义拦截器、异常处理以及父子容器配置

    自定义拦截器:

    一、若想实现自定义拦截器,需要实现 org.springframework.web.servlet.HandlerInterceptor 接口。

    二、HandlerInterceptor API

    1. 接口中定义了三个方法

    2.preHandle() 

    (1)调用时机

    在 org.springframework.web.servlet.DispatcherServlet#doDispatch 方法中。

    org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle 具体的调用过程

    可以看到,preHander() 方法的调用是在调用目标方法前调用的。

    同时可以看到,通过循环,调用了所有的拦截器,并且如果自定义的拦截器的 preHandler() 返回 false 的情况下,还是会去调用拦截器的 afterCompletion() 方法。

    (2)可以获取到的资源

     HttpServletRequest、HttpServletResponse、以及目标处理器。

    3.postHandler() 

    (1)调用的时机

    可以看到在调用目标方法后,渲染视图前调用的 postHandler() 方法。

    具体的调用过程:

    去调用每一个拦截器的 postHandler() 方法,注意循环的方式,可以看到拦截器栈 preHandler() 和 postHandler() 方法调用形成了一个 U 形。 

    (2)可以获取到的资源

    HttpServletRequest、HttpServletResponse、目标hanler 处理器、以及返回的 ModelAndView 对象。

    3.afterCompletion()

    (1)调用时机

    可以看到,org.springframework.web.servlet.DispatcherServlet#doDispatch 执行逻辑的过程,捕获到异常后,最终都是由拦截器的 afterCompletion() 方法进行的处理。

    (2)可以获取到的资源

    HttpServletReques, HttpServletResponse, 目标 handler 处理器, 所有的异常信息

    4. HandlerInterceptor 家族

    三、实现自定义的拦截器

    1.继承 HandlerInterceptorAdapter ,按照实际需求实现对应的方法就ok。

    2.在 SpringMVC Config 文件中配置。

    e1:

    /**
     * @author solverpeng
     * @create 2016-09-01-15:56
     */
    public class FirstInterceptor extends HandlerInterceptorAdapter {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion");
        }
    }
    <mvc:interceptors>
        <bean class="com.nucsoft.springmvc.interceptor.FirstInterceptor"/>
    </mvc:interceptors>

    说明:此种配置可以拦截器所有请求。

    e2:

    /**
     * @author solverpeng
     * @create 2016-09-01-16:08
     */
    public class SecondInterceptor extends HandlerInterceptorAdapter {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("SecondInterceptor#preHandle");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("SecondInterceptor#postHandle");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("SecondInterceptor#afterCompletion");
        }
    }
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/test/**"/>
            <bean class="com.nucsoft.springmvc.interceptor.SecondInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

    说明:只会拦截路径以 test 开头的请求。如:http://localhost:8080/springmvc/test/testInterceptor02 会被 SecondInterceptor 拦截。

    四、拦截器的几个用处

    1.性能监控

    /**
     * 计算每次请求耗时
     * @author solverpeng
     * @create 2016-09-01-17:46
     */
    public class ConsumeTimeInterceptor extends HandlerInterceptorAdapter{
        // SpringMVC 是单例的,所以对于每一次请求,从 ThreadLocal 中获取。
        private NamedThreadLocal<Long> consumeTime = new NamedThreadLocal<>("consume_time");
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            consumeTime.set(System.currentTimeMillis());
            System.out.println("ConsumeTimeInterceptor#preHandle");
            return true;
        }
    
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("ConsumeTimeInterceptor#afterCompletion");
            Long threadEnd = System.currentTimeMillis();
            Long threadStart = consumeTime.get();
            Long consume = threadEnd - threadStart;
            if(consume > 10) {
                System.out.println("add to log: " + consume);
            }
        }
    }
    <mvc:interceptors>
        <bean class="com.nucsoft.springmvc.interceptor.ConsumeTimeInterceptor"/>
        <bean class="com.nucsoft.springmvc.interceptor.FirstInterceptor"/>
    </mvc:interceptors>

    控制台输出:

    从中也可以看出:拦截器的顺序与 SpringMVC 中配置的顺序是一致的。

    2.登录检测

    检测用户是否登录。

    异常处理

    1.局部的

    在目标 handler 类中,声明一个有 @ExceptionHandler 标注的方法,通过 @ExceptionHandler 的 value 的属性来指定需要处理的异常类型。

    可以处理的异常可以是一个类型,也可以是多个类型。如:

    @ExceptionHandler(value = {ArithmeticException.class})
    
    @ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})

    如:

    @Controller
    public class SpringTest {
        @ExceptionHandler(value = {ArithmeticException.class})
        public String handleArithmeticException(Exception ex) {
            System.out.println("spring test class");
            ex.printStackTrace();
            return "error";
        }
    }

    handleArithmeticException() 只能处理 SpringTest 控制器中出现的 ArithmeticException 类型的异常。

    2.全局的

    (1)基于注解

    声明一个统一的异常处理类:

    需要对异常处理类添加 @ControllerAdvice 注解,对异常处理方法的标注还和局部的情况一样。如:

    @ControllerAdvice
    public class HandlerException {
    
        @ExceptionHandler({ArithmeticException.class})
        public String handlerArithmeticException(Exception ex) {
            ex.printStackTrace();
            return "error";
        }
    
    }

    handlerArithmeticException() 可以处理所有处理器发生的 ArithmeticException 类型的异常。

    (2)基于xml

    如:

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
        id="simpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="ArithmeticException">error</prop>
            </props>
        </property>
    </bean>

    通过属性 exceptionMappings 来指定要处理的异常,以及出现异常返回的页面。

    3.优先级

    基于xml>局部>全局

    4.如何在异常页面得到异常信息

    request.getAttribute("javax.servlet.error.exception")

    5.@ResponseStatus

    可以对全局的异常类标注 @ResponseStatus 注解,通过其 value 属性来指定返回的 Http状态码。是 HttpStatus 枚举类型。

    来指定返回对应状态码的错误页面。

    父子容器配置

    SpringMVC 层容器可以作为 Spring 容器的子容器:

    即 Web 层容器可以引用业务层容器的 Bean,而业务层容器却访问不到 WEB 层容器 Bean。

    SpringMVC Config:

    <context:component-scan base-package="com.nucsoft.springmvc" use-default-filters="false">
        <!-- 只扫描 @Controller 和 @ControllerAdvice 注解-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>

    Spring Config:

    <context:component-scan base-package="com.nucsoft.springmvc">
        <!-- 不扫描 @Controller 和 @ControllerAdvice 注解-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>
  • 相关阅读:
    微擎模块机制分析2
    微擎we7模块和模板安装方法
    git的使用 及一些常见的错误处理
    人,活着为了什么?
    fedora配置ip
    fedora安装gcc
    linux查看内核版本和发行版本号
    python数据类型2
    python之零碎知识
    python之数据类型1
  • 原文地址:https://www.cnblogs.com/solverpeng/p/5830931.html
Copyright © 2011-2022 走看看