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

Posted MinggeQingchun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java--请求转发;重定向;异常处理;拦截器相关的知识,希望对你有一定的参考价值。

一、请求转发

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

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

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 注解修饰的,可以<context:component-scan>

扫描到 @ControllerAdvice 所在的类路径 ( 包名 ) ,创建对象
/**
 * @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配置文件中,注册多个拦截器

<!--声明拦截器: 拦截器可以有0或多个
        在框架中保存多个拦截器是ArrayList,
        按照声明的先后顺序放入到ArrayList
    -->
    <mvc:interceptors>
        <!--声明第一个拦截器-->
        <mvc:interceptor>
            <!-- 指定拦截器的URI地址
                path:URI地址,可以使用通配符 ** ( 表示任意的字符,文件或者多级目录和目录中的文件)

            -->
            <mvc:mapping path="/**"/>
            <!-- 声明拦截器对象 -->
            <bean class="com.mycompany.handler.MyInterceptor" />
        </mvc:interceptor>
        <mvc:interceptor>
            <!-- 指定拦截器的URI地址
                path:URI地址,可以使用通配符 ** ( 表示任意的字符,文件或者多级目录和目录中的文件)

            -->
            <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()
     */

以上是关于Java--请求转发;重定向;异常处理;拦截器的主要内容,如果未能解决你的问题,请参考以下文章

转发和重定向的区别和过滤器和拦截器的区别

java重定向时如何保持地址栏不变

django中web页面的跳转方式

关于请求转发重定向url重写

java手记------------------------java中转发和重定向区别

SpringMVC总结