SpringMVC-4-请求转发和请求重定向和拦截器和过滤器

目录

SpringMVC的核心技术

1、请求转发和请求重定向

1.1 请求转发的实例

1.1.1 项目结构:从ssm-web项目中修改而来

1.1.2 处理器:StudentController.doForward()

1.1.3 没转发之前的主视图:index.jsp

1.1.4 请求转发到的视图解析器范围之外的新视图:hello.jsp

1.1.5 请求转发到的视图解析器范围之内的新视图:show.jsp

1.1.6 SpringMVC的配置文件中配置了视图解析器:springmvc.xml

1.1.7 转发测试

1.2 请求重定向的实例

1.2.1 处理器:StudentController.doRedirect()

1.2.2 没重定向之前的主视图:index.jsp

1.2.3 请求重定向到的新视图:helloRedirect.jsp

1.2.4 重定向的测试

2、异常处理

2.1 定义一个后端业务处理器: StudentController.java(可能抛出Name/AgeException等)

2.2 新建一个自定义的全局异常类:MyUserException.java

2.3 定义全局异常类的子类用来处理姓名异常: NameException.java

2.4 定义全局异常类的子类用来处理年龄异常: AgeException.java

2.5 定义一个普通类用作全局异常处理类(处理姓名/年龄异常): GlobalExceptionHandler.java

2.6 定义一个姓名异常的视图: nameError.jsp

2.7 定义一个年龄异常的视图: ageError.jsp

2.8 定义一个其他的未知异常的视图: defaultError.jsp

2.9 定义一个前端页面的主视图: index.jsp

2.10 定义一个StudentController处理器处理业务成功后跳转到的数据展示视图: show.jsp

2.11 在spriingmvc.xml文件中声名GlobalExceptionHandler处理器的扫描

2.12 业务成功的测试

2.13 姓名异常测试

2.14 年龄异常测试

2.15 其他未知的异常测试

2.16 项目结构图

3、拦截器

3.1 定义一个拦截器:步骤如下

3.1.1 引入依赖 pom.xml

3.1.2 编写springmvc.xml

3.1.3 编写spring.xml

3.1.4 编写mybatis.xml

3.1.5 编写db.properties

3.1.6 编写控制器:StudentController

3.1.7 编写拦截器MyInterceptor(需要 implement HandlerInterceptor)

3.1.8 编写前端主页面:index.jsp

3.1.9 编写处理器StudentController处理完成后转发到的页面:show.jsp

3.1.10 编写拦截器返回false时拦截器内部转发到的友好页面:tips.jsp

3.1.11 测试preHandler()方法:预处理方法

(1)preHandler返回true时:

(2)preHandler返回false时:

3.1.12 测试postHandler()方法:后处理方法

(1)首先preHandler()需要返回true

(2)在postHandler()方法中对处理器返回的结果做二次修正

(3)将修正后的结果在转发的新的视图中展示出来:postHandlerJsp.jsp

(4)测试postHandler()方法

3.1.13 测试afterCompletion()方法:最后执行的方法

(1)afterCompletion():

(2)测试结果:

3.1.14 经过preHandler/postHandler/afterCompletion之后的项目结构图

3.2 在项目中声名多个拦截器时

3.2.1 声名拦截器1的类

3.2.2 声名拦截器2的类

3.2.3 在springmvc.xml文件中配置多个拦截器

3.2.4 当项目中存在多个拦截器时, 拦截器的执行流程图和执行顺序

3.3 过滤器和拦截器之间的区别与联系

SpringMVC的核心技术

1、请求转发和请求重定向

当处理器对请求处理完毕后,向其它资源进行跳转时,有两种跳转方式: 请求转发与重定向。而根据所要跳转的资源类型,又可分为两类:跳转到页面与跳转到其它处理器。

注意:对于请求转发的页面,可以是 WEB-INF 中页面。而重定向的页面, 是不能为 WEB-INF 中页的。因为重定向相当于用户再次发出一次请求,而用户是不能直接访问 WEB-INF 中资源的。

SpringMVC框架把原来 Servlet 中的请求转发和重定向操作进行了封装。 现在可以使用简单的方式实现转发和重定向。

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

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

1.1 请求转发的实例

处理器方法返回 ModelAndView 时,需在 setViewName()指定的视图前添加 forward: ,而且此时的视图不再与视图解析器一同工作,这样可以在即使配置了视图解析器时也可以指定到不同位置的视图。视图页面必须写出相对于项目根的路径。注:forward 操作不需要视图解析器。处理器方法返回 String,在视图路径前面加入 forward: 视图完整路径。

1.1.1 项目结构:从ssm-web项目中修改而来

ssm-web完整项目见https://blog.csdn.net/cmm0401/article/details/112065678

