springmvc笔记补充—请求转发重定向,异常处理,拦截器

请求转发和重定向



当处理器对请求处理完毕后,向其他资源跳转时,有两种跳转方式:请求转发 与 重定向 。而根据所要跳转的资源类型,又分为两类:跳转到页面与跳转到其他处理器。
注意,对于请求转发的页面,可以是 WEB-INF 中的页面;而重定向的页面,是不能为 WEB-INF中的页面。因为重定向相当于用户再次发出一次请求,而用户是不能直接访问 WEB-INF 中资源的。


在这里插入图片描述


springmvc框架把原来的servlet中的请求转发和重定向进行了封装,现在可以使用简单方式实现了。
    
forward:表示转发,实现request.getRequestDispatcher("xx.jsp").forward()
redirect:表示重定向,实现response.sendRedirect("xxx.jsp")

1、forward,请求转发

处理器方法返回 ModelAndView,实现转发 forward操作
语法:setViewName("forward:视图文件完整路径")
forward特点:不和视图解析器一同使用,就当项目中没有视图解析器

对应控制器

@Controller
public class MyController {

    @RequestMapping(value = "/doForward.do")
    public ModelAndView doSome(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","-----欢迎使用spring mvc做web开发------" );
        mv.addObject("fun","执行的是doSome方法");

        //=====================重点===========================
        
        //使用视图解析器
        //mv.setViewName("show");
        
        //显式转发
        mv.setViewName("forward:WEB-INF/view/show.jsp");
        
        //=====================重点===========================
        
        return mv;
    }
}

2、redirect 重定向

处理器方法返回ModelAndView,实现转发redirect操作
语法:setViewName("redirect:视图文件完整路径")
redirect特点:不和视图解析器一同使用,就当作项目中没有视图解析器

<br/>

框架对重定向的操作:
1、框架会把model中的简单类型的数据,转为String使用,作为hello.jsp的get请求参数使用
   目的是在 doRedirect.do 和 hello.jsp 两次请求之间传递参数
       
2、在目标hello.jsp可以使用参数集合对象 $(param) 获取请求参数值,格式为:$(param.name)
       
3、重定向不能访问WEB-INF资源

对应控制器

@RequestMapping(value = "/doRedirect.do")
public ModelAndView doWithRedirect(String name,Integer age){
    ModelAndView mv = new ModelAndView();
    //数据放入到 request 作用域
    mv.addObject("name",name);
    mv.addObject("age",age);

     //=====================重点===========================
    
    //重定向
    mv.setViewName("redirect:hello.jsp");
    //http://localhost:8080/08_forward/hello.jsp?name=zhangsan&age=11
    
     //=====================重点===========================
    
    return mv;
}

hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>show.jsp</h3><br/>
    <h3>name数据:${name}</h3>
    <h3>age数据:${age}</h3>
</body>
</html>

输入参数如下图

在这里插入图片描述


结果如下图
在这里插入图片描述


虽然网址上传递了参数,但name和age取不到参数,因为重定向是两次请求,参数在第一次请求的作用域里面,无法直接传递到第二个作用域。此时修改hello.jsp,直接访问第一次请求作用域里面的参数。


hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>show.jsp</h3><br/>
    <h3>name数据:${param.name}</h3>
    <h3>age数据:${param.age}</h3>
	
    <!--使用request对象中的getParameter方法,可以访问到第一次request作用域-->
    <h3>取参数数据:<%=request.getParameter("name")%></h3>
</body>
</html>

成功取到参数,如下图
在这里插入图片描述


异常处理


springmvc框架采用的是统一,全局的异常处理。把controller中的所有异常处理都集中到一个地方,采用的是aop思想,把业务逻辑和异常处理代码分开。也叫解耦(ou)合。
使用两个注解:1、ExceptionHandler 2、ControllerAdvice


异常处理主要步骤:
    
