当处理器对请求处理完毕后,向其它资源进行跳转时,有两种跳转方式:
请求转发与重定向,两者区别如下:

forward:表示转发,实现 request.getRequestDispatcher("xx.jsp").forward()
- /**
- * 处理器方法返回ModelAndView,实现转发forward
- * 语法:setViewName("forward:视图文件完整路径")
- * forward:不和视图解析器一同使用(忽略视图解析器)
- */
- @RequestMapping("/doForward")
- public ModelAndView doForward(){
- ModelAndView mdv = new ModelAndView();
-
- ModelAndView mv = new ModelAndView();
- mv.addObject("msg","欢迎使用SpringMVC做web开发");
- mv.addObject("fun","执行的是doForward方法");
-
- //显示转发
- //mdv.setViewName("forward:WEB-INF/jsp/show.jsp");
- mdv.setViewName("forward:hello.jsp");
-
- return mdv;
- }
redirect:表示重定向,实现 response.sendRedirect("xx.jsp")
- /**
- * 处理器方法返回ModelAndView,实现重定向redirect
- * 语法:setViewName("redirect:视图完整路径")
- * redirect:不和视图解析器一同使用(忽略视图解析器)
- *
- * SpringMVC框架对重定向操作:
- * 1、SpringMVC框架把Model中的简单类型数据转为string使用,作为hello.jsp的get请求参数使用
- * 在doRedirect 和 hello.jsp 两次请求之间传递数据
- * 2、在目标hello.jsp页面可以使用参数集合对象 ${param}获取请求参数值${param.myname}
- *
- * 注:重定向不能访问 /WEB-INF资源
- */
- @RequestMapping("doRedirect")
- public ModelAndView doRedirect(String name,Integer age){
- ModelAndView mv = new ModelAndView();
- //数据放入到 request作用域
- mv.addObject("myname",name);
- mv.addObject("myage",age);
-
- //重定向
- //http://localhost:8081/springmvc_8_forward_redirect/hello.jsp?myname=%E6%9D%8E%E5%9B%9B&myage=18
- mv.setViewName("redirect:hello.jsp");
-
- /**
- * 重定向不能访问 /WEB-INF资源
- * HTTP状态 404 - 未找到
- * http://localhost:8081/springmvc_8_forward_redirect/WEB-INF/jsp/show.jsp?myname=%E6%9D%8E%E5%9B%9B&myage=18
- * */
- // mv.setViewName("redirect:WEB-INF/jsp/show.jsp");
-
- return mv;
- }
将异常处理方法专门定义在一个类中,作为全局的异常处理类
需要使用注解@ControllerAdvice(控制器增强),是给控制器对象增强功能的。
使用@ControllerAdvice 修饰的类中可以使用@ExceptionHandler。
当使用@RequestMapping 注解修饰的方法抛出异常时,会执行@ControllerAdvice 修饰的类中的异常处理方法
@ControllerAdvice 是使用@Component 注解修饰的,可以
- /**
- * @ControllerAdvice : 控制器增强(给控制器类增加功能--异常处理功能)
- * 位置:类上面
- * 特点:在SpringMvc配置文件声明组件扫描器,指定@ControllerAdvice所在的包名
- */
- @ControllerAdvice
- public class GlobalExceptionHandler {
- /**
- * 处理异常方法和控制器方法定义一样,可以有多个参数,可以有ModelAndView,String, void,对象类型的返回值
- *
- * 形参:Exception,表示Controller中抛出的异常对象。
- * 通过形参可以获取发生的异常信息。
- *
- * @ExceptionHandler (异常的class) : 表示异常的类型,当发生此类型异常时,
- * 由当前方法处理
- * */
- @ExceptionHandler(value = NameException.class)
- public ModelAndView doNameExcepton(Exception exception){
- /*
- 异常发生处理逻辑
- 1、需要把异常记录下来,记录到数据库,日志文件
- 记录法身时间,那个类、方法发生的,异常发生内容
- 2、发送通知,将异常信息通过邮件,短信发送给开发人员
- 3、给用户友好提示
- * */
- ModelAndView mv = new ModelAndView();
- mv.addObject("msg","用户名必须是admin,其它用户不能访问");
- mv.addObject("ex",exception);
- mv.setViewName("nameError");
- return mv;
- }
-
- //处理AgeException
- @ExceptionHandler(value = AgeException.class)
- public ModelAndView doAgeException(Exception exception){
- ModelAndView mv = new ModelAndView();
- mv.addObject("msg","年龄不能大于120");
- mv.addObject("ex",exception);
- mv.setViewName("ageError");
- return mv;
- }
-
- //处理其它异常, NameException, AgeException以外,不知类型的异常
- @ExceptionHandler
- public ModelAndView doOtherException(Exception exception){
- //处理其它异常
- ModelAndView mv = new ModelAndView();
- mv.addObject("msg","其它异常");
- mv.addObject("ex",exception);
- mv.setViewName("defaultError");
- return mv;
- }
- }
自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中有三个方法
- 该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方
- 法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行
- preHandle(request,response, Object handler):
-
-
- 该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。
- 由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修
- 改处理器方法的处理结果数据,且可以修改跳转方向。
- postHandle(request,response, Object handler,modelAndView):
-
- 当 preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有
- 工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的
- afterCompletion(request,response, Object handler, Exception ex):
拦截器中方法与处理器方法的执行顺序如下图