1.1.2 处理器:StudentController.doForward()

package com.wind.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;


@Controller
public class StudentController {

    /**
     * 处理器方法返回ModelAndView,实现转发【forward】。
     * 语法:modelAndView.setViewName("forward:视图文件的完整路径名");
     * forward的特点:forward不和项目中的视图解析器不同工作的,就当做项目中没有视图解析器,
     * 也即可以转发到视图解析器之外的视图中去。
     */
    @RequestMapping(value = "doForward.do", method = RequestMethod.POST)
    public ModelAndView doForward() {
        //创建一个视图
        ModelAndView modelAndView = new ModelAndView();
        //添加数据
        modelAndView.addObject("msg", "实现请求的转发功能");
        modelAndView.addObject("fun", "doForward方法执行了");
        //添加视图
        /**
         * 方式1:隐式转发
         * modelAndView.setViewName("show");
         */
        /**
         * 方式2:显示转发
         * modelAndView.setViewName("forward:/WEB-INF/jsp/show.jsp");
         */
        /**
         * 方式2:显示转发,这个是转发到非jsp目录下的页面中去,第1种方式就不支持了
         */
        modelAndView.setViewName("forward:/hello.jsp");
        return modelAndView;
    }
}

1.1.3 没转发之前的主视图:index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<%
    String basePath = request.getScheme()
            + "://" + request.getServerName()
            + ":" + request.getServerPort()
            + request.getContextPath() + "/";
%>
<head>
    <title>Title</title>
    <base href="<%=basePath%>"/>
</head>

<body>
<p>当你的方法返回ModelAndView的时候实现转发forward</p>
<form action="doForward.do" method="post">
    姓名:<input type="text" name="name"><br/>
    年龄:<input type="text" name="age"><br/>
    <input type="submit" value="提交请求">
</form>
</body>
</html>

1.1.4 请求转发到的视图解析器范围之外的新视图:hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>/hello.jsp 从request作用域中取出数据</h3>
<h3>msg数据是:${msg}</h3>
<h3>fun数据是:${fun}</h3>
</body>
</html>

1.1.5 请求转发到的视图解析器范围之内的新视图:show.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>/WEB-INF/view/show.jsp 从request作用域中取出数据</h3>
<h3>msg数据是:${msg}</h3>
<h3>fun数据是:${fun}</h3>
</body>
</html>

1.1.6 SpringMVC的配置文件中配置了视图解析器:springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--SpringMVC的配置文件,用来声名Controller和其他web相关的对象-->

    <!--配置组件扫描器-->
    <context:component-scan base-package="com.wind.controller"/>

    <!--视图解析器:添加前缀和后缀。
    SpringMVC框架为了避免对于请求资源路径与扩展名上的冗余,在视图解析器 InternalResouceViewResolver
    中引入了请求的前辍与后辍。而 ModelAndView 中只需给出要跳转页面的文件名即可,对于具体的文件路径与文件扩展名,
    视图解析器会自动完成拼接。-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--视图文件的路径-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--视图文件的扩展名-->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--注册注解驱动。
    (1)响应ajax请求,返回json字符串。
    (2)解决静态资源访问问题。-->
    <mvc:annotation-driven/>

    <!--加载静态资源图片啊,jQuery文件啊等等-->
    <mvc:resources location="js/" mapping="/js/**"/>
    <mvc:resources location="images/" mapping="/images/**"/>

</beans>

1.1.7 转发测试

1.2 请求重定向的实例

1.2.1 处理器:StudentController.doRedirect()

package com.wind.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;


@Controller
public class StudentController {

    /**
     * 处理器方法返回ModelAndView,实现转发【forward】。
     * 语法:modelAndView.setViewName("forward:视图文件的完整路径名");
     * forward的特点:forward不和项目中的视图解析器不同工作的,就当做项目中没有视图解析器,
     * 也即可以转发到视图解析器之外的视图中去。
     */
    @RequestMapping(value = "doForward.do", method = RequestMethod.POST)
    public ModelAndView doForward() {
        //创建一个视图
        ModelAndView modelAndView = new ModelAndView();
        //添加数据
        modelAndView.addObject("msg", "实现请求的转发功能");
        modelAndView.addObject("fun", "doForward方法执行了");
        //添加视图
        /**
         * 方式1:隐式转发
         * modelAndView.setViewName("show");
         */
        /**
         * 方式2:显示转发
         * modelAndView.setViewName("forward:/WEB-INF/jsp/show.jsp");
         */
        /**
         * 方式2:显示转发,这个是转发到非jsp目录下的页面中去,第1种方式就不支持了
         */
        modelAndView.setViewName("forward:/hello.jsp");
        return modelAndView;
    }


