SpringMVC一步到位精通 *
作者:Hhzzy99 发布时间:2023-11-25 01:47:45
前言
在上一篇文章中讲完了SpringMVC的大部分知识,此篇文章中主要讲解 * 。上一篇文章🚩
* 的使用是非常普遍的。例如在 OA系统中通过 * 可以拦截未登录的用户,或者使用它来验证己登录用户是否有相应的操作权限等。SpringMVC
中提供了 * 功能,通过配置即可对请求进行拦截处理。
* 概述
SpringMVC 中的 * (Interceptor
)类似于 Servlet 中的过滤器(Filter
),它主要用于拦截用户请求并做相应的处理。例如通过 * 可以进行权限验证、判断用户是否己登录等。
* 的定义
要使用SpringMVC中的 * ,就需要对 * 类进行定义和配置。通常 * 类可以通过两种方式来定义:
一种是通过实现
HandlerInterceptor
接口或者继承HandlerInterceptor
接口的实现类(如HandlerInterceptorAdapter
)来定义。另一种是通过实现
WebRequestInterceptor
接口或继承WebRequestInterceptor
接口的实现类来定义。
实现HandlerInterceptor
接口的定义方式为例,自定义 * 类的代码如下所示:
public class UserInterceptor implements HandlerInterceptor {
public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {
System.out.println("UserInterceptor...preHandle");
//对拦截的请求进行放行处理(true为放行,false为不放行)
return true;
}
public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("UserInterceptor...postHandle");
}
public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("UserInterceptor...afterCompletion");
}
}
从上述代码可以看出,自定义的 * 类实现了 HandlerInterceptor
接口,并实现了接口中的3 个方法。关于这3个方法的具体描述如下:
preHandle()
方法:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true
时,表示继续向下执行; 当其返回值为false
时,会中断后续的所有操作(包括调用下一个 * 和控制器类中的方法执行等)。postHandle()
方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。afterCompletion()
方法:该方法在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
* 的配置
要使自定义的 * 类生效,需要在SpringMVC的配置文件中进行配置,配置代码如下:
<!--配置 * -->
<mvc:interceptors>
<!--使用bean直接定义在<mvc:interceptor>下面的Interceptor 将拦截所有请求-->
<bean class="com.hzy.interceptor.UserInterceptor"/>
<!-- * 1-->
<mvc:interceptor>
<!--配置 * 作用的路径-->
<mvc:mapping path="/**"/>
<!--配置不需要 * 作用的路径-->
<mvc:exclude-mapping path=""/>
<!--定义在<mvc:interceptor>下面,表示对匹配路径的请求才进行拦截-->
<bean class="com.hzy.interceptor.Interceptor1"/>
</mvc:interceptor>
<!-- * 2-->
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean class="com.hzy.interceptor.Interceptor2"/>
</mvc:interceptor>
......
</mvc:interceptors>
在上述代码中, <mvc:interceptors>
元素用于配置一组 * ,其子元素<bean>
中定义的是全局 * ,它会拦截所有的请求;而<mvc:interceptor>
元素中定义的是指定路径的 * ,它会对指定路径下的请求生效。<mvc:interceptor>
元素的子元素<mvc:mapping>
用于配置 * 作用的路径,该路径在其属性 path
中定义。如上述代码中 path
的属性值 “/**”
表示拦截所有路径, “/hello”
表示拦截所有以“hello”
结尾的路径。如果在请求路径中包含不需要拦截的内容,还可以通过 <mvc:exclude-mapping>
元素进行配置。
* 的执行流程
* 的执行是有一定顺序的,该顺序与配置文件中所定义的 * 的顺序相关。
单个 * 的执行流程
如果在项目中只定义了一个 * ,那么该 * 在程序中的执行流程如下图所示。从中可以看出,程序首先会执行 * 类中的 preHandle()
方法,如果该方法的返回值为 true
,则程序就会继续向下执行处理器中的方法,否则将不再向下执行:在业务处理器(即控制器Controller
类)处理完请求后,会执行 postHandle()
方法,然后通过 DispatcherServlet
向客户端返回响应;在 DispatcherServlet
处理完请求后,才会执行 afterCompletion()
方法。
简单的案例
web.xml中配置SpringMVC的前端过滤器和初始化加载配置文件等信息。
<?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_3_1.xsd"
version="3.1">
<servlet>
<!--配置前端过滤器-->
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--初始化时加载配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<!--表示容器在启动时立即加载Servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在src下创建com.hzy.controller包,并在里面创建控制器类HelloController
,
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(){
System.out.println("Hello");
return "success";
}
}
在src下创建com.hzy.interceptor包,并在里面创建 * 类UserInterceptor
,该类需要实现HandlerInterceptor
接口。
public class UserInterceptor implements HandlerInterceptor {
public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {
System.out.println("UserInterceptor...preHandle");
//对拦截的请求进行放行处理(true为放行,false为不放行)
return true;
}
public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("UserInterceptor...postHandle");
}
public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("UserInterceptor...afterCompletion");
}
}
在resources目录下创建springmvc-config.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:mvc="http://www.springframework.org/schema/mvc"
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
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.hzy.controller"/>
<!--定义视图解析器-->
<bean id="internalResourceViewResolve"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--设置前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--设置后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<mvc:annotation-driven/>
<!--配置 * -->
<mvc:interceptors>
<!--使用bean直接定义在<mvc:interceptor>下面的Interceptor 将拦截所有请求-->
<bean class="com.hzy.interceptor.UserInterceptor"/>
</mvc:interceptors>
</beans>
在WEB-INF目录下创建一个jsp文件夹,并在里面创建一个页面文件success.jsp,然后在<body>
里面显示任意信息。发布并启动项目,访问http://localhost:8080/springMvc_SSM/hello (注意你的访问路径可能和我不一样哦)
结果:
控制台
多个 * 的执行流程
在大型项目中,通常会定义很多 * 来实现不同的功能。多个 * 的执行顺序如图所示。这里假设有两个 * Interceptor1
和 Interceptor2
,并且在配置文件中,Interceptor1
* 配置在前。
从图上可以看出,当有多个 * 同时工作时,它们的preHandle()
方法会按照配置文件中 * 的配置顺序执行,而它们的postHandle()
方法和afterCompletion()
方法则会按照配置顺序的反序执行。
下为了验证上述描述,下面就修改上面的代码来演示多个 * 的执行。
在com.hzy.interceptor包中创建两个 * 类Interceptor1和Interceptor2。
Interceptor1.java
public class Interceptor1 implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Interceptor1...preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor1...postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Interceptor1...afterCompletion");
}
}
Interceptor2.java
public class Interceptor2 implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Interceptor2...preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor2...postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Interceptor2...afterCompletion");
}
}
springmvc-config.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:mvc="http://www.springframework.org/schema/mvc"
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
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.hzy.controller"/>
<!--定义视图解析器-->
<bean id="internalResourceViewResolve"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--设置前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--设置后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<mvc:annotation-driven/>
<!--配置 * -->
<mvc:interceptors>
<!--使用bean直接定义在<mvc:interceptor>下面的Interceptor 将拦截所有请求-->
<bean class="com.hzy.interceptor.UserInterceptor"/>
<!-- * 1-->
<mvc:interceptor>
<!--配置 * 作用的路径-->
<mvc:mapping path="/**"/>
<!--配置不需要 * 作用的路径-->
<!-- <mvc:exclude-mapping path=""/>-->
<!--定义在<mvc:interceptor>下面,表示对匹配路径的请求才进行拦截-->
<bean class="com.hzy.interceptor.Interceptor1"/>
</mvc:interceptor>
<!-- * 2-->
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean class="com.hzy.interceptor.Interceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
上述 * 的配置代码中,第一个 * 会作用于所有路径下的请求,而第二个 * 会作用于“/hello”
结尾的请求。运行项目得到结果:
页面输出跟前面一样。
控制台输出:
从图中可以看出,程序先执行了前面两个 * 类中的preHandle()
方法,这两个方法的执行顺序与配置文件中定义的顺序相同;然后执行了控制器中类中的hello()
方法;最后执行了两个 * 类中的postHandle()
方法和afterCompletion()
方法,且这两个方法的执行顺序与配置文件中所定义的 * 顺序相反。
来源:https://blog.csdn.net/XUHUANGHOST/article/details/128406785


猜你喜欢
- 本文介绍spring-rest接口中的LocalDateTime日期类型转时间戳的方法。具体的代码参照示例项目 https://github
- 一、构造函数构造函数的最大作用就是创建对象时完成初始化,当我们在new一个对象并传入参数的时候,会自动调用构造函数并完成参数的初始化。如下:
- 前言众所周知Java提供File类,让我们对文件进行操作,下面就来简单整理了一下File类的用法。 话不多说了,来一起看看详细的介绍吧1.基
- 一)URL代理请求 该方式请求有两种代理方式。方式一:使用该方式代理之后,之后的所有接口都会使用代理请求// 对http开启全局代理Syst
- 一、java发展史1.java之父:詹姆斯·高家林2.关键时间点:1996年Java(1.0)发布,2004年Java(5.0)发扬光大,2
- 一、连接数据库的配置单独放在一个properties文件中之前,我们是直接将数据库的连接配置信息写在了MyBatis的conf.xml文件中
- 利用C#编写一个计算器。如下图,能够完成基本的四则运算。当然这个程序甚至还不上Windows附件那个自带的多功能计算器。 不过这个
- ReferenceWhy using finalizers is a bad idea当在一个类中使用了另外一个实现了IDisposable
- 之前由于项目需要比较详细地学习了Spring Security的相关知识,并打算实现一个较为通用的权限管理模块。由于项目是前后端分离的,所以
- 本文实例讲述了C#使用Object类实现栈的方法。分享给大家供大家参考,具体如下:Stack类的代码:using System;using
- LeetCode54. 螺旋矩阵 java实现题目难度 中给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,
- 一、项目运行环境配置:Jdk1.8 + Tomcat8.5 + mysql + Eclispe(IntelliJ IDEA,Eclispe,
- namespace ConsoleApplication2 { class Program { static v
- Rsa加密RSA是目前最有影响力的公钥加密算法,RSA也是第一个既能用于数据加密也能用于数字签名的算法。该算法基于一个十分简单的数论事实:将
- 这一节我们将探索选择器(selectors)。选择器提供选择执行已经就绪的任务的能力,这使得多元 I/O 成为可能。就像在第一章中描述的那样
- 本文实例讲述了C#日期格式字符串的相互转换操作。分享给大家供大家参考,具体如下:方法一:Convert.ToDateTime(string)
- 话不多说,上代码: /** * 获取字符串的长度,如果有中文,则每个中文字符计为2位 * @param value
- 前言本文主要学习函数的相关内容。1、函数是什么? * 中对函数的定义:子程序在计算机科学中,子程序(英语:Subroutine, proc
- 这篇文章主要介绍了Java日期与时间类原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参
- 有时您可能想限制可以在参数化类型中用作类型参数的类型。 例如,对数字进行操作的方法可能只希望接受Number或其子类的实例。 这就是有界类型