Spring MVC拦截器
在Spring MVC中,拦截器Interceptor和过滤器的Filter的作用是一样的,都是对某些资源的拦截。并且如果有多个拦截器对同一个资源进行拦截的时候,那么这时候就形成了拦截器链,此时是根据在spring-mvc.xml中配置拦截器的顺序,按照顺序执行preHandle方法,然后当目标资源执行完毕之后,就根据配置的顺序,倒序执行postHandle操作,当postHandle操作执行完毕之后,在根据配置的顺序,倒叙执行afterCompletion操作。
而Spring MVC拦截器和Filter的区别是:
所以执行拦截器的相关操作主要有3个步骤:
-
自定义拦截器XXInterceptor,使得这个类实现了HandlerInterceptor,然后重写它的方法preHandle,postHandle,afterCompletion,其中主要是重写preHandle方法。
-
在spring-mvc.xml中配置拦截器,对应的格式为:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="xxx"/> <!--对path中的资源进行拦截,其中如果它的值为/**时,表示对所有的资源进行拦截--> <mvc:exclude-mapping path="zzz"> <!--对path中的资源不进行拦截--> <bean class="yyyy"></bean> <!--class是对应的拦截器--> </mvc:interceptor> <mvc:interceptor> ...... </mvc:interceptor> </mvc:interceptors>
-
进行相应的测试
所以Interceptors自定义类对应的代码为:
public class MyInterceptor implements HandlerInterceptor {
/*
在对应的方法执行之前,进行拦截。如果返回值为true,那么表示
放行,这时候就可以执行下面postHandle,afterCompletion方法
否则,如果返回的是false,那么表示进行拦截,不可以执行对应的
方法,从而下面2个方法也不会执行。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle is running......");
String param = request.getParameter("param");
if("yes".equals(param)){
//如果param不为null,并且值为yes,那么就放行
return true;
}
//如果没有传递参数param,或者它的值不为yes,那么不会放行
return false;
}
//在对应的方法执行完毕之后,但是还没有开始渲染视图之前执行的
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle is running......");
}
//当所有的操作完成之后,也即视图已经渲染完成了,才执行这个方法
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion is running.....");
}
}
public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor2 preHandle is running.........");
return true;//放行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor2 postHandle is running........");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor2 afterCompletion is running........");
}
}
对应的spring-mvc.xml文件中配置拦截器的代码为:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/interceptorController/**"/>
<bean class="day6.demo.interceptors.MyInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"></mvc:mapping> <!--拦截所有的资源-->
<bean class="day6.demo.interceptors.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
对应的测试类:
@Controller
@RequestMapping("/interceptorController")
public class InterceptorController {
@RequestMapping("/test")
public ModelAndView test(ModelAndView modelAndView){
System.out.println("InterceptorController is running....");
modelAndView.addObject("name","大大怪");
modelAndView.setViewName("/index.jsp");
return modelAndView;
}
}
所以,如果输入的是localhost:8080/interceptorController/test?param=yes
的时候,2个拦截器都进行拦截同一个资源,这时候preHandle操作时根据sprng-mvc中配置的顺序来执行的是,当所有的拦截器的preHandle方法都执行之后,才可以放行去执行目标资源,当目标资源执行完毕之后,先去执行postHandle操作,但是这时候是根据拦截器配置的顺序的倒序执行的,当所有的拦截器都执行了postHandle方法之后,再根据拦截器配置的顺序的倒序执行afterCompletion方法。所以多个拦截器对同一资源进行拦截的时候,执行顺序也是如此。所以对应的结果如下所示:
Spring MVC中请求映射发生404错误
当Spring MVC请求映射发生404错误的时候,情况可能有很多种:
- controller中没有使用注解@Controller,将这个xxxController添加到Spring MVC容器中;
- 虽然已经使用了注解@Controller,但是spring-mvc.xml中没有配置
<context:component-scan base-package="xxx"/>
来扫描controller层的组件; - 有可能请求的资源路径错误了;
- 可能web.xml中配置错误
但是如果上面的配置都没有错误的情况下,那么我们需要看一下spring-mvc.xml中是否已经添加了<mvc:annotation-driven/>
,如果没有,那么尝试将这一句添加到spring-mvc.xml中,再次请求的时候,发现能够正常映射了(我的情况就是这个,😭😭😭)
但是为什么加上这个之后,就可以映射了呢?
原来,<mvc:annotation-driver/>
是Spring MVC用来提供Controller请求转发,json自动转换,配置内部资源解析器等功能的类,会默认帮我们注册处理请求,参数和返回值的类。
参考资料:springmvc 中 注解驱动:<mvc:annotation-driven>的作用和使用
Spring MVC的异常处理
利用Spring MVC中,我们可以在service.dao层通过throws来声明可能出现的异常,如果抛出了异常,那么将会有controller来通过try-catch来处理。但是我们可以利用Spring MVC来处理异常,所以并不需要我们在controller层中来try-catch异常。所以对应的异常处理步骤如下所示:
所以我们在利用Spring MVC来处理异常的时候,需要配置异常处理器HandlerExceptionResolver.而配置异常处理器可以有2种方式:
-
直接在spring-mvc.xml中配置Spring MVC中的SimpleMappingExceptionResolver(简单映射异常解析器),对应的代码为:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!--defaultErrorView的值表示发生错误时,默认跳转的页面是error.jsp--> <property name="defaultErrorView" value="error.jsp"></property> <property name="exceptionMappings"> <!--当发生的异常和下面的异常匹配的时候,那么就会跳转到value对应的界面,否则 如果不匹配时候,就会跳转到默认界面--> <map> <entry key="java.lang.ArithmeticException" value="error2.jsp"></entry> <entry key="java.lang.NumberFormatException" value="error1.jsp"></entry> <entry key="java.lang.NullPointerException" value="error3.jsp"></entry> </map> </property> </bean>
-
自定义一个类,使得这个类实现了Spring MVC中的HandlerExceptionResolver接口,并且实现它的resolveException方法,在这个方法中,根据对应的异常,从而做出相应的处理,然后将返回一个ModleAndView对象。之后再spring mvc中将这个自定义类添加到Spring MVC容器中,对应的代码为:
自定义类MyExceptionResolver代码:
public class MyHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView modelAndView = new ModelAndView(); if(e instanceof NumberFormatException){ //如果发生的是NumberFormatException异常,那么跳转到error1.jsp页面 modelAndView.setViewName("error1.jsp"); }else if(e instanceof NullPointerException){ //如果发生的是NullPointerException异常,那么跳转到error3.jsp页面 modelAndView.setViewName("error3.jsp"); }else if(e instanceof ArithmeticException){ //如果发生的是ArithmeticException异常,那么跳转到error2.jsp页面 modelAndView.setViewName("error2.jsp"); }else{ //默认跳转到error.jsp页面 modelAndView.setViewName("error.jsp"); } return modelAndView; } }
在spring-mvc.xml中配置自定义类
<bean class="day7.demo.exceptions.MyHandlerException"></bean>