    /**
     * 处理器方法返回ModelAndView,实现重定向【redirect】。
     * 语法:modelAndView.setViewName("redirect:视图文件的完整路径名");
     * redirect的特点:redirect不和项目中的视图解析器不同工作的,就当做项目中没有视图解析器,
     * <p>
     * 框架对重定向做的操作:
     * 框架会把Model中的简单的数据类型转化为String类型,并把它们作为helloRedirect.jsp的GET请求参数传递过去,
     * 目的是在doDirect.do和helloRedirect.jsp之间传递数据。
     * <p>
     * 所以需要在试图中使用:${param.myage} 或者 ${param} 即可,同时,重定向不同访问/WEB-INF项目下资源。
     */
    @RequestMapping(value = "doDirect.do", method = RequestMethod.GET)
    public ModelAndView doRedirect(String name, Integer age) {
        //创建一个视图
        ModelAndView modelAndView = new ModelAndView();
        //添加数据,这两个数据是存储在request作用域中的
        modelAndView.addObject("myname", name);
        modelAndView.addObject("myage", age);
        //添加视图
        modelAndView.setViewName("redirect:/helloRedirect.jsp");
        //测试结果:http://localhost:8080/ssm-web/helloRedirect.jsp?myname=fb&myage=22
        return modelAndView;
    }

}

1.2.2 没重定向之前的主视图:index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<%
    String basePath = request.getScheme()
            + "://" + request.getServerName()
            + ":" + request.getServerPort()
            + request.getContextPath() + "/";
%>
<head>
    <title>Title</title>
    <base href="<%=basePath%>"/>
</head>

<body>
<p>当你的方法返回ModelAndView的时候实现转发forward</p>
<form action="doForward.do" method="post">
    姓名:<input type="text" name="name"><br/>
    年龄:<input type="text" name="age"><br/>
    <input type="submit" value="提交请求">
</form>

<br/>

<p>当你的方法返回ModelAndView的时候实现重定向direct</p>
<form action="doDirect.do" method="get">
    姓名:<input type="text" name="name"><br/>
    年龄:<input type="text" name="age"><br/>
    <input type="submit" value="提交请求">
</form>

</body>
</html>

1.2.3 请求重定向到的新视图:helloRedirect.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>/helloRedirect.jsp 从request作用域中取出数据</h3>
<h3>myname数据是:${param.myname}</h3>
<h3>myage数据是:${param.myage}</h3>
<h3>parm数据是:${param}</h3>
<h3>parm数据是:<% request.getParameter("myname");%></h3>
</body>
</html>

1.2.4 重定向的测试

2、异常处理

SpringMVC 框架处理异常的常用方式:使用@ExceptionHandler 注解处理异常。

2.1 定义一个后端业务处理器: StudentController.java(可能抛出Name/AgeException等)

package com.wind.controller;

import com.wind.exception.AgeException;
import com.wind.exception.MyUserException;
import com.wind.exception.NameException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;


@Controller
public class StudentController {

    @RequestMapping(value = "doException.do", method = RequestMethod.POST)
    public ModelAndView doException(String name, Integer age) throws MyUserException {
        //创建一个视图
        ModelAndView modelAndView = new ModelAndView();

        //参数校验时可能会抛出异常
        if (name == null || !name.equals("yangguo")) {
            throw new NameException("姓名输入错误了。。。");
        }
        if (age == null || age > 100) {
            throw new AgeException("年龄输入错误了。。。");
        }

        //添加数据,这两个数据是存储在request作用域中的
        modelAndView.addObject("myname", name);
        modelAndView.addObject("myage", age);
        //添加视图
        modelAndView.setViewName("show");
        return modelAndView;
    }

}

2.2 新建一个自定义的全局异常类:MyUserException.java

package com.wind.exception;

public class MyUserException extends Exception {

    public MyUserException() {
        super();
    }

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

2.3 定义全局异常类的子类用来处理姓名异常: NameException.java

package com.wind.exception;

public class NameException extends MyUserException {
    public NameException() {
        super();
    }

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

2.4 定义全局异常类的子类用来处理年龄异常: AgeException.java

package com.wind.exception;

public class AgeException extends MyUserException {

