
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。
🍎个人主页:Java Fans的博客
🍊个人信条:不迁怒,不贰过。小知识,大智慧。
💞当前专栏:SSM 框架从入门到精通
✨特色专栏:国学周更-心性养成之路
🥭本文内容:一文学会 SpringMVC 拦截器
文章目录

SpringMVC 的拦截器 Interceptor 的主要用来拦截指定的用户请求,并进行相应的预处理或后处理。它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登录等操作。
其拦截的时间点是在处理器适配器执行处理器之前。创建拦截器类需要实现 HandlerInterceptor 接口,然后在配置文件中注册并指定拦截目标。
对于 SpringMVC 拦截器的定义方式有两种:
目录结构:

为了便于下面知识结构的讲解,先创建好未使用拦截器的项目,步骤如下:
【1】创建 spring-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: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 http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--逻辑视图前缀-->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!--逻辑视图后缀,匹配模式:前缀+逻辑视图+后缀,形成完整路径名-->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置组件扫描器 -->
<context:component-scan base-package="cn.hh.springmvc03"/>
</beans>
【2】创建 User 实体类,代码如下:
package cn.hh.springmvc03.entity;
import lombok.Data;
@Data
public class User {
String username;
String password;
}
项目案例:创建第一个拦截器。
实现步骤:
【1】新建处理器 UserController,添加方法如下:
//测试拦截器
@RequestMapping("/test1.do")
public String doTestInterceptor(){
System.out.println("执行了处理器的方法!");
return "welcome";
}
【2】新建包 cn.hh.springmvc03.intercepter,在包下新建一个自定义拦截器类 Intercepter1,实现 HandlerInterceptor 接口,重写以下3个方法,代码如下:
package cn.hh.springmvc03.intercepter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class Intercepter1 implements HandlerInterceptor{
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception arg3)
throws Exception {
System.out.println("执行了Intercepter1 ----------afterCompletion");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
System.out.println("执行了Intercepter1 ----------postHandle");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行了Intercepter1 ----------preHandle");
return true;
}
}
自定义拦截器,需要实现HandlerInterceptor接口,实现该接口中的以下三个方法:
拦截器中方法与处理器方法的执行顺序如图所示。

也可以这样来看 ,如下图:

【3】在 spring-config.xml 配置文件中注册拦截器,代码如下:
<!-- 注册拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.hh.springmvc03.intercepter.Intercepter1"/>
</mvc:interceptor>
</mvc:interceptors>
【4】运行测试,则控制台输出如下:
执行了Intercepter1 ----------preHandle
执行了处理器的方法!
执行了Intercepter1 ----------postHandle
执行了Intercepter1 ----------afterCompletion
项目案例: 创建多个拦截器。(在上面案例的基础上编写以下代码)
【1】创建Intercepter2,代码如下所示:
package cn.hh.springmvc03.intercepter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class Intercepter2 implements HandlerInterceptor{
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception arg3)
throws Exception {
System.out.println("执行了Intercepter2----------afterCompletion");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
System.out.println("执行了Intercepter2----------postHandle");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行了Intercepter2----------preHandle");
return true;
}
}
【2】在 spring-config.xml 文件中注册多个拦截器,代码如下:
<!-- 注册多个拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.lifeng.intercepter.Intercepter1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.lifeng.intercepter.Intercepter2"/>
</mvc:interceptor>
</mvc:interceptors>
【3】运行测试,则控制台输出如下:
执行了Intercepter1 ----------preHandle
执行了Intercepter2 ----------preHandle
执行了处理器的方法!
执行了Intercepter2 ----------postHandle
执行了Intercepter1 ----------postHandle
执行了Intercepter2 ----------afterCompletion
执行了Intercepter1 ----------afterCompletion
当有多个拦截器时,形成拦截器链。拦截器的执行顺序与其注册顺序一致。需要再次强调一点的是当某一个拦截器的 preHandle() 方法返回 true 并被执行到时,会向一个专门的方法栈中放入该拦截器的 afterCompletion() 方法。
多个拦截器方法与处理器方法的执行顺序如下图所示:

