- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
拦截器
(Interceptor)主要是针对特定处理器进行拦截的。也就是说它拦截的对象是我们的Controller请求。我们可以将Controller中的通用代码进行抽取放在拦截器中,就这一点来讲功能跟我们之前讲的AOP类似(Interceptor底层就是利用AOP来实现的)。在实际开发中Interceptor通常用来做权限校验(现在都有成熟的权限校验框架。比如轻量级的Shiro
,还有Spring推出的Spring Security
)
拦截器
(Interceptor)实现对每一个请求处理前后进行相关的业务处理,类似与servlet中的Filter。
SpringMVC 中的 Interceptor 拦截请求是通过 HandlerInterceptor 接口来实现的。
拦截器可以通过以下几种方式进行实现:
在上一节SpringBoot.11.IDEA中如何快速复制当前父项目中的一个Module为新的项目中我们已经准备好了Module – springboot-08-interceptor
。如下图所示:
package com.christy.config.interceptors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义拦截器
* @Author Christy
* @Date 2021/9/28 10:20
**/
public class MyInterceptor01 implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(MyInterceptor01.class);
/**
*
* @author Christy
* @date 2021/9/28 10:22
* @param request
* @param response
* @param handler 当前请求请求的控制器方法对象 InterceptorController#sayHello
* @return boolean
* true:表示放行当前请求
* false:终端当前请求 例如做权限校验时如果校验不通过我们可以使用response.sendRedirect(request.getContextPath()+"/login.suffix");跳转到登录界面
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("==========MyInterceptor01==========handler=========" + handler);
log.info("==========MyInterceptor01==========preHandle=========");
return true;
}
/**
*
* @author Christy
* @date 2021/9/28 10:28
* @param request
* @param response
* @param handler 当前请求请求的控制器方法对象 InterceptorController#sayHello
* @param modelAndView 模型和视图 当前请求访问方法的 modelandview 对象
* @return void
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("==========MyInterceptor01==========postHandle=========");
}
/**
*
* @author Christy
* @date 2021/9/28 10:29
* @param request
* @param response
* @param handler 当前请求请求的控制器方法对象 InterceptorController#sayHello
* @param ex 如果控制器出现异常时异常对象
* @return void
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("==========MyInterceptor01==========ex========={}", ex);
log.info("==========MyInterceptor01==========afterCompletion=========");
}
}
我们进入到MyWebMvcConfigurer.java
中,按快捷键Alt+Insert
,选择Implement Methods…
或者直接按快捷键Alt+Shift+P
。如下图所示:
在Select Methods to Implement
中选择addIntefceptors()
这个方法。如下图所示:
修改MyWebMvcConfigurer.java
内容如下所示:
import com.christy.config.interceptors.MyInterceptor01;
import com.christy.constants.FileConstants;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author Christy
* @Date 2021/9/15 16:24
**/
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
/**
* 配置拦截器
* addInterceptor(): 指定拦截器
* addPathPatterns("/**"):拦截所有Controller请求
* excludePathPatterns("/file/**"):排除文件操作的请求路径
* order():指定拦截器执行顺序 int 类型数字: 默认按照自然排序执行 数字相同时,按照配置顺序执行
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor01())
.addPathPatterns("/interceptor/**")
.excludePathPatterns("/file/**")
.order(1);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/**
* 文件上传到服务器后并不能在项目中直接访问,需要将磁盘路径映射成虚拟路径使用http://domain/的方式才可以
*/
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")){
// Windows虚拟路径映射本地磁盘
registry.addResourceHandler(FileConstants.fileVirtualPath + "**").addResourceLocations("file:" + FileConstants.fileWindowsPath);
} else {
// Linux虚拟路径映射本地磁盘
registry.addResourceHandler(FileConstants.fileVirtualPath + "**").addResourceLocations("file:" + FileConstants.fileLinuxPath);
}
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author Christy
* @Date 2021/9/28 10:44
**/
@RestController
@RequestMapping("/interceptor")
public class InterceptorController {
private static final Logger log = LoggerFactory.getLogger(InterceptorController.class);
@RequestMapping("sayHello")
public String sayHello(){
log.info("Hello Interceptor…");
return "interceptor";
}
}
启动项目,浏览器访问http://localhost:8808/interceptor/sayHello
,注意观察页面和控制台输出:
我们改造一下sayHello()
方法抛出一个异常,如下所示:
@RequestMapping("sayHello")
public String sayHello(){
log.info("Hello Interceptor…");
int i = 1/0;
return "interceptor";
}
重新启动项目,浏览器访问http://localhost:8808/interceptor/sayHello
,注意观察页面和控制台输出:
我们修改一下MyInterceptor01.java
如下:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义拦截器
* @Author Christy
* @Date 2021/9/28 10:20
**/
public class MyInterceptor01 implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(MyInterceptor01.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("==========MyInterceptor01==========1=========");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("==========MyInterceptor01==========2=========");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("==========MyInterceptor01==========3=========");
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义拦截器
* @Author Christy
* @Date 2021/9/28 10:20
**/
public class MyInterceptor02 implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(MyInterceptor02.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("==========MyInterceptor02==========4=========");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("==========MyInterceptor02==========5=========");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("==========MyInterceptor02==========6=========");
}
}
import com.christy.config.interceptors.MyInterceptor01;
import com.christy.config.interceptors.MyInterceptor02;
import com.christy.constants.FileConstants;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author Christy
* @Date 2021/9/15 16:24
**/
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
/**
* 配置拦截器
* addInterceptor(): 指定拦截器
* addPathPatterns("/**"):拦截所有Controller请求
* excludePathPatterns("/file/**"):排除文件操作的请求路径
* order():指定拦截器执行顺序 int 类型数字: 默认按照自然排序执行 数字相同时,按照配置顺序执行
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor01())
.addPathPatterns("/interceptor/**")
.excludePathPatterns("/file/**")
.order(1);
registry.addInterceptor(new MyInterceptor02())
.addPathPatterns("/interceptor/**")
.excludePathPatterns("/file/**")
.order(2);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/**
* 文件上传到服务器后并不能在项目中直接访问,需要将磁盘路径映射成虚拟路径使用http://domain/的方式才可以
*/
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")){
// Windows虚拟路径映射本地磁盘
registry.addResourceHandler(FileConstants.fileVirtualPath + "**").addResourceLocations("file:" + FileConstants.fileWindowsPath);
} else {
// Linux虚拟路径映射本地磁盘
registry.addResourceHandler(FileConstants.fileVirtualPath + "**").addResourceLocations("file:" + FileConstants.fileLinuxPath);
}
}
}
重新启动项目,浏览器访问http://localhost:8808/interceptor/sayHello
,注意观察控制台输出:
多个拦截器注册以后按照注册的顺序以栈
式结构存储,上面我们配置了两个拦截器,MyInterceptor01
先入栈,MyInterceptor02
后入栈;所以当请求来了之后:
首先,进入MyInterceptor01
的preHandle打印输出1,再进入MyInterceptor02
的preHandle打印输出4;这是一个入栈
的过程
其次访问方法主体打印输出方法体内的logger
然后,进入MyInterceptor02
的postHandle打印输出5,再进入MyInterceptor01
的postHandle打印输出2;这是一个出栈
的过程
最后,进入MyInterceptor02
的afterCompletion打印输出6,再进入MyInterceptor01
的afterCompletion打印输出3;这也是一个出栈
的过程
按照上面的描述如果我们更换两个拦截器的顺序,让MyInterceptor02
先入栈,MyInterceptor01
后入栈;那么打印的结果应该是4->1->2->5->3->6
。
我们修改MyWebMvcConfigurer.java
的代码更换两个拦截器的顺序如下:
import com.christy.config.interceptors.MyInterceptor01;
import com.christy.config.interceptors.MyInterceptor02;
import com.christy.constants.FileConstants;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author Christy
* @Date 2021/9/15 16:24
**/
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
/**
* 配置拦截器
* addInterceptor(): 指定拦截器
* addPathPatterns("/**"):拦截所有Controller请求
* excludePathPatterns("/file/**"):排除文件操作的请求路径
* order():指定拦截器执行顺序 int 类型数字: 默认按照自然排序执行 数字相同时,按照配置顺序执行
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor01())
.addPathPatterns("/interceptor/**")
.excludePathPatterns("/file/**")
.order(2);
registry.addInterceptor(new MyInterceptor02())
.addPathPatterns("/interceptor/**")
.excludePathPatterns("/file/**")
.order(1);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/**
* 文件上传到服务器后并不能在项目中直接访问,需要将磁盘路径映射成虚拟路径使用http://domain/的方式才可以
*/
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")){
// Windows虚拟路径映射本地磁盘
registry.addResourceHandler(FileConstants.fileVirtualPath + "**").addResourceLocations("file:" + FileConstants.fileWindowsPath);
} else {
// Linux虚拟路径映射本地磁盘
registry.addResourceHandler(FileConstants.fileVirtualPath + "**").addResourceLocations("file:" + FileConstants.fileLinuxPath);
}
}
}
然后重启项目,浏览器访问http://localhost:8808/interceptor/sayHello
,注意观察控制台输出:
我刚开始使用新的拦截方法,有一个基本问题,想知道如何在一个测试中链接下面的两个断言。 cy.intercept('GET', '/states').as('states'); cy.reload(tr
我有一个标签控件的自定义版本(使用用户控件构建)。在设计器中工作时,我想截取 Name 属性的设置(在属性面板中)并使用它来生成 Text 属性。也就是说,如果我在属性面板的 Name 属性中输入“l
嗨,我想通过 soapUI 解析 ssl soap 消息,而我试图通过 HttpMonitor 进行拦截它显示在异常下方 ERROR:Exception in request: javax.net.s
是否有可能从某个任意层拦截反向梯度,修改其值并继续反向传播回到网络的开始,根据您提供的修改后的梯度值更新所有先前层的反向梯度? 我知道你可以directly modify the gradients
我可以从什么 dll 中获得 Intercept 的扩展?我从 http://github.com/danielmarbach/ninject.extensions.interception 添加了
我有一个实现 onCreateOptionsMenu 方法的顶级 TabHost。我希望子 Activity (选项卡内的子 Activity )能够通过 onOptionsItemSelected
我在尝试反序列化 URL 时遇到此错误 Caused by: java.net.MalformedURLException: no protocol: www.boo.com at java.
首先,我是 Spring 的新手,这是我第一次尝试使用 Spring 编写基于 REST 的应用程序。 我计划在请求参数和响应中使用 Json。这让我想到两个问题。 有没有办法将 products="
在我基于 j_security_check 的登录表单中登录时一切正常。在这种情况下,我看到 JSESSIONID cookie 中的路径具有来自 URL 的值。但是当另一个登录页面构造动态表单(它正
我有一个我一直致力于下载文件的程序。一切正常,除非用户使用 AVG。奇怪的是,为了解决这个问题,似乎必须禁用 AVG 的“电子邮件保护”;将我的程序或 JRE 添加到异常(exception)列表不起
我正在寻找一种方法来挂接 SMSManager 或较低级别的机制,以便我可以在发送任何外发 SMS 消息之前拦截、读取和取消它们。 最佳答案 迟到总比不到好:) 我已经在这上面花了 2 天...并且不
我已成功拦截对 read() 的调用, write() , open() , unlink() , rename() , creat()但不知何故截获完全相同的语义stat()没有发生。我已经使用 L
阿里云ECS通过安全组屏蔽/拦截/阻断特定IP对云服务器的访问 所适用的场景: 通过安全组屏蔽、拦截、阻止特定IP对用户云服务器的访问,或者屏蔽IP访问服务器的特定端口。 配置的方法: 1、
我希望能够在类本身的构造函数中代理类的所有方法。 class Boy { constructor() { // proxy logic, do something before
使用 ajax 请求可以使用以下代码完成: let oldXHROpen = window.XMLHttpRequest.prototype.open; window.lastXhr = ''; wi
我想“拦截”/更改将 OData 与 Web API 一起使用时生成的 OData 查询..但我不完全确定如何“提取”生成的查询..我假设 OData 过滤器、扩展和更多一些如何生成某种表达式树或某种
当 JUnit 中的断言失败时,我想做一些“自己的事情”。我想要这个: public class MyAssert extends org.junit.Assert { // @Overrid
如何拦截 PartialFunction?例如在 Actor 中,如果我只想打印进入以下接收方法的所有内容,然后再将其传递给流程方法: class MyActor extends Actor {
我们正在使用 fluentvalidation(带有服务堆栈)来验证我们的请求 DTO。我们最近扩展了我们的框架以接受“PATCH”请求,这意味着我们现在需要仅在补丁包含要验证的字段时才应用验证。 我
我有一个作为 excel 插件运行的 WPF 应用程序,它有这样的可视化树 精益求精 元素主机 WPF 用户控件 WPF 色带条控件 现在,在 excel 中加载插件时,不会启用位于 WPF 功能区栏
我是一名优秀的程序员,十分优秀!