    public AgeException() {
        super();
    }

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

2.5 定义一个普通类用作全局异常处理类(处理姓名/年龄异常): GlobalExceptionHandler.java

package com.wind.handler;


import com.wind.exception.AgeException;
import com.wind.exception.NameException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

/**
 * @ControllerAdvice :控制器增强,也就是说给控制器类增加额外的功能(异常处理功能)
 * (1)这个注解放在类的上面使用。
 * (2)必须让SpringMVC框架知道这个注解所在的包名,需要在SpringMVC配置文件中声名组件扫描器,指定@ControllerAdvice所在的包名
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    //定义方法来处理在Controller业务中抛出的各种异常

    /**
     * (1)处理异常的方法和控制器方法的定义一样,可以有多个参数,有返回值(ModelAndView,String,void等)。
     * (2)形参Exception:表示在Controller中抛出的异常对象,通过此形参即可获取异常对象。
     * (3)@ExceptionHandler(异常类.class):在方法上加注解,标识异常的类型,代表这个异常类型的异常被抛出时由此方法处理。
     */
    //这是处理NameException异常类型的异常
    @ExceptionHandler(value = NameException.class)
    public ModelAndView doNameException(Exception exception) {
        /**
         * 异常发生处理器:
         * (1)需要把异常记录下来,落到DB中、日志文件中等,记录异常发生的时间、哪个方法抛出的、异常错误的内容是啥。
         * (2)发送异常通知给相关人员。
         * (3)给用户一个友好的提示。
         */
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", "姓名必须是yangguo才能访问,其他用户不能访问此页面");
        modelAndView.addObject("ex", exception);
        modelAndView.setViewName("nameError");
        return modelAndView;
    }

    //这是处理AgeException异常类型的异常
    @ExceptionHandler(value = AgeException.class)
    public ModelAndView doAgeException(Exception exception) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", "你的年龄不能大于100岁");
        modelAndView.addObject("ex", exception);
        modelAndView.setViewName("ageError");
        return modelAndView;
    }

    //这是处理NameException、AgeException异常类型之外的其他的未知的异常
    @ExceptionHandler
    public ModelAndView doDefaultException(Exception exception) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", "其他的未知的异常发生了");
        modelAndView.addObject("ex", exception);
        modelAndView.setViewName("defaultError");
        return modelAndView;
    }
}

2.6 定义一个姓名异常的视图: nameError.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>/WEB-INF/jsp/nameError.jsp</h3>
提示信息:${msg}<br/>
系统消息:${ex.message}<br/>
</body>
</html>

2.7 定义一个年龄异常的视图: ageError.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>/WEB-INF/jsp/ageError.jsp</h3>
提示信息:${msg}<br/>
系统消息:${ex.message}<br/>
</body>
</html>

2.8 定义一个其他的未知异常的视图: defaultError.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>/WEB-INF/jsp/defaultError.jsp</h3>
提示信息:${msg}<br/>
系统消息:${ex.message}<br/>
</body>
</html>

2.9 定义一个前端页面的主视图: index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<%
    String basePath = request.getScheme()
            + "://" + request.getServerName()
            + ":" + request.getServerPort()
            + request.getContextPath() + "/";
%>
<head>
    <title>Title</title>
    <base href="<%=basePath%>"/>
</head>

<body>
<p>处理异常的:全局异常处理</p>
<form action="doException.do" method="post">
    姓名:<input type="text" name="name"><br/>
    年龄:<input type="text" name="age"><br/>
    <input type="submit" value="提交请求">
</form>

<br/>

</body>
</html>

2.10 定义一个StudentController处理器处理业务成功后跳转到的数据展示视图: show.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>/WEB-INF/jsp/show.jsp 从request作用域中取出数据</h3>
<h3>myname数据是:${myname}</h3>
<h3>myage数据是:${myage}</h3>
</body>
</html>

2.11 在spriingmvc.xml文件中声名GlobalExceptionHandler处理器的扫描

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--SpringMVC的配置文件,用来声名Controller和其他web相关的对象-->

    <!--配置组件扫描器-->
    <context:component-scan base-package="com.wind.controller"/>

    <!--视图解析器:添加前缀和后缀。
    SpringMVC框架为了避免对于请求资源路径与扩展名上的冗余,在视图解析器 InternalResouceViewResolver
    中引入了请求的前辍与后辍。而 ModelAndView 中只需给出要跳转页面的文件名即可,对于具体的文件路径与文件扩展名,
    视图解析器会自动完成拼接。-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--视图文件的路径-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--视图文件的扩展名-->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--注册注解驱动。
    (1)响应ajax请求,返回json字符串。
    (2)解决静态资源访问问题。-->
    <mvc:annotation-driven/>

    <!--注册组件扫描器-->
    <context:component-scan base-package="com.wind.handler"/>

    <!--加载静态资源图片啊,jQuery文件啊等等-->
    <mvc:resources location="js/" mapping="/js/**"/>

</beans>

2.12 业务成功的测试

2.13 姓名异常测试

2.14 年龄异常测试

2.15 其他未知的异常测试

2.16 项目结构图

3、拦截器

SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。

其拦截的时间点在“处理器映射器根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器执行处理器之前”。

当然,在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。

3.1 定义一个拦截器:步骤如下

