SpringMVC学习记录

注意:以下内容是学习 北京动力节点 的SpringMVC视频后所记录的笔记、源码以及个人的理解等,记录下来仅供学习

第4章 SpringMVC 核心技术

4.3 拦截器

  SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。其拦截的时间点在“处理器映射器根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器执行处理器之前”。当然,在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。

4.3.1 一个拦截器的执行

自定义拦截器

package com.bjpowernode.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 { private long btime = 0;
/*
* preHandle叫做预处理方法。
*/
@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 true;
} /*
postHandle:后处理方法。
*/
@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:最后执行的方法
*/
@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 ));
}
}

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

1、 preHandle(request,response, Object handler) 预处理方法:

  该方法在处理器方法执行之前执行。其返回值为boolean,若为true,则紧接着会执行处理器方 法,且会将afterCompletion()方法放入到一个专门的方法栈中等待执行。

重要:
是整个项目的入口,门户。 当preHandle返回true 请求可以被处理。 preHandle返回false,请求到此方法就截止。
参数:
Object handler : 被拦截的控制器对象
返回值boolean
true:请求是通过了拦截器的验证,可以执行处理器方法。
拦截器的MyInterceptor的preHandle()
=====执行MyController中的doSome方法=====
拦截器的MyInterceptor的postHandle()
拦截器的MyInterceptor的afterCompletion() false:请求没有通过拦截器的验证,请求到达拦截器就截止了。 请求没有被处理
拦截器的MyInterceptor的preHandle() 特点:
a.方法在控制器方法(MyController的doSome)之前先执行的。 用户的请求首先到达此方法
b.在这个方法中可以获取请求的信息, 验证请求是否符合要求。可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)。
如果验证失败,可以截断请求,请求不能被处理。
如果验证成功,可以放行请求,此时控制器方法才能执行。

2、postHandle(request/response/ Object handlei,modelAndView) 后处理方法:

 该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。 由于该方法是在处理器方法执行完后执行,且该方法参数中包含ModelAndView,所以该方法可以修 改处理器方法的处理结果数据,且可以修改跳转方向。

参数:
Object handler:被拦截的处理器对象MyController
ModelAndView mv:处理器方法的返回值 特点:
a.在处理器方法之后执行的(MyController.doSome())
b.能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的
数据和视图,可以影响到最后的执行结果。
c.主要是对原来的执行结果做二次修正, ModelAndView mv = MyController.doSome();
postHandle(request,response,handler,mv);

3、afterCompletion(request,response, Object handler, Exception ex)最后执行的方法:

 当preHandle()方法返回true时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有 工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此 时对ModelAndView再操作也对响应无济于事。

afterCompletion**最后执行的方法,清除资源,例如在Controller方法中加入数据

参数
Object handler:被拦截器的处理器对象
Exception ex:程序中发生的异常
特点:
a.在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
b.一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收。

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

换一种表现方式,也可以这样理解:

(1) 注册拦截器

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 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="com.bjpowernode.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
-->
<mvc:mapping path="/**"/>
<!--声明拦截器对象-->
<bean class="com.bjpowernode.handler.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors> </beans>

mvc:mapping/用于指定当前所注册的拦截器可以拦截的请求路径,而 /**表示拦截所 有请求。

(2) 修改 index 页面

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>Title</title>
<base href="<%=basePath%>" />
</head>
<body>
<p>一个拦截器</p>
<form action="some.do" method="post">
姓名:<input type="text" name="name"> <br/>
年龄:<input type="text" name="age"> <br/>
<input type="submit" value="提交请求">
</form>
</body>
</html>

(3) 修改处理器

MyController.java

package com.bjpowernode.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView; /**
* @RequestMapping:
* value : 所有请求地址的公共部分,叫做模块名称
* 位置: 放在类的上面
*/
@Controller
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;
}
}

(4) 修改 show 页面

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>

4.3.2 多个拦截器的执行

项目在4.3.1的基础上

项目结构

(1) 再定义一个拦截器

MyInterceptor2 .java

package com.bjpowernode.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()");
}
}