只要有一个 preHandler() 方法返回 false,则上部的执行链将被断开,其后续的处理器方法与 postHandle() 方法将无法执行。但无论执行链执行情况怎样,只要方法栈中有方法,即执行链中只要有 preHandle() 方法返回 true,就会执行方法栈中的 afterCompletion() 方法,最终都会给出响应。
项目案例: 只有经过登录的用户方可访问处理器,否则,将返回“无权访问”提示。 本例的登录,由一个 JSP 页面完成。即在该页面里将用户信息放入 session 中。也就是说,只要访问过该页面,就说明登录了。没访问过,则为未登录用户。
实现步骤:
【1】web.xml 代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!--配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config.xml</param-value>
</init-param>
<!--tomcat启动就创建该实例对象-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
【2】spring-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: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 http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--实现更加强大的功能,支持json数据格式的解析-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--第5步:配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀配置-->
<property name="prefix" value="/"></property>
<!--后缀配置-->
<property name="suffix" value=".jsp"></property>
</bean>
<!--第6步:开启包扫描 base-package 设置需要扫描的包 -->
<context:component-scan base-package="cn.kgc.springmvc03"></context:component-scan>
<!--静态资源的处理 不需要经过前端控制器 tomcat-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/user/login"/>
<mvc:exclude-mapping path="/user/getcode"/>
<bean class="cn.kgc.springmvc03.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
<!--配置文件上传组件-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
</beans>
【3】UserController 类中添加登陆方法,代码如下:
//登陆
@RequestMapping("login")
@ResponseBody
public Map<String,Object> login(User user, HttpSession session,@SessionAttribute("code") String attribute){
HashMap<String, Object> map = new HashMap<>();
System.out.println("--------login方法-------"+attribute);
if(user.getCode().equals(attribute)){//验证码填写正确
if("tom".equals(user.getUsername())&&"123456".equals(user.getPassword())){//账号密码正确
session.setAttribute("user",user);
map.put("code",200);
map.put("msg","登陆成功");
}else{//账号密码不正确
map.put("code",500);
map.put("msg","登陆失败");
}
}else{//验证码填写不正确
map.put("code",500);
map.put("msg","验证码输入不正确");
}
return map;
}
【4】添加拦截器 LoginInterceptor 代码如下:
package cn.kgc.springmvc03.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("-------------preHandle方法--------------");
HttpSession session = request.getSession();
Object user = session.getAttribute("user");
if(user==null){
response.sendRedirect("/login.jsp");
return false;
}
return true;
}
}
【5】添加前端页面 login.jsp 代码如下:
<%--
Created by IntelliJ IDEA.
User: hhzb100
Date: 2023/3/2
Time: 9:35
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="jquery-1.11.1.js"></script>
<script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<form>
<p><input type="text" name="username" placeholder="请输入用户名" id="username"></p>
<p><input type="password" name="password" placeholder="请输入密码" id="password"></p>
<p><input type="text" name="code" placeholder="请输入验证码" id="code"></p>
<p><input type="button" value="登录" id="login"></p>
</form>
<span id="msg" style="color: red"></span>
</body>
<script>
$("#login").click(function () {
let username=$("#username").val()
let password = $("#password").val()
let code = $("#code").val()
$.get("/user/login",{username,password,code},function (res) {
if(res.code=200){
window.location.href="/main.jsp"
}else{
let info = res.msg
$("#msg").text(info)
}
})
});
</script>
</html>
【6】运行测试
码文不易,本篇文章就介绍到这里,如果想要学习更多Java系列知识,点击关注博主,博主带你零基础学习Java知识。与此同时,对于日常生活有困扰的朋友,欢迎阅读我的第四栏目:《国学周更—心性养成之路》,学习技术的同时,我们也注重了心性的养成。