3.1.1 引入依赖 pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wind</groupId>
    <artifactId>ssm-web4</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>ssm-web Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.3.2</spring.version>
        <mybatis.version>3.4.6</mybatis.version>
        <mybatis.spring.version>2.0.3</mybatis.spring.version>
        <mysql.version>8.0.22</mysql.version>
        <druid.version>1.2.4</druid.version>
    </properties>

    <dependencies>

        <!--Spring事务依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!--Spring原生JDBC依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!--SpringMVC依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!--SpringMVC使用的Servlet依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>

        <!--SpringMVC使用的jsp依赖-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2.1-b03</version>
        </dependency>

        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <!--MyBatis依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>

        <!--MyBatis与SpringMVC整合时需要的依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis.spring.version}</version>
        </dependency>

        <!--mysql驱动依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!--mysql数据库连接池依赖:使用的是德鲁伊数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>

        <!--springMVC序列化用的jackson依赖-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.10.2</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.2</version>
        </dependency>

        <!--单元测试依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

    </dependencies>


    <build>
        <finalName>ssm-web</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>

        <!--
        maven默认扫描src/main/java中的文件而不理会src/main/resources中的xml文件,
        所以后来添加了resource节点,这样就将src/main/resources中的xml文件改变maven默认的扫描策略,
        防止造成src/main/resources下的配置文件打包丢失。
        编译之后的文件中少了mapper.xml,这个和maven有关,maven编译src/java代码的时候,
        默认只会对java文件进行编译然后放在target/classes目录,需要在pom.xml中加入下面配置-->
        <!--如果不添加此节点,mapper.xml文件、config.properties文件、config.spring文件等
        都不会被加载到target的classes中去,也就不能被使用,也就会报错。-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

</project>

3.1.2 编写springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--SpringMVC的配置文件,用来声名Controller和其他web相关的对象-->

    <!--配置组件扫描器-->
    <context:component-scan base-package="com.wind.controller"/>

    <!--视图解析器:添加前缀和后缀。
    SpringMVC框架为了避免对于请求资源路径与扩展名上的冗余,在视图解析器 InternalResouceViewResolver
    中引入了请求的前辍与后辍。而 ModelAndView 中只需给出要跳转页面的文件名即可,对于具体的文件路径与文件扩展名,
    视图解析器会自动完成拼接。-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--视图文件的路径-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--视图文件的扩展名-->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--注册注解驱动。
    (1)响应ajax请求,返回json字符串。
    (2)解决静态资源访问问题。-->
    <mvc:annotation-driven/>

    <!--加载静态资源图片啊,jQuery文件啊等等-->
    <mvc:resources location="js/" mapping="/js/**"/>

    <!--
    1.在SpringMVC配置文件中声名拦截器:拦截器可以有一个或者多个。
    2.path:指定拦截器拦截的URI地址,可以使用通配符 **
        (1)**:表示任意的字符,可以表示文件、目录、多级目录下的文件。
        (2)http://localhost:8080/student/addStudent.do
        (3)http://localhost:8080/user/addUser.do
    3.class:声名拦截器对象
    -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.wind.handler.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

</beans>

3.1.3 编写spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!--Spring的配置文件,用来声名service、dao、工具类等对象-->

    <!--加载连接mysql时需要的配置文件-->
    <context:property-placeholder location="classpath:config/jdbc.properties"/>

    <!--声名数据源,连接数据库-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <!--配置数据库连接池的初始化大小、最小、最大-->
        <property name="initialSize" value="5"/>
        <property name="minIdle" value="5"/>
        <property name="maxActive" value="20"/>
        <!--配置获取连接等待超时的时间,单位是毫秒-->
        <property name="maxWait" value="10000"/>
        <!--配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒-->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!--配置一个连接在池中最小生存的时间,单位是毫秒-->
        <property name="minEvictableIdleTimeMillis" value="300000"/>
    </bean>

    <!--声名一个SqlSessionFactoryBean,用它来创建SqlSessionFactory-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:config/mybatis.xml"/>
    </bean>

    <!--声名MyBatis的扫描器,创建dao接口接口对象-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
        <property name="basePackage" value="com.wind.dao"/>
    </bean>

    <!--声名service的注解@Service所在的包名-->
    <!--<context:component-scan base-package="com.wind.service,com.wind.serviceImpl"/>-->
    <context:component-scan base-package="com.wind.service*"/>

    <!--事务的配置:注解的配置方式;aspectJ的配置方式。可以后期去加。-->

</beans>

