拦截器
过滤器过滤的是客户端对资源的访问
拦截器的配置
SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC的拦截器需要实现HandlerInterceptor
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:
<mvc:interceptors> <bean id="firstInterceptor" class="com.my.interceptor.FirstInterceptor" /> <ref bean="secondInterceptor" /> <!-- bean标签和ref标签所配置的拦截器默认对DispatcherServlet处理的所有请求进行拦截 --> <!--<bean class="com.my.interceptor.FirstInterceptor"/>--> <!--<ref bean="firstInterceptor" />--> <!--<mvc:interceptor> <!-- 配置需要拦截的请求的请求路径,/**表示所有请求 --> <!-- <mvc:mapping path="/**"/> <!-- 配置需要排除拦截的请求的请求路径 --> <!-- <mvc:exclude-mapping path="/abc"/> <!-- 配置拦截器 --> <!-- <ref bean="firstInterceptor" /> <!-- </mvc:interceptor> --> </mvc:interceptors>
/** * 拦截器的三个方法: * preHandle():在控制器方法执行之前执行,其返回值表示对控制器方法的拦截(false) 或放行(true) * postHandle():在控制器方法执行之后执行 * afterCompletion():在控制器方法执行之后,且渲染视图完毕之后执行 在render()之后执行, * * 多个拦截器执行顺序和在SpringMVC的配置文件中配置的顺序有关 * preHandle()按照配置的顺序执行,而postHandle()和afterCompletion按照配置的反序执行 */ @Component public class FirstInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 控制器方法执行之前执行 true 放行 false 拦截 System.out.println("FirstInterceptor-->preHandle"); return HandlerInterceptor.super.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("FirstInterceptor-->postHandle"); HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("FirstInterceptor-->afterCompletion"); HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
异常处理器
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <!-- key设置要处理的异常,value设置出现该异常时要跳转的页面所对应的逻辑视图 --> <prop key="java.lang.ArithmeticException">error</prop> </props> </property> <!-- 设置共享在请求域中的异常信息的属性名 --> <property name="exceptionAttribute" value="ex"></property> </bean>
处理器 == 控制器方法
applyPreHandle()源码
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) { HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i); if (!interceptor.preHandle(request, response, this.handler)) { this.triggerAfterCompletion(request, response, (Exception)null); return false; } } return true; }
applyPostHandle()源码
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { for(int i = this.interceptorList.size() - 1; i >= 0; --i) { HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i); interceptor.postHandle(request, response, this.handler, mv); } }
triggerAfterCompletion源码
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) { for(int i = this.interceptorIndex; i >= 0; --i) { HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i); try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable var7) { logger.error("HandlerInterceptor.afterCompletion threw exception", var7); } } }
根据观察源码我们可以知道为什么preHandle()按照配置的顺序执行,而postHandle()和afterCompletion按照配置的反序执行。
因为在源码中applyPreHandle()遍历时用的是i++,而applyPostHandle()和triggerAfterCompletion()中用的是i--,
若拦截器中有某个拦截器的preHandle()返回了false
-
拦截器的preHandle()返回了false和它之前的拦截器都会执行 之后的不会执行
-
所有拦截器的postHandle()都不执行
-
拦截器的preHandle()返回了false之前的拦截器的afterCompletion()会执行
异常处理器
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:Handler ExceptionResolver
Handler ExceptionResovler接口的实现类又:DefaultHandlerExceptionResolver 和 SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResovler,使用方式:
XML
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <!-- key设置要处理的异常,value设置出现该异常时要跳转的页面所对应的逻辑视图 --> <prop key="java.lang.ArithmeticException">error</prop> </props> </property> <!-- 设置共享在请求域中的异常信息的属性名 --> <property name="exceptionAttribute" value="ex"></property> </bean>
注解:
// 将当前类标识为异常处理的组件 @ControllerAdvice public class ExceptionController { // 设置要处理的异常信息 @ExceptionHandler(ArithmeticException.class) public String handleException(Throwable ex, Model model){ // ex标识控制器方法所出现的异常 model.addAttribute("ex", ex); return "error"; } }