SpringMVC框架入门60-72:拦截器

开始时间:2022-02-22
课程链接:动力节点SpringMVC课程

拦截器

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

拦截器的使用步骤:
1.定义类实现HandlerInterceptor接口
2.在springmvc配置文件中,声明拦截器, 让框架知道拦截器的存在。

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

拦截器:看做是多个Controller中公用的功能,集中到拦截器统一处理。使用的aop的思想

拦截器使用步骤

1.新建maven web项目
2.加入依赖
3.创建Controller类
4.创建一个普通类,作为拦截器使用
1)实现HandlerInterceptor接口
2)实现接口中的三个方法
5.创建show.jsp
6.创建springmvc的配置文件
1)组件扫描器 ,扫描@Controller注解
2)声明拦截器,并指定拦截的请求uri地址

按照这个是顺序来写
MyController类

public class MyController {
    @RequestMapping(value = "/some.do")
    public ModelAndView doSome(String name, Integer age) {
        System.out.println("=====执行MyController中的doSome方法=====");
        //处理some.do请求了。 相当于service调用处理完成了。
        ModelAndView mv = new ModelAndView();
        mv.addObject("myname", name);
        mv.addObject("myage", age);
        mv.setViewName("show");
        return mv;
    }
}

创建拦截器

package BUPT.handler;

import...;

//拦截器类:拦截用户的请求。
public class MyInterceptor implements HandlerInterceptor {

    //private long btime = 0;
    /*
     * preHandle叫做预处理方法。
     *   重要:是整个项目的入口,门户。 当preHandle返回true 请求可以被处理。
     *        preHandle返回false,请求到此方法就截止。
     * 参数:
     *  Object handler : 被拦截的控制器对象
     * 返回值boolean
     *   true:请求是通过了拦截器的验证,可以执行处理器方法。
         *   拦截器的MyInterceptorpreHandle()
             =====执行MyController中的doSome方法=====
             拦截器的MyInterceptorpostHandle()
             拦截器的MyInterceptorafterCompletion()
         *
     *   false:请求没有通过拦截器的验证,请求到达拦截器就截止了。 请求没有被处理
     *      拦截器的MyInterceptorpreHandle()

     *  特点:
     *   1.方法在控制器方法(MyController的doSome)之前先执行的。
     *     用户的请求首先到达此方法
     *
     *   2.在这个 方法中可以获取请求的信息, 验证请求是否符合要求。
     *     可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)。
     *      如果验证失败,可以截断请求,请求不能被处理。
     *      如果验证成功,可以放行请求,此时控制器方法才能执行。
     */

预处理方法

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //btime = System.currentTimeMillis();
        System.out.println("拦截器的MyInterceptor的preHandle()");
        //计算的业务逻辑,根据计算结果,返回true或者false

        return true;
    }

预处理方法返回false
此时就只能转到tip里面而没办法转发到dosome那里去

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //btime = System.currentTimeMillis();
        System.out.println("拦截器的MyInterceptor的preHandle()");
        //计算的业务逻辑,根据计算结果,返回true或者false
        //给浏览器一个返回结果
        request.getRequestDispatcher("/tips.jsp").forward(request,response);
        return false;
    }

后处理方法:主要是对原来的执行结果做二次修正
转发到的是other视图

    /*
       postHandle:后处理方法。
       参数:
        Object handler:被拦截的处理器对象MyController
        ModelAndView mv:处理器方法的返回值

        特点:
         1.在处理器方法之后执行的(MyController.doSome())
         2.能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的
         数据和视图,可以影响到最后的执行结果。
         3.主要是对原来的执行结果做二次修正,

         ModelAndView mv = MyController.doSome();
         postHandle(request,response,handler,mv);
     */
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler, ModelAndView mv) throws Exception {
        System.out.println("拦截器的MyInterceptor的postHandle()");
        //对原来的doSome执行结果,需要调整。
        if( mv != null){
            //修改数据
            mv.addObject("mydate",new Date());
            //修改视图
            mv.setViewName("other");
        }
    }