3.1.4 编写mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
        <!-- 打印SQL-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--给实体类设置别名-->
    <typeAliases>
        <package name="com.wind.entity"/>
    </typeAliases>

    <!--SQL Mapper映射文件的位置-->
    <mappers>
        <!--name:是包名,这个包下的mapper文件能够一次性加载-->
        <!--package:使用这个属性的前提是:
        (1)mapper文件名称和dao接口名必须完全一样,包括大小写。
        (2)mapper文件和dao接口必须在同一目录下。-->
        <package name="com.wind.dao"/>
    </mappers>

</configuration>

3.1.5 编写db.properties

##数据库驱动
jdbc.driverClassName=com.mysql.jdbc.Driver
##MySQL连接信息
jdbc.url=jdbc:mysql://127.0.0.1:3306/RUNOOB?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT
##用户名
jdbc.username=root
##密码
jdbc.password=root

3.1.6 编写控制器:StudentController

package com.wind.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;


@Controller
public class StudentController {

    @RequestMapping(value = "doIntercept.do", method = RequestMethod.POST)
    public ModelAndView doIntercept(String name, Integer age) {
        System.out.println("====StudentController.doIntercept()方法执行了====");
        //创建一个视图
        ModelAndView modelAndView = new ModelAndView();
        //添加数据,这两个数据是存储在request作用域中的
        modelAndView.addObject("myname", name);
        modelAndView.addObject("myage", age);
        //添加视图
        modelAndView.setViewName("show");
        return modelAndView;
    }

}

3.1.7 编写拦截器MyInterceptor(需要 implement HandlerInterceptor)

package com.wind.handler;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 当前这个类是一个拦截器类,用于拦截用户的请求
 */
@Component
public class MyInterceptor implements HandlerInterceptor {

    /**
     * 1、preHandle:预处理方法,很重要,是整个项目中所有请求的门户,可以控制请求是否需要被处理。
     * 返回true:表示请求通过了拦截器的验证,可以继续执行后续的业务逻辑。
     * 返回false:表示请求没有通过拦截器的验证,不可以继续执行后续的业务逻辑,请求到这儿就截止了。
     * <p>
     * 2、参数:
     * HttpServletRequest:请求参数
     * HttpServletResponse:应答结果
     * handler:被拦截的控制器
     * <p>
     * 3、返回值boolean:
     * (1)true:表示请求通过了拦截器的验证,可以继续执行后续的业务逻辑。
     * MyInterceptor.preHandle()方法执行了...
     * ====StudentController.doIntercept()方法执行了====
     * MyInterceptor.postHandle()方法执行了...
     * MyInterceptor.afterCompletion()方法执行了...
     * (2)false:表示请求没有通过拦截器的验证,不可以继续执行后续的业务逻辑,请求到这儿就截止了。
     * MyInterceptor.preHandle()方法执行了...
     * <p>
     * 4、特点:在这个方法中可以获得用户请求信息,从而判断用户请求信息是否符合要求,
     * 比如可以判断用户是否登陆了,是否有权限去访问某个URL链接地址。
     * (1)如果符合要求:可以放行请求,由处理器接着执行真正的业务逻辑。
     * (2)如果不符合要求:可以截断请求,请求不能被处理。
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {

        //注意:这里面可以做你自己的业务逻辑,根据业务逻辑需要来返回true或者false。

        System.out.println("MyInterceptor.preHandle()方法执行了...");
        //当返回false的时候,可以转发到一个jsp页面给用户一个提示。
        request.getRequestDispatcher("/tips.jsp").forward(request, response);
        return false;
    }

    /**
     * 1、postHandle:后处理方法
     * 2、参数:
     * HttpServletRequest:请求参数
     * HttpServletResponse:应答结果
     * handler:被拦截的控制器
     * ModelAndView:处理器方法的返回值对象
     * 3、特点:
     * (1)无返回值。
     * (2)在处理器方法执行之后才执行的。
     * (3)可以对处理器方法执行之后的结果ModelAndView做数和视图的修正,可以影响最终吐给用户的数据。
     * (4)主要是对原处理器执行结果做的二次修正。
     */
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {

        System.out.println("MyInterceptor.postHandle()方法执行了...");
    }

    /**
     * 1、afterCompletion:最后执行的方法
     * 2、参数:
     * HttpServletRequest:请求参数
     * HttpServletResponse:应答结果
     * handler:被拦截的控制器
     * Exception:程序发生的异常
     * 3、特点:
     * (1)在"请求处理完成"之后执行的方法。
     * (2)什么是"请求处理完成"呢?框架中规定是在你的处理器对视图处理完成之后,对视图做了forward处理,就算是"请求处理完成"了。
     * (3)一般是做资源回收的,程序在处理请求的执行中创建了一些对象,在这里可以删除,回收内存。
     */
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        System.out.println("MyInterceptor.afterCompletion()方法执行了...");
    }
}