1	新建一个自定义异常类 MyUserException,再定义它的子类 NameException,AgeException
2	在 controller 抛出 NameException,AgeException
3	创建一个普通类,作为 全局异常处理类
		1>	类上面加上 @ControllerAdvice
		2>	类中方法上面加上 @ExceptionHandler
4	创建对应视图。创建组件扫描器扫描,扫描全局变量处理程序。创建注解驱动。

项目结构如下

在这里插入图片描述


springmvc.xml,加入组件扫描器和注解驱动

<!--处理异常两个步骤-->

<!--1、组件扫描器:扫描全局异常处理程序-->
<context:component-scan base-package="com.zh.handler"/>

<!--2、注解驱动-->
<mvc:annotation-driven/>

MyController.java,控制器方法,向 MyUserException 抛出异常

@Controller
public class MyController {

    @RequestMapping(value = "/some.do")
    public ModelAndView doSome(String name,Integer age) throws MyUserException {
        ModelAndView mv = new ModelAndView();

        //根据请求抛出异常
        if (!"zs".equals(name)){
            throw new NameException("姓名不正确");
        }

        if (age <= 0 || age >= 99){
            throw new AgeException("年龄输入有误");
        }
        
        mv.addObject("name",name);
        mv.addObject("age",age);
        mv.setViewName("show");
        return mv;
    }
}

自定义异常类 MyUserException.java,继承 Exception

public class MyUserException extends Exception{

    public MyUserException() {
        super();
    }
    public MyUserException(String message) {
        super(message);
    }
}

子类 NameException.java

//表示当前用户姓名有异常,抛出NameException
public class NameException extends MyUserException {

    public NameException() {
        super();
    }
    public NameException(String message) {
        super(message);
    }
}

下面创建一个GlobalExceptionHandler.java,作为 全局异常处理类


1、@ControllerAdvice

控制器增强 (可以理解为:增加控制器功能),放在类上面
    
特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明 组件扫描器
指定 @ControllerAdvice 所在的全局异常处理类包名

2、@ExceptionHandler

@ExceptionHandler(异常的class):表示异常的类型,当发生此类型的异常时,由当前方法处理。放在方法上面

处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有ModelAndView,String,void,对象类型的返回值
形参:Exception,表示Controller中抛出的异常对象,通过形参可以获取发送的异常信息

GlobalExceptionHandler.java

//@ControllerAdvice 增强控制器
@ControllerAdvice
public class GlobalExceptionHandler {
	
    //处理NameException异常
    @ExceptionHandler(value = NameException.class)
    public ModelAndView doNameException(Exception exception){

        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","用户名必须是zs,其他用户不能访问");
        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","年龄输入范围有误");
        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.setViewName("defaultError");
        return mv;
    }
}

检测姓名异常
在这里插入图片描述


结果如下
在这里插入图片描述


检测未知异常
在这里插入图片描述


结果如下
在这里插入图片描述


拦截器


拦截器说明:

1	拦截器是springmvc中的一种,需要实现HandlerInterceptor接口
2	拦截器和过滤器类似,功能方向侧重点不同。过滤器是用来过滤请求参数,设置编码字符集等。
	拦截器是拦截用户的请求,可以对多个Controller做拦截。
3	拦截器是全局的,可以对多个Controller做拦截。
	一个项目中可以有0个或多个拦截器,他们在一起拦截用户的请求。
	拦截器常用在:用户登录处理,权限检查,记录日志。

拦截器的使用步骤:

1	定义普通类实现HandlerInterceptor接口,实现接口的三个方法
2	在springmvc文件中,声明拦截器,指定拦截请求的uri地址

拦截器的执行时间:

1	在请求处理之前,也就是controller类中方法执行之前先被拦截
2	在控制器方法执行之后也会执行拦截器
3	在请求处理完成后也会执行拦截器

在主配置文件sprinmvc.xml中,声明拦截器