- /**
- * 拦截器类:拦截用户请求
- */
- public class MyInterceptor implements HandlerInterceptor {
- private long beginTime = 0;
-
- /**
- * preHandle():预处理方法
- * 整个项目入口;
- * 当preHandle返回true 请求可以被处理;preHandle返回false,请求到此方法就截止。
- *
- * 参数
- * Object handler:被拦截的控制器对象
- * 返回值 boolean
- * true:请求通过了拦截器的验证,可以执行处理器方法
- * 拦截器MyInterceptor的preHandle()
- * =====执行MyController中的doSome方法=====
- * 拦截器MyInterceptor的postHandle()
- * 拦截器MyInterceptor的afterCompletion()
- * false:请求没有通过拦截器的验证,请求到达拦截器就截止
- * 拦截器MyInterceptor的preHandle()
- *
- * 特点:
- * 1、方法在控制器方法(MyController的doSome)之前先执行
- * 2、在这个方法中可以获取请求的信息,验证请求是否符合要求
- * 可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)
- * 如果验证失败,截断请求,请求不能被处理
- * 如果验证成功,放行请求,此时控制器方法才能执行
- */
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- beginTime = System.currentTimeMillis();
- System.out.println("拦截器MyInterceptor的preHandle()");
- //计算的业务逻辑,根据计算结果,返回true或者false
- //给浏览器一个返回结果
- //request.getRequestDispatcher("/tips.jsp").forward(request,response);
- return true;
- }
-
- /**
- * postHandle()方法:后处理方法
- * 参数:
- * Object handler:被拦截的处理器对象MyController
- * ModelAndView mv:处理器方法的返回值
- * 特点:
- * 1、在处理器方法之后执行的(MyController.doSome())
- * 2、能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的
- * 数据和视图,可以影响到最后的执行结果。
- * 3、主要是对原来的执行结果进行二次修改
- */
- @Override
- public void postHandle(HttpServletRequest request,
- HttpServletResponse response,
- Object handler,
- ModelAndView modelAndView) throws Exception {
- System.out.println("拦截器MyInterceptor的postHandle()");
- //对原来的doSome执行结果,需要调整。
- if( modelAndView != null){
- //修改数据
- modelAndView.addObject("mydate",new Date());
- //修改视图
- modelAndView.setViewName("other");
- }
- }
-
- /**
- * afterCompletion()方法:最后执行的方法
- * 参数
- * Object handler:被拦截器的处理器对象
- * Exception ex:程序中发生的异常
- * 特点:
- * 1、在请求处理完成后执行的。框架中规定是当视图处理完成后,对视图执行了forward。就认为请求处理完成
- * 2、一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收
- */
- @Override
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
- System.out.println("拦截器MyInterceptor的afterCompletion()");
-
- long endTime = System.currentTimeMillis();
- System.out.println("从preHandle到请求处理完成的时间:"+(endTime - beginTime));
- }
- }
在SpringMVC配置文件中,注册多个拦截器
- <mvc:interceptors>
-
- <mvc:interceptor>
-
- <mvc:mapping path="/**"/>
-
- <bean class="com.mycompany.handler.MyInterceptor" />
- mvc:interceptor>
- <mvc:interceptor>
-
- <mvc:mapping path="/**"/>
-
- <bean class="com.mycompany.handler.MyInterceptor2" />
- mvc:interceptor>
- mvc:interceptors>
执行顺序

输出如下:
- /**
- * 1、第一个拦截器preHandle=true , 第二个拦截器preHandle=true
- * 111111拦截器MyInterceptor的preHandle()
- * 222222拦截器MyInterceptor的preHandle()
- * =====执行MyController中的doSome方法=====
- * 222222拦截器MyInterceptor的postHandle()
- * 111111拦截器MyInterceptor的postHandle()
- * 222222拦截器MyInterceptor的afterCompletion()
- * 111111拦截器MyInterceptor的afterCompletion()
- *
- * 2、第一个拦截器preHandle=true , 第二个拦截器preHandle=false
- * 111111拦截器MyInterceptor的preHandle()
- * 222222拦截器MyInterceptor的preHandle()
- * 111111拦截器MyInterceptor的afterCompletion()
- *
- * 3、第一个拦截器preHandle=false , 第二个拦截器preHandle=true|false
- * 111111拦截器MyInterceptor的preHandle()
- */