3.1.8 编写前端主页面:index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<%
    String basePath = request.getScheme()
            + "://" + request.getServerName()
            + ":" + request.getServerPort()
            + request.getContextPath() + "/";
%>
<head>
    <title>Title</title>
    <base href="<%=basePath%>"/>
</head>

<body>
<p>一个拦截器</p>
<form action="doIntercept.do" method="post">
    姓名:<input type="text" name="name"><br/>
    年龄:<input type="text" name="age"><br/>
    <input type="submit" value="提交请求">
</form>

<br/>

</body>
</html>

3.1.9 编写处理器StudentController处理完成后转发到的页面:show.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>/WEB-INF/jsp/show.jsp 从request作用域中取出数据</h3>
<h3>myname数据是:${myname}</h3>
<h3>myage数据是:${myage}</h3>
</body>
</html>

3.1.10 编写拦截器返回false时拦截器内部转发到的友好页面:tips.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<%
    String basePath = request.getScheme()
            + "://" + request.getServerName()
            + ":" + request.getServerPort()
            + request.getContextPath() + "/";
%>
<head>
    <title>Title</title>
    <base href="<%=basePath%>"/>
</head>

<body>
<p>tips.jap:请求被拦截了,不能继续向后执行了</p>
</body>
</html>

3.1.11 测试preHandler()方法:预处理方法

(1)preHandler返回true时:

(2)preHandler返回false时:

3.1.12 测试postHandler()方法:后处理方法

(1)首先preHandler()需要返回true

(2)在postHandler()方法中对处理器返回的结果做二次修正

package com.wind.handler;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * 当前这个类是一个拦截器类,用于拦截用户的请求
 */
@Component
public class MyInterceptor implements HandlerInterceptor {

    /**
     * 1、preHandle:预处理方法,很重要,是整个项目中所有请求的门户,可以控制请求是否需要被处理。
     * 返回true:表示请求通过了拦截器的验证,可以继续执行后续的业务逻辑。
     * 返回false:表示请求没有通过拦截器的验证,不可以继续执行后续的业务逻辑,请求到这儿就截止了。
     * <p>
     * 2、参数:
     * HttpServletRequest:请求参数
     * HttpServletResponse:应答结果
     * handler:被拦截的控制器
     * <p>
     * 3、返回值boolean:
     * (1)true:表示请求通过了拦截器的验证,可以继续执行后续的业务逻辑。
     * MyInterceptor.preHandle()方法执行了...
     * ====StudentController.doIntercept()方法执行了====
     * MyInterceptor.postHandle()方法执行了...
     * MyInterceptor.afterCompletion()方法执行了...
     * (2)false:表示请求没有通过拦截器的验证,不可以继续执行后续的业务逻辑,请求到这儿就截止了。
     * MyInterceptor.preHandle()方法执行了...
     * <p>
     * 4、特点:在这个方法中可以获得用户请求信息,从而判断用户请求信息是否符合要求,
     * 比如可以判断用户是否登陆了,是否有权限去访问某个URL链接地址。
     * (1)如果符合要求:可以放行请求,由处理器接着执行真正的业务逻辑。
     * (2)如果不符合要求:可以截断请求,请求不能被处理。
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {

        //注意:这里面可以做你自己的业务逻辑,根据业务逻辑需要来返回true或者false。

        System.out.println("MyInterceptor.preHandle()方法执行了...");
        //当返回false的时候,可以转发到一个jsp页面给用户一个提示。
        //request.getRequestDispatcher("/tips.jsp").forward(request, response);
        return true;
    }

    /**
     * 1、postHandle:后处理方法
     * 2、参数:
     * HttpServletRequest:请求参数
     * HttpServletResponse:应答结果
     * handler:被拦截的控制器
     * ModelAndView:处理器方法的返回值对象
     * 3、特点:
     * (1)无返回值。
     * (2)在处理器方法执行之后才执行的。
     * (3)可以对处理器方法执行之后的结果ModelAndView做数和视图的修正,可以影响最终吐给用户的数据。
     * (4)主要是对原处理器执行结果做的二次修正。
     */
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {

        System.out.println("MyInterceptor.postHandle()方法执行了...");
        //对处理器执行的结果做一个二次修正
        if (modelAndView != null) {
            modelAndView.addObject("mydate", new Date());
            modelAndView.setViewName("postHandleJsp");
        }
    }

    /**
     * 1、afterCompletion:最后执行的方法
     * 2、参数:
     * HttpServletRequest:请求参数
     * HttpServletResponse:应答结果
     * handler:被拦截的控制器
     * Exception:程序发生的异常
     * 3、特点:
     * (1)在"请求处理完成"之后执行的方法。
     * (2)什么是"请求处理完成"呢?框架中规定是在你的处理器对视图处理完成之后,对视图做了forward处理,就算是"请求处理完成"了。
     * (3)一般是做资源回收的,程序在处理请求的执行中创建了一些对象,在这里可以删除,回收内存。
     */
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        System.out.println("MyInterceptor.afterCompletion()方法执行了...");
    }
}