<!--声明拦截器:拦截器可以有0个或者多个-->
<mvc:interceptors>

    <!--声明一个拦截器-->
    <mvc:interceptor>
        <!--
        指定拦截请求的uri地址
            path:就是uri地址,可以使用通配符 **
              **:表示任意字符,文件或者多级目录中的文件
        -->
        <mvc:mapping path="/**"/>
        <!--声明拦截器对象-->
        <bean class="com.zh.handler.MyInterceptor"/>
    </mvc:interceptor>
    
</mvc:interceptors>

创建一个MyInterceptor.java,作为拦截器类,继承自HandlerInterceptor,实现三个方法:preHandle,postHandle,afterCompletion


在这里插入图片描述


preHandle:预处理方法(重要)

预处理方法: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),
     如果验证失败,可以截断请求;如果验证成功,可以放行请求,此时控制器方法才能执行


MyInterceptor.java

//拦截器类:看作是多个控制器中公用的功能,集中到拦截器统一处理,使用的是aop思想(面向切面编程)。
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor拦截器的preHandle()方法执行了!");
        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 mv) throws Exception {
        System.out.println("MyInterceptor拦截器的postHandle()方法执行了!");
    }

   /*
    * 最后执行方法: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()方法执行了!");
    }
}

多个拦截器时

在框架中保存多个拦截器是ArrayList,
按照声明的先后顺序放入ArrayList

在这里插入图片描述


第一个拦截器preHandle=true,第二个拦截器preHandle=true


第一个拦截器类

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("11111--MyInterceptor拦截器的preHandle()方法执行了!");
        return true;
    }
        @Override
    public void postHandle(......){
         System.out.println("11111--MyInterceptor拦截器的postHandle()方法执行了!");
    }
        .....

第二个拦截器类

public class MyInterceptor2 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("22222--MyInterceptor拦截器的preHandle()方法执行了!");
        return true;
    }
        @Override
    public void postHandle(......){
         System.out.println("22222--MyInterceptor拦截器的postHandle()方法执行了!");
    }
        .....

配置文件中也要同时声明两个拦截器

    <mvc:interceptors>

        <!--声明一个拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.zh.handler.MyInterceptor"/>
        </mvc:interceptor>
        
        <!--声明第二个拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.zh.handler.MyInterceptor2"/>
        </mvc:interceptor>

    </mvc:interceptors>


运行结果如下

11111--MyInterceptor拦截器的preHandle()方法执行了!
22222--MyInterceptor拦截器的preHandle()方法执行了!
MyController控制器的doSome()方法执行!
22222--MyInterceptor拦截器的postHandle()方法执行了!
11111--MyInterceptor拦截器的postHandle()方法执行了!
22222--MyInterceptor拦截器的afterCompletion()方法执行了!
11111--MyInterceptor拦截器的afterCompletion()方法执行了!

第一个拦截器preHandle=true,第二个拦截器preHandle=false

执行结果为

11111--MyInterceptor拦截器的preHandle()方法执行了!
22222--MyInterceptor拦截器的preHandle()方法执行了!
11111--MyInterceptor拦截器的afterCompletion()方法执行了!

第一个拦截器preHandle=false,第二个拦截器preHandle=true

11111--MyInterceptor拦截器的preHandle()方法执行了!

拦截器和过滤器的区别,了解


1	过滤器是servlet中的对象,拦截器是框架中的对象
2	过滤器实现Filter接口,拦截器实现HandlerInterceptor
3	过滤器是用来设置request,response的参数,属性,侧重对数据过滤的
	拦截器用来验证请求,能截断请求
	
4	过滤器是在拦截器之前先执行
5	过滤器是tomcat服务器创建的对象
	拦截器是springmvc容器中创建的对象

6	过滤器是一个执行时间点
	拦截器是三个执行时间点

7	过滤器可以处理jsp,js,html等
	拦截器是侧重拦截对Controller的对象。如果你的请求不能被DispatcherServlet接收,这个请求	不会执行拦截器内容
	
8	拦截器拦截普通类方法执行,过滤器过滤servlet请求响应

springmvc更详细笔记:

https://blog.csdn.net/weixin_40350981/article/details/109645897

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页