使用Ruby1.8.6/Rails2.3.2我注意到在我的任何ActiveRecord模型类上调用的任何方法都返回nil而不是NoMethodError。除了烦人之外,这还破坏了动态查找器(find_by_name、find_by_id等),因为即使存在记录,它们也总是返回nil。不从ActiveRecord::Base派生的标准类不受影响。有没有办法追踪在ActiveRecord::Base之前拦截method_missing的是什么?更新:切换到1.8.7后,我发现(感谢@MichaelKohl)will_paginate插件首先处理method_missing。但是will_pa
一文解决关于VLAN所有的疑惑VLAN基本概念为什么需要VLAN?怎么在交换机上划分VLAN,VLAN的工作原理有了子网,已经隔离了广播,还需要VLAN干啥?只进行子网划分,不进行VLAN划分VLAN划分与子网划分附加VLAN信息的方法VLAN划分交换机的端口类型(Access和Trunk)一、访问链接二、汇聚链接汇聚链接VLAN间通信为什么要进行VLAN间通信?路由器实现VLAN间通信路由器和交换机的连接方式通信细节三层交换机实现VLAN间通信加速VLAN间通信三层交换机与路由器三层交换机路由器路由器和交换机配合构建LAN的实例使用VLAN设计局域网的特点VLAN增加网络的灵活性不使用VLA
✅作者简介:大家好,我是小杨📃个人主页:「小杨」的csdn博客🔥系列专栏:小杨带你玩转C语言【初阶】🐳希望大家多多支持🥰一起进步呀!大家好呀!我是小杨。小杨花几天的时间将C语言中的操作符这部分知识做了一个大总结,在方便自己复习的同时也能够帮助到大家。通篇字数在一万字左右,可以算作是非常详细了,一文就可以带领大家彻底掌握操作符这部分内容,文章很长建议先收藏再看,防止下次想看就找不到啦。文章目录✍1,算术操作符✍2,移位操作符 🔍2.1,左移操作符 🔍2.2,右移操作符 ✨2.2.1,算术移位 ✨2.2.2,逻辑移位✍3,位操作符 🔍3.1,按位与&
我目前有一个父类(superclass),它有一个函数,我希望所有子类在它的每个函数中调用该函数。该函数的行为应该像rails中的before_filter函数,但我不确定如何去实现before_filter。这是一个例子classSuperclassdefbefore_each_methodputs"BeforeMethod"#thisissupposedtobeinvokedbyeachextendingclass'methodendendclassSubclass 最佳答案 这是一种方法:classSuperclassdefb
每个企业都希望在完成项目后获得盈利,但不少企业到了年终后才发现项目做了不少,公司却并没能达到预期,甚至还出现了亏损。那么钱究竟去了哪里?很多公司都搞不清楚原因,出现糊涂账较多的状况,这将会造成严重的后果,尤其在疫情影响下,大环境很恶劣,如果是大公司的事业部门出现亏损,就可能会导致事业部门解散;如果是小公司出现亏损,就很容易导致公司倒闭;怎样做才能确保我们所完成的项目都能获利?从财务角度看,要确保盈利必须做到合理估算成本,只有这样才能在对外签订合约时做出合理报价,在对内在开始项目前做出充分评估投入代价,同时在实施过程中还要控制成本得当,最后项目结束时才会有可能获得盈利。那么我们怎样才能准确的判断
我正在使用rails3.0.3、ruby1.9.2-p180、邮件(2.2.13)。我正在尝试设置邮件拦截器,但出现以下错误/home/abhimanyu/Aptana_Studio_3_Workspace/delivery_health_dashboard_03/config/initializers/mailer_config.rb:16:in`':uninitializedconstantDevelopmentMailInterceptor(NameError)我该如何解决?我使用的代码如下所示:config/initializer/mailer_config.rbActionM
COINDAO旨在重建社区信任和安全。基于皖北基因的强烈共识,COINDAO自发产生了一个共创、共建、共治、共享的协作组织。它专注于DAO投资管理协议,为新的优质项目创造增长技术和资金。COINDAO的使命就是为真正的优质项目打造一个去中心化、公开透明的平台,让各个赛道上的优质项目能够以更低的成本快速募集资金并向公众开放.打破头部垄断。让真正的爱好者直接获得早期参与优质项目的资格,不再遥不可及,构建生态应用的可信体系,打造人人参与共建、人人共享的去中心化DAO好处。生态系统,我们称之为COINDAO生态系统。COINDAO国内各大财经网站宣发如下:COINDAO国外各大财经网站宣发: COIN
今天来说说前端低代码有多幸福?低代码是啥?顾名思义少写代码……这种情况下带来的幸福有:代码写得少,bug也就越少(所谓“少做少错”),因此开发环节的两大支柱性工作“赶需求”和“修bug”就都少了;要测的代码少了,那么测试用例也可以少写了。所以,总结低代码带来的幸福感有这三大点:开发效率提高开发成本减少维护性更高针对上述三点,我们展开说说。01、开发效率提高对于低代码的理解,个人认为可以通过配置化的低成本交互方式(主流是拖拽)加上少量的胶水代码,去满足一类应用的需求。这就说明,基于低代码,开发人员无需代码或说只需少量代码就可以开发出各类应用管理系统,如:OA协同办公、KM知识管理、CRM客户关系
我的angular-cli(v1.5.1,angularv5)应用程序中有以下两个环境:开发产品Dev使用模拟数据,我提供了一个http拦截器。Pro使用实时休息api。我如何在dev上提供http拦截器,而不是在pro上?我已经尝试了以下方法,但它不起作用:{provide:HTTP_INTERCEPTORS,useFactory:()=>{if(environment.useMockBackend===true){returnMockHttpInterceptor;}returnfalse;},multi:true} 最佳答案
我正在使用Capybara、Cucumber和Poltergeist。我正在测试附加到表单提交按钮的JavaScript函数,该函数旨在捕获提交事件并阻止它(在后台执行AJAX请求)。使用和不使用AJAX,页面最终看起来都一样,但AJAX方法要快得多,并且不会中断浏览体验等。我可以做些什么来测试表单确实没有提交,并且更改是动态AJAX调用而不是重新加载的结果? 最佳答案 @jules答案的修改版本:describe"Mypage",:jsdoit"reloadswhenitshould"dovisit"/"expect_page_t