(3)将修正后的结果在转发的新的视图中展示出来:postHandlerJsp.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>/WEB-INF/jsp/postHandleJsp.jsp 从request作用域中取出数据</h3>
<h3>myname数据是:${myname}</h3>
<h3>myage数据是:${myage}</h3>
<h3>拦截器增加的数据:${mydate}</h3>
</body>
</html>

(4)测试postHandler()方法

3.1.13 测试afterCompletion()方法:最后执行的方法

(1)afterCompletion():

   /**
     * 1、afterCompletion:最后执行的方法
     * 2、参数:
     * HttpServletRequest:请求参数
     * HttpServletResponse:应答结果
     * handler:被拦截的控制器
     * Exception:程序发生的异常
     * 3、特点:
     * (1)在"请求处理完成"之后执行的方法。
     * (2)什么是"请求处理完成"呢?框架中规定是在你的处理器对视图处理完成之后,对视图做了forward处理,就算是"请求处理完成"了。
     * (3)一般是做资源回收的,程序在处理请求的执行中创建了一些对象,在这里可以删除,回收内存。
     */
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        
        eTime = System.currentTimeMillis();
        System.out.println("MyInterceptor.afterCompletion()方法执行了..." +
                "preHandler到afterCompletion执行结束用时=" + (eTime - bTime));
    }

(2)测试结果:

3.1.14 经过preHandler/postHandler/afterCompletion之后的项目结构图

3.2 在项目中声名多个拦截器时

3.2.1 声名拦截器1的类

package com.wind.handler;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 当前这个类是一个拦截器类,用于拦截用户的请求
 */
@Component
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {

        System.out.println("1111111-MyInterceptor.preHandle()方法执行了...");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {

        System.out.println("1111111-MyInterceptor.postHandle()方法执行了...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {

        System.out.println("1111111-MyInterceptor.afterCompletion()方法执行了...");
    }
}

3.2.2 声名拦截器2的类

package com.wind.handler;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 当前这个类是一个拦截器类,用于拦截用户的请求
 */
@Component
public class MyInterceptor2 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {

        System.out.println("2222222-MyInterceptor.preHandle()方法执行了...");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {

        System.out.println("2222222-MyInterceptor.postHandle()方法执行了...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {

        System.out.println("2222222-MyInterceptor.afterCompletion()方法执行了...");
    }
}

3.2.3 在springmvc.xml文件中配置多个拦截器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--SpringMVC的配置文件,用来声名Controller和其他web相关的对象-->

    <!--配置组件扫描器-->
    <context:component-scan base-package="com.wind.controller"/>

    <!--视图解析器:添加前缀和后缀。
    SpringMVC框架为了避免对于请求资源路径与扩展名上的冗余,在视图解析器 InternalResouceViewResolver
    中引入了请求的前辍与后辍。而 ModelAndView 中只需给出要跳转页面的文件名即可,对于具体的文件路径与文件扩展名,
    视图解析器会自动完成拼接。-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--视图文件的路径-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--视图文件的扩展名-->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--注册注解驱动。
    (1)响应ajax请求,返回json字符串。
    (2)解决静态资源访问问题。-->
    <mvc:annotation-driven/>

    <!--加载静态资源图片啊,jQuery文件啊等等-->
    <mvc:resources location="js/" mapping="/js/**"/>

    <!--
    1.在SpringMVC配置文件中声名拦截器:拦截器可以有一个或者多个。
    2.path:指定拦截器拦截的URI地址,可以使用通配符 **
        (1)**:表示任意的字符,可以表示文件、目录、多级目录下的文件。
        (2)http://localhost:8080/student/addStudent.do
        (3)http://localhost:8080/user/addUser.do
    3.class:声名拦截器对象
    4.拦截器在框架内部其实存储在一个ArrayList中的,先声明的放在ArrayList中的前面,后声明的放在ArrayList中的后面。
    也即:对于多个拦截器而言,先声明的先执行,后声明的后执行。
    -->
    <mvc:interceptors>
        <!--声名第一个拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.wind.handler.MyInterceptor"/>
        </mvc:interceptor>
        <!--声名第二个拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.wind.handler.MyInterceptor2"/>
        </mvc:interceptor>
    </mvc:interceptors>

</beans>

3.2.4 当项目中存在多个拦截器时, 拦截器的执行流程图和执行顺序

3.3 过滤器和拦截器之间的区别与联系

猜你喜欢

转载自blog.csdn.net/cmm0401/article/details/112094335