最后执行的方法afterCompletion
特点:
1.在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
2.一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收

    /*
      afterCompletion:最后执行的方法
      参数
        Object handler:被拦截器的处理器对象
        Exception ex:程序中发生的异常
  。
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        System.out.println("拦截器的MyInterceptor的afterCompletion()");

        //long etime = System.currentTimeMillis();
        //System.out.println("计算从preHandle到请求处理完成的时间:"+(etime - btime ));
    }
}

我们这里得到结果

计算从preHandle到请求处理完成的时间:199

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><br/>
    <h3>myname数据:${myname}</h3><br/>
    <h3>myage数据:${myage}</h3>
</body>
</html>

配置文件
组件扫描器

<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--声明组件扫描器-->
    <context:component-scan base-package="BUPT.controller" />

    <!--声明 springmvc框架中的视图解析器, 帮助开发人员设置视图文件的路径-->
    <bean  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀:视图文件的路径-->
        <property name="prefix" value="/WEB-INF/view/" />
        <!--后缀:视图文件的扩展名-->
        <property name="suffix" value=".jsp" />
    </bean>

声明拦截器

    <!--声明拦截器: 拦截器可以有0或多个-->
    <mvc:interceptors>
        <!--声明第一个拦截器-->
        <mvc:interceptor>
            <!--指定拦截的请求uri地址
                path:就是uri地址,可以使用通配符 **
                      ** : 表示任意的字符,文件或者多级目录和目录中的文件
                http://localhost:8080/myweb/user/listUser.do
                http://localhost:8080/myweb/student/addStudent.do
                user开头的都拦截下来
            -->
            <mvc:mapping path="/**"/>
            <!--声明拦截器对象-->
            <bean class="BUPT.handler.MyInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>

</beans>

可以观察到执行顺序

拦截器的MyInterceptorpreHandle()
=====执行MyController中的doSome方法=====
拦截器的MyInterceptorpostHandle()
拦截器的MyInterceptorafterCompletion()

多个拦截器

再定义一个拦截器MyInterceptor2
执行顺序按照在SpringMVC里面的配置顺序来的
因为传回去是一个ArrayList,顺序就是配置顺序

package BUPT.handler;

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

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

//拦截器类:拦截用户的请求。
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(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler, ModelAndView mv) throws Exception {
        System.out.println("22222-拦截器的MyInterceptor的postHandle()");
    }


    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        System.out.println("22222-拦截器的MyInterceptor的afterCompletion()");
    }
}

并给他进行注册

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

此时preHandle两个拦截器都是true
得到运行结果

111111-拦截器的MyInterceptorpreHandle()
22222-拦截器的MyInterceptorpreHandle()
=====执行MyController中的doSome方法=====
22222-拦截器的MyInterceptorpostHandle()
111111-拦截器的MyInterceptorpostHandle()
22222-拦截器的MyInterceptorafterCompletion()
111111-拦截器的MyInterceptorafterCompletion()

执行顺序如图
在这里插入图片描述
考虑情况
拦截器1为真,2 为假

111111-拦截器的MyInterceptorpreHandle()
22222-拦截器的MyInterceptorpreHandle()
111111-拦截器的MyInterceptorafterCompletion()

考虑情况
拦截器1为假,2为真/假

111111-拦截器的MyInterceptorpreHandle()

只要有一个 preHandle()方法返回 false,则上部的执行链将被断开,
其后续的处理器方法与 postHandle()方法将无法执行。但,无论执行链执行情况怎样,只要
方法栈中有方法,即执行链中只要有 preHandle()方法返回 true,就会执行方法栈中的
afterCompletion()方法。最终都会给出响应。
在这里插入图片描述

拦截器和过滤器的区别

拦截器和过滤器的区别

1.过滤器是servlet中的对象, 拦截器是框架中的对象

2.过滤器实现Filter接口的对象, 拦截器是实现HandlerInterceptor

3.过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的。
拦截器是用来验证请求的,能截断请求。

4.过滤器是在拦截器之前先执行的。

5.过滤器是tomcat服务器创建的对象
拦截器是springmvc容器中创建的对象

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

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

8.拦截器拦截普通类方法执行,过滤器过滤servlet请求响应

登录验证拦截器

ch12-interceptor-permission: 使用拦截器检查登录的用户是不是能访问系统

实现步骤:
1.新建maven
2.修改web.xml注册中央调度器
3.新建index.jsp发起请求
4.创建MyController处理请求
5.创建结果show.jsp
6.创建一个login.jsp,模拟登录(把用户的信息放入到session);
创建一个jsp, logout.jsp,模拟退出系统(从session中删除数据)
7.创建拦截器,从session中获取用户的登录数据,验证能否访问系统
8.创建一个验证的jsp,如果验证视图,给出提示
9.创建springmvc配置文件
声明组件扫描器
声明拦截器

这个功能我要说明下
就是说
我最开始如果直接在index界面上输入姓名和年龄
无论我输入的姓名是否是zs,我都进不去,因为他这里的判断逻辑是session里面有没有携带zs

而当我直接在浏览器中输入
http://localhost:8080/ch12_interceptor_permission/login.jsp
进入了一次login.jsp,模拟了登录成功(这里的登录成功不是从index里面来的,是直接输入的网址)
此时
我再到index界面后,无论输入是否是zs,都能进去得到信息了
相当于进入了一次login,获取了管理员权限,此时都可以操作

那想取消权限,就在浏览器中输入
http://localhost:8080/ch12_interceptor_permission/logout.jsp
这样来看再从index里面进去,输入什么都不行了

很多代码都是重复的
下面给些不重复的
MyInterceptor

package BUPT.handler;

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;

//拦截器类:拦截用户的请求。
public class MyInterceptor implements HandlerInterceptor {
    //验证登录的用户信息, 正确return true,其它return false
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("111111-拦截器的MyInterceptor的preHandle()");
        String loginName = "";
        //从session中获取name的值
        Object attr  = request.getSession().getAttribute("name");
        if( attr != null){
            loginName = (String)attr;
        }

        //判断登录的账户,是否符合要求
        if( !"zs".equals(loginName)){
            //不能访问系统
            //给用户提示
            request.getRequestDispatcher("/tips.jsp").forward(request,response);
            return false;
        }
        //zs登录
        return true;
    }
}

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    模拟登录,zs登录系统
    <%
        session.setAttribute("name","zs");
    %>

</body>
</html>

logout.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
   退出系统,从session中删除数据
  <%
      session.removeAttribute("name");
  %>
</body>
</html>

tips.jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  tips.jsp  非zs不能访问系统
</body>
</html>

第一次访问
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后让其登录一次
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
再退出一次
在这里插入图片描述
就不能进去了
在这里插入图片描述
在这里插入图片描述

总结SpringMVC流程

在这里插入图片描述
(1)浏览器提交请求到中央调度器(index.jsp中的some.do)
(2)中央调度器直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后
返回给中央调度器。(MyController中的doSome)
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器。
(6)处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给
处理器适配器。(doSome返回mv)
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器将封装了的视图对象返回给中央调度器(springmvc.xml中的视图解析器)
(10)中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器。(show.jsp)

或者说
SpringMVC内部请求的处理流程:

  • 用户发起请求some.do
  • DispatcherServlet接收请求some.do,把请求转交给处理器映射器
  • 处理器映射器:springmvc框架中的一种对象,框架把实现了HandlerMapping接口的类都叫做映射器(多个)
    处理器映射器作用;根据请求,从SpringMVC容器对象中获取处理器对象(MyController controller=ctx.getBean(“some.do”),框架把找到的处理器对象放到一个叫做处理器执行链(HandletExecutionChain)的类保存
    HandlerExecutionChain类中保存着:处理器对象(MyController)以及项目中的所有拦截器List<HandlerInterceptors>
  • DispatcherServlet把2中的HandlerExecutionChain中的处理器对象交给了处理器适配器对象(多个)
    处理器适配器:springMVC框架中的对象,需要实现HandlerAdapter接口
    适配器作用:执行处理器方法(调用MyControllerl.doSome()得到返回值ModelAndView)
  • DispatcherServlet把3中获取的ModelAndView交给了视图解析器对象
    视图解析器:springmvc中的对象,需要实现viewResoler接口(可以有多个)
    视图解析器作用:组成视图完整路径,使用前缀,后缀。并创建view对象。
    View是一个接口,表示视图的,在框架中jsp,html不是string表示,而是使用view和他的实现类表示视图。
    InternalResourceView:视图类,表示jsp文件,视图解析器会创建InternalResourceView类对象。
    这个对象里面有一个属性url=/WEB-INF/view/show.jsp
  • DispatcherServlet把4步骤中创建的view对象获取到,调用view类自己的方法,把Modiel数据放入到request作用域。执行对象视图的forward。请求结束。

结束时间:2022-02-23

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值