(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 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="com.bjpowernode.controller" /> <!--声明 springmvc框架中的视图解析器, 帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀:视图文件的路径-->
<property name="prefix" value="/WEB-INF/view/" />
<!--后缀:视图文件的扩展名-->
<property name="suffix" value=".jsp" />
</bean> <!--声明拦截器: 拦截器可以有0或多个
在框架中保存多个拦截器是ArrayList,
按照声明的先后顺序放入到ArrayList
-->
<mvc:interceptors>
<!--声明第一个拦截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!--声明拦截器对象-->
<bean class="com.bjpowernode.handler.MyInterceptor" />
</mvc:interceptor>
<!--声明第二个拦截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.bjpowernode.handler.MyInterceptor2" />
</mvc:interceptor>
</mvc:interceptors> </beans>

当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致。需要再次强调一点的是,当某一个拦截器的peHandle()方法返回 true 并被执行到时,会向一个专门的方法栈中放入该拦截器的 afterCompletion()方法。

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

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

换一种表现方式,也可以这样理解:

4.3.3 公共资源

(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.bjpowernode</groupId>
<artifactId>ch11-interceptor2</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging> <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>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--jsp依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
<scope>provided</scope>
</dependency>
<!--springmvc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
</dependencies> <build>
<plugins>
<!-- 编码和编译和JDK版本 -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

(2) web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"> <!--声明,注册springmvc的核心对象DispatcherServlet
需要在tomcat服务器启动后,创建DispatcherServlet对象的实例。
为什么要创建DispatcherServlet对象的实例呢?
因为DispatcherServlet在他的创建过程中, 会同时创建springmvc容器对象,
读取springmvc的配置文件,把这个配置文件中的对象都创建好, 当用户发起
请求时就可以直接使用对象了。 servlet的初始化会执行init()方法。 DispatcherServlet在init()中{
//创建容器,读取配置文件
WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
//把容器对象放入到ServletContext中
getServletContext().setAttribute(key, ctx);
} 启动tomcat报错,读取这个文件 /WEB-INF/springmvc-servlet.xml(/WEB-INF/myweb-servlet.xml)
springmvc创建容器对象时,读取的配置文件默认是/WEB-INF/<servlet-name>-servlet.xml .
-->
<servlet>
<servlet-name>myweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--自定义springmvc读取的配置文件的位置-->
<init-param>
<!--springmvc的配置文件的位置的属性-->
<param-name>contextConfigLocation</param-name>
<!--指定自定义文件的位置-->
<param-value>classpath:springmvc.xml</param-value>
</init-param> <!--在tomcat启动后,创建Servlet对象
load-on-startup:表示tomcat启动后创建对象的顺序。它的值是整数,数值越小,
tomcat创建对象的时间越早。 大于等于0的整数。
-->
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>myweb</servlet-name>
<!--
使用框架的时候, url-pattern可以使用两种值
1. 使用扩展名方式, 语法 *.xxxx , xxxx是自定义的扩展名。 常用的方式 *.do, *.action, *.mvc等等
不能使用 *.jsp
http://localhost:8080/myweb/some.do
http://localhost:8080/myweb/other.do 2.使用斜杠 "/"
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>

【SpringMVC】 4.3 拦截器的更多相关文章

  1. 9.springMVC中的拦截器

    springMVC中的拦截器大概大致可以分为以下几个步骤去学习: 1.自定义一个类实现HandlerInterceptor接口,这里要了解其中几个方法的作用 2.在springMVC的配置文件中添加拦 ...

  2. springMVC的全局拦截器

    先说说为什么要使用springMVC的全局拦截器,比如 当我们在访问接口的时候,我们一般都会先判断这个用户是否登陆,我们就要在每个接口的前面都要判断一下,想想是不是很蛋疼,那工作量... 这时候,我们 ...

  3. SpringMVC中的拦截器、过滤器的区别、处理异常

    1. SpringMVC中的拦截器(Interceptor) 1.1. 作用 拦截器是运行在DispatcherServlet之后,在每个Controller之前的,且运行结果可以选择放行或拦截! 除 ...

  4. 【SpringMVC学习11】SpringMVC中的拦截器

    Springmvc的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理.本文主要总结一下springmvc中拦截器是如何定义的,以及测试拦截器的执行情况和使用 ...

  5. SpringMVC 学习笔记(拦截器的配置))

    在设置SpringMVC的拦截器时,需要在SpringMVC中配置 拦截器对象,拦截器的的对象要 实现 HandlerInterceptor 接口 拦截器类的设置: public class inte ...

  6. (转)SpringMVC学习(十二)——SpringMVC中的拦截器

    http://blog.csdn.net/yerenyuan_pku/article/details/72567761 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter, ...

  7. SpringMVC(AbstractController,拦截器,注解)

    1.Controller接口及其实现类 Controller是控制器/处理器接口,只有一个方法handleRequest,用于进行请求的功能处理(功能处理方法),处理完请求后返回ModelAndVie ...

  8. SpringMVC 自定义一个拦截器

    自定义一个拦截器方法,实现HandlerInterceptor方法 public class FirstInterceptor implements HandlerInterceptor{ /** * ...

  9. SpringMvc中Interceptor拦截器用法

    SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户是否登陆等. 一. 使用场景 1 ...

  10. 关于springmvc 方法注解拦截器的解决方案,多用于方法的鉴权

    最近在用SpringMvc写项目的时候,遇到一个问题,就是方法的鉴权问题,这个问题弄了一天了终于解决了,下面看下解决方法 项目需求:需要鉴权的地方,我只需要打个标签即可,比如只有用户登录才可以进行的操 ...

随机推荐

  1. 【有趣的全彩LED | 编程】用STM32 HAL库让WS2812B为你所动

    一.效果展示 观看演示效果:https://www.bilibili.com/video/BV1dv411Y7x3 使用STM32 HAL库编程 PWM+DMA控制输出,CubeMX生成初始工程 实现 ...

  2. jvm系列五-java内存模型(2)

    原作者系列文章链接:并发编程系列博客传送门 前言# 在网上看了很多文章,也看了好几本书中关于JMM的介绍,我发现JMM确实是Java中比较难以理解的概念.网上很多文章中关于JMM的介绍要么是照搬了一些 ...

  3. Linux 防火墙相关操作

    目录 1.查看防火墙状态 2.部署防火墙 3.常用操作 4.其他操作 1.查看防火墙状态 systemctl status firewalld 绿字部分 Active:active(running) ...

  4. [CF套题] CF-1201

    CF-1201 传送门 # = * A 500 B 1000 C 1500 D 2000 E1 2000 E2 1000 1 (2217) 1672 482 00:09 400 01:40 790 0 ...

  5. Luogu T16048 会议选址

    本题idea版权来自CSDN博客Steve_Junior的医院设置2. 并没有什么用的链接 题目背景 \(A\)国的国情十分独特.它总共有\(n\)个城市,由\(n-1\)条道路连接.国内的城市当然是 ...

  6. Codeforces Round #654 (Div. 2) D. Grid-00100 (构造)

    题意:构造一个\(n\)x\(n\)只含\(0\)和\(k\)个\(1\)的矩阵,统计每一行每一列\(1\)的sum,然后构造一个权值最大行和最小行的差的平方加权值最大列和最小列的差的平方的最小和(\ ...

  7. Vue的七种传值方式

    目录 1,父传子 2,子传父 3,兄弟组件传值 4,父组件使用子组件的数据和方法 5,子组件使用父组件的数据和方法 6,Vuex传值 6.1,定义store 6.2,挂载 6.3,使用 7,路由传值 ...

  8. Databricks 第11篇:Spark SQL 查询(行转列、列转行、Lateral View、排序)

    本文分享在Azure Databricks中如何实现行转列和列转行. 一,行转列 在分组中,把每个分组中的某一列的数据连接在一起: collect_list:把一个分组中的列合成为数组,数据不去重,格 ...

  9. C#中word导出功能骚操作

    马上过牛年了,先祝大家新年好,身体好,心情好!!! 年前最后写一篇之前项目开发的一个功能,自己根据系统业务,想到的一个解决办法,效率还是不错的,废话不多说,开整!!! 需求:企业填报自己的企业信息到系 ...

  10. XV6学习(16)Lab net: Network stack

    最后一个实验了,代码在Github上. 这一个实验其实挺简单的,就是要实现网卡的e1000_transmit和e1000_recv函数.不过看以前的实验好像还要实现上层socket相关的代码,今年就只 ...