• Java--请求转发;重定向;异常处理;拦截器


    一、请求转发

    当处理器对请求处理完毕后,向其它资源进行跳转时,有两种跳转方式:

    请求转发与重定向,两者区别如下:

    forward:表示转发,实现 request.getRequestDispatcher("xx.jsp").forward()

    1. /**
    2. * 处理器方法返回ModelAndView,实现转发forward
    3. * 语法:setViewName("forward:视图文件完整路径")
    4. * forward:不和视图解析器一同使用(忽略视图解析器)
    5. */
    6. @RequestMapping("/doForward")
    7. public ModelAndView doForward(){
    8. ModelAndView mdv = new ModelAndView();
    9. ModelAndView mv = new ModelAndView();
    10. mv.addObject("msg","欢迎使用SpringMVC做web开发");
    11. mv.addObject("fun","执行的是doForward方法");
    12. //显示转发
    13. //mdv.setViewName("forward:WEB-INF/jsp/show.jsp");
    14. mdv.setViewName("forward:hello.jsp");
    15. return mdv;
    16. }

    二、请求重定向

    redirect:表示重定向,实现 response.sendRedirect("xx.jsp")

    1. /**
    2. * 处理器方法返回ModelAndView,实现重定向redirect
    3. * 语法:setViewName("redirect:视图完整路径")
    4. * redirect:不和视图解析器一同使用(忽略视图解析器)
    5. *
    6. * SpringMVC框架对重定向操作:
    7. * 1、SpringMVC框架把Model中的简单类型数据转为string使用,作为hello.jsp的get请求参数使用
    8. * 在doRedirect 和 hello.jsp 两次请求之间传递数据
    9. * 2、在目标hello.jsp页面可以使用参数集合对象 ${param}获取请求参数值${param.myname}
    10. *
    11. * 注:重定向不能访问 /WEB-INF资源
    12. */
    13. @RequestMapping("doRedirect")
    14. public ModelAndView doRedirect(String name,Integer age){
    15. ModelAndView mv = new ModelAndView();
    16. //数据放入到 request作用域
    17. mv.addObject("myname",name);
    18. mv.addObject("myage",age);
    19. //重定向
    20. //http://localhost:8081/springmvc_8_forward_redirect/hello.jsp?myname=%E6%9D%8E%E5%9B%9B&myage=18
    21. mv.setViewName("redirect:hello.jsp");
    22. /**
    23. * 重定向不能访问 /WEB-INF资源
    24. * HTTP状态 404 - 未找到
    25. * http://localhost:8081/springmvc_8_forward_redirect/WEB-INF/jsp/show.jsp?myname=%E6%9D%8E%E5%9B%9B&myage=18
    26. * */
    27. // mv.setViewName("redirect:WEB-INF/jsp/show.jsp");
    28. return mv;
    29. }

    三、异常处理

    将异常处理方法专门定义在一个类中,作为全局的异常处理类

    需要使用注解@ControllerAdvice(控制器增强),是给控制器对象增强功能的。

    使用@ControllerAdvice 修饰的类中可以使用@ExceptionHandler

    当使用@RequestMapping 注解修饰的方法抛出异常时,会执行@ControllerAdvice 修饰的类中的异常处理方法

    @ControllerAdvice 是使用@Component 注解修饰的,可以

    扫描到 @ControllerAdvice 所在的类路径 ( 包名 ) ,创建对象
    1. /**
    2. * @ControllerAdvice : 控制器增强(给控制器类增加功能--异常处理功能)
    3. * 位置:类上面
    4. * 特点:在SpringMvc配置文件声明组件扫描器,指定@ControllerAdvice所在的包名
    5. */
    6. @ControllerAdvice
    7. public class GlobalExceptionHandler {
    8. /**
    9. * 处理异常方法和控制器方法定义一样,可以有多个参数,可以有ModelAndView,String, void,对象类型的返回值
    10. *
    11. * 形参:Exception,表示Controller中抛出的异常对象。
    12. * 通过形参可以获取发生的异常信息。
    13. *
    14. * @ExceptionHandler (异常的class) : 表示异常的类型,当发生此类型异常时,
    15. * 由当前方法处理
    16. * */
    17. @ExceptionHandler(value = NameException.class)
    18. public ModelAndView doNameExcepton(Exception exception){
    19. /*
    20. 异常发生处理逻辑
    21. 1、需要把异常记录下来,记录到数据库,日志文件
    22. 记录法身时间,那个类、方法发生的,异常发生内容
    23. 2、发送通知,将异常信息通过邮件,短信发送给开发人员
    24. 3、给用户友好提示
    25. * */
    26. ModelAndView mv = new ModelAndView();
    27. mv.addObject("msg","用户名必须是admin,其它用户不能访问");
    28. mv.addObject("ex",exception);
    29. mv.setViewName("nameError");
    30. return mv;
    31. }
    32. //处理AgeException
    33. @ExceptionHandler(value = AgeException.class)
    34. public ModelAndView doAgeException(Exception exception){
    35. ModelAndView mv = new ModelAndView();
    36. mv.addObject("msg","年龄不能大于120");
    37. mv.addObject("ex",exception);
    38. mv.setViewName("ageError");
    39. return mv;
    40. }
    41. //处理其它异常, NameException, AgeException以外,不知类型的异常
    42. @ExceptionHandler
    43. public ModelAndView doOtherException(Exception exception){
    44. //处理其它异常
    45. ModelAndView mv = new ModelAndView();
    46. mv.addObject("msg","其它异常");
    47. mv.addObject("ex",exception);
    48. mv.setViewName("defaultError");
    49. return mv;
    50. }
    51. }

    四、拦截器

    自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中有三个方法

    1. 该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方
    2. 法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行
    3. preHandle(request,response, Object handler):
    4. 该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。
    5. 由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修
    6. 改处理器方法的处理结果数据,且可以修改跳转方向。
    7. postHandle(request,response, Object handler,modelAndView):
    8. 当 preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有
    9. 工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的
    10. afterCompletion(request,response, Object handler, Exception ex):

    拦截器中方法与处理器方法的执行顺序如下图

    1. /**
    2. * 拦截器类:拦截用户请求
    3. */
    4. public class MyInterceptor implements HandlerInterceptor {
    5. private long beginTime = 0;
    6. /**
    7. * preHandle():预处理方法
    8. * 整个项目入口;
    9. * 当preHandle返回true 请求可以被处理;preHandle返回false,请求到此方法就截止。
    10. *
    11. * 参数
    12. * Object handler:被拦截的控制器对象
    13. * 返回值 boolean
    14. * true:请求通过了拦截器的验证,可以执行处理器方法
    15. * 拦截器MyInterceptor的preHandle()
    16. * =====执行MyController中的doSome方法=====
    17. * 拦截器MyInterceptor的postHandle()
    18. * 拦截器MyInterceptor的afterCompletion()
    19. * false:请求没有通过拦截器的验证,请求到达拦截器就截止
    20. * 拦截器MyInterceptor的preHandle()
    21. *
    22. * 特点:
    23. * 1、方法在控制器方法(MyController的doSome)之前先执行
    24. * 2、在这个方法中可以获取请求的信息,验证请求是否符合要求
    25. * 可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)
    26. * 如果验证失败,截断请求,请求不能被处理
    27. * 如果验证成功,放行请求,此时控制器方法才能执行
    28. */
    29. @Override
    30. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    31. beginTime = System.currentTimeMillis();
    32. System.out.println("拦截器MyInterceptor的preHandle()");
    33. //计算的业务逻辑,根据计算结果,返回true或者false
    34. //给浏览器一个返回结果
    35. //request.getRequestDispatcher("/tips.jsp").forward(request,response);
    36. return true;
    37. }
    38. /**
    39. * postHandle()方法:后处理方法
    40. * 参数:
    41. * Object handler:被拦截的处理器对象MyController
    42. * ModelAndView mv:处理器方法的返回值
    43. * 特点:
    44. * 1、在处理器方法之后执行的(MyController.doSome())
    45. * 2、能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的
    46. * 数据和视图,可以影响到最后的执行结果。
    47. * 3、主要是对原来的执行结果进行二次修改
    48. */
    49. @Override
    50. public void postHandle(HttpServletRequest request,
    51. HttpServletResponse response,
    52. Object handler,
    53. ModelAndView modelAndView) throws Exception {
    54. System.out.println("拦截器MyInterceptor的postHandle()");
    55. //对原来的doSome执行结果,需要调整。
    56. if( modelAndView != null){
    57. //修改数据
    58. modelAndView.addObject("mydate",new Date());
    59. //修改视图
    60. modelAndView.setViewName("other");
    61. }
    62. }
    63. /**
    64. * afterCompletion()方法:最后执行的方法
    65. * 参数
    66. * Object handler:被拦截器的处理器对象
    67. * Exception ex:程序中发生的异常
    68. * 特点:
    69. * 1、在请求处理完成后执行的。框架中规定是当视图处理完成后,对视图执行了forward。就认为请求处理完成
    70. * 2、一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收
    71. */
    72. @Override
    73. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    74. System.out.println("拦截器MyInterceptor的afterCompletion()");
    75. long endTime = System.currentTimeMillis();
    76. System.out.println("从preHandle到请求处理完成的时间:"+(endTime - beginTime));
    77. }
    78. }

    在SpringMVC配置文件中,注册多个拦截器

    1. <mvc:interceptors>
    2. <mvc:interceptor>
    3. <mvc:mapping path="/**"/>
    4. <bean class="com.mycompany.handler.MyInterceptor" />
    5. mvc:interceptor>
    6. <mvc:interceptor>
    7. <mvc:mapping path="/**"/>
    8. <bean class="com.mycompany.handler.MyInterceptor2" />
    9. mvc:interceptor>
    10. mvc:interceptors>

    执行顺序

     输出如下:

    1. /**
    2. * 1、第一个拦截器preHandle=true , 第二个拦截器preHandle=true
    3. * 111111拦截器MyInterceptor的preHandle()
    4. * 222222拦截器MyInterceptor的preHandle()
    5. * =====执行MyController中的doSome方法=====
    6. * 222222拦截器MyInterceptor的postHandle()
    7. * 111111拦截器MyInterceptor的postHandle()
    8. * 222222拦截器MyInterceptor的afterCompletion()
    9. * 111111拦截器MyInterceptor的afterCompletion()
    10. *
    11. * 2、第一个拦截器preHandle=true , 第二个拦截器preHandle=false
    12. * 111111拦截器MyInterceptor的preHandle()
    13. * 222222拦截器MyInterceptor的preHandle()
    14. * 111111拦截器MyInterceptor的afterCompletion()
    15. *
    16. * 3、第一个拦截器preHandle=false , 第二个拦截器preHandle=true|false
    17. * 111111拦截器MyInterceptor的preHandle()
    18. */
  • 相关阅读:
    Qt 输入组控件(Input Widgets)& 显示组控件(Display Widgets)详解
    第8章 丰富你的程序——运用手机多媒体
    知名插画师走尺,带你走进“薪”世界
    lua # 获取table数组长度
    MyBatis的高级映射
    SpringBoot——关于Controller的简单使用
    数据挖掘实战应用案例精讲-【概念篇】数据仓库(附实战应用案例)
    Java架构师系统架构设计原则
    【Git-2022总结】分布式代码版本控制工具【GitHub/Gitee/GitLab】
    12c向19c迁移:使用数据泵(impdp)+dblink做全量迁移
  • 原文地址:https://blog.csdn.net/MinggeQingchun/article/details/123781995