【Spring Boot】Spring Boot之自定义拦截器
一、拦截器的作用
将通用的代码抽取出来,达到复用的效果。比如可以用来做日志记录、登录判断、权限校验等等
二、如何实现自定义拦截器
1)创建自定义拦截器类并实现HandlerInterceptor类
/**
* @author zhangboqing
* @date 2019-07-28
*/
public class MyInterceptor implements HandlerInterceptor { /**
* 执行Controller方法之前,调用
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //返回false,请求将被拦截。放回true代表放行
return false;
} /**
* 执行Controller方法之后,响应给前端之前,调用
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } /**
* 响应给前端之后,调用
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }
}
2)将我们自已的拦截器注册到注册器中
/**
* @author zhangboqing
* @date 2019-07-28
*
* MVC配置类
*/
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer { /** 创建自定义拦截器实例 */
@Bean
MyInterceptor myInterceptor() {
return new MyInterceptor();
} @Override
public void addInterceptors(InterceptorRegistry registry) { //注册自定义拦截器
registry.addInterceptor(myInterceptor())
//拦截所有请求
.addPathPatterns("/*")
//指定需要过滤的请求地址
// .excludePathPatterns()
;
}
}
三、请求日志记录拦截器实现
import com.alibaba.fastjson.JSON;
import com.talkilla.talkillalexile.common.utils.JodaTimeUtils;
import com.talkilla.talkillalexile.common.utils.RandomCodeUtils;
import com.talkilla.talkillalexile.config.filter.HttpHelperUtils;
import com.talkilla.talkillalexile.config.interceptor.model.PostRequestLogInfoModel;
import com.talkilla.talkillalexile.config.interceptor.model.PreRequestLogInfoModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map; /**
* @author zhangboqing
* @date 2018/10/13
* <p>
* 日志打印拦截
*/
@Slf4j
public class LoggingInterceptor implements HandlerInterceptor { @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//生成这次请求的唯一标识
String requestUUID = RandomCodeUtils.getUUID();
long logStartTime = System.currentTimeMillis(); //记录开始时间
request.setAttribute("logStartTime", logStartTime);
request.setAttribute("requestUUID",requestUUID); //请求日志记录
preRequestLoggin(request,requestUUID);
return true;
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
long logEndTime = System.currentTimeMillis();
long logStartTime = (Long)request.getAttribute("logStartTime");
String requestUUID = (String)request.getAttribute("requestUUID"); //记录整个请求的执行时间
loggingHandleTime(requestUUID,logStartTime,logEndTime);
} private void loggingHandleTime(String requestUUID, long logStartTime, long logEndTime) {
String logInfo = getLoggingHandleTime(requestUUID,logStartTime,logEndTime);
log.info("[请求拦截日志信息]:{}", logInfo);
} private String getLoggingHandleTime(String requestUUID, long logStartTime, long logEndTime) {
PostRequestLogInfoModel build = PostRequestLogInfoModel.builder()
.requestUUID(requestUUID)
.requestTime(JodaTimeUtils.timestampToString(logStartTime / 1000, JodaTimeUtils.DateFormat.DATETIME_FORMAT))
.responseTime(JodaTimeUtils.timestampToString(logEndTime / 1000, JodaTimeUtils.DateFormat.DATETIME_FORMAT))
.handleTime((logEndTime - logStartTime) + "ms").build(); return JSON.toJSONString(build);
} /**
* 请求日志记录
*
* @param request
*/
private void preRequestLoggin(HttpServletRequest request,String requestUUID) {
//获取相关参数
//请求地址
String requestURI = request.getRequestURI();
//请求方法
String method = request.getMethod();
//请求参数
Map<String, String[]> parameterMap = request.getParameterMap();
String bodyString = "";
try {
bodyString = HttpHelperUtils.getBodyString(request);
} catch (IOException e) {
e.printStackTrace();
} String reqestLogInfo = getRequestLogInfo(requestURI, method, parameterMap, bodyString,requestUUID);
log.info("[请求拦截日志信息]:{}", reqestLogInfo);
} private String getRequestLogInfo(String requestURI, String method, Map<String, String[]> getParameterMap, String postBodyString,String requestUUID) { PreRequestLogInfoModel build = PreRequestLogInfoModel.builder()
.requestUUID(requestUUID)
.requestURI(requestURI)
.method(method)
.getParameter(getParameterMap)
.postParameter(postBodyString).build(); return JSON.toJSONString(build);
} }
四、从源码角度去理解拦截器三个方法的执行时机
将代码定位到Spring MVC核心处理类DispatcherServlet的doDispatcher()方法,从标记的1,2,3,4,5可以很清楚的看出下面几点启示
1.启示一:拦截器的preHandle方法是在执行Controller方法之前被调用的
2.启示二:拦截器的postHandle方法是在执行Controller方法之后被调用的,但是再处理响应结果之前
3.启示三:拦截器的afterCompletion方法是在处理响应结果之后执行的,也就是说,在调用afterCompletion方法的时候,响应结果已经返回给前端了,该方法的任何处理都不会影响响应结果
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 1.执行拦截器preHandle()方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 2.实际调用处理程序(Controller的方法)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 3.执行拦截器postHandle()方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 4.处理响应结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 5.执行拦截器afterCompletion()方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
【Spring Boot】Spring Boot之自定义拦截器的更多相关文章
- JavaEE开发之SpringMVC中的自定义拦截器及异常处理
上篇博客我们聊了<JavaEE开发之SpringMVC中的路由配置及参数传递详解>,本篇博客我们就聊一下自定义拦截器的实现.以及使用ModelAndView对象将Controller的值加 ...
- 【第四十章】Spring Boot 自定义拦截器
1.首先编写拦截器代码 package com.sarnath.interceptor; import javax.servlet.http.HttpServletRequest; import ja ...
- Spring boot 自定义拦截器
1.新建一个类实现HandlerInterceptor接口,重写接口的方法 package com.zpark.interceptor; import com.zpark.tools.Constant ...
- Spring Boot 2.X 如何添加拦截器?
最近使用SpringBoot2.X搭建了一个项目,大部分接口都需要做登录校验,所以打算使用注解+拦截器来实现,在此记录下实现过程. 一.实现原理 1. 自定义一个注解@NeedLogin,如果接口需要 ...
- Spring Boot干货:静态资源和拦截器处理
前言 本章我们来介绍下SpringBoot对静态资源的支持以及很重要的一个类WebMvcConfigurerAdapter. 正文 前面章节我们也有简单介绍过SpringBoot中对静态资源的默认支持 ...
- Spring Boot项目中如何定制拦截器
本文首发于个人网站:Spring Boot项目中如何定制拦截器 Servlet 过滤器属于Servlet API,和Spring关系不大.除了使用过滤器包装web请求,Spring MVC还提供Han ...
- Spring MVC中自定义拦截器的简单示例
1. 引言 拦截器(Interceptor)实现对每一个请求处理前后进行相关的业务处理,类似于Servlet的Filter. 我们可以让普通的Bean实现HandlerIntercpetor接口或继承 ...
- spring mvc <mvc:annotation-driven/> 自定义拦截器不走
<mvc:annotation-driven/> 这个便签会注册2个自定义拦截器,所以导致请求过来就会自己去走注册的这2个拦截器和定义的一堆bean 但是这个便签是必须得定义的 直接贴代码 ...
- Spring自定义拦截器
HandlerInterceptorAdapter由Spring MVC提供,用来拦截请求. 实现自定义拦截器需要继承HandlerInterceptorAdapter或实现HandlerInterc ...
随机推荐
- Qt编写安防视频监控系统15-远程回放
一.前言 远程回放有两种处理方式,一种是采用NVR厂家提供的SDK开发包来登录到NVR上,然后根据SDK的函数接口指定的视频文件,当然也有接口查询视频文件列表等:一种是采用视频监控行业的国标GB281 ...
- PMP 第8章错题总结
1.项目经理为项目的可交付成果定义验收标准.这些应记录在项目范围说明书2.项目的总体预算是“成本基准+管理储备”,成本基准里本身已包含了应急储备.工作包成本估算.活动成本估算3.范围基准包含----项 ...
- Redis面试大全
1. 什么是Redis Redis是由意大利人Salvatore Sanfilippo(网名:antirez)开发的一款内存高速缓存数据库.Redis全称为:Remote Dictionary Ser ...
- window 10 U盘启动制作教程
微软win10工具下载链接https://www.microsoft.com/zh-cn/software-download/windows10?OCID=WIP_r_Win10_Body_AddPC ...
- 接口和抽象类的区别,注意JDK8的接口可以有实现。
Java中,抽象类和接口有相似的地方.下面我们就来细说说接口和抽象类的异同. 首先是相同的地方: 1. 接口和抽象类都能定义方法和属性. 2. 接口和抽象类都是看作是一种特殊的类.大部分的时候,定义的 ...
- 服务器BMC资料整理
1. 现在服务器都有BMC管理了,可以直接连上服务器进行处理. bios里面进行简单设置就可以了, 连接上IPMI的口进行管理. 2. 可以使用 远程控制安装操作系统. 安装系统时 比较清楚的能够看到 ...
- [转帖]NSA武器库知识整理
NSA武器库知识整理 https://www.cnblogs.com/FrostDeng/p/7120812.html 美国国家安全局(NSA)旗下的“方程式黑客组织”(shadow brokers) ...
- 洛谷--P3808 【模板】AC自动机(“假的“简单版)
如果你想要做出这道题,你需要先了解两个知识点: 1.字典树的构造 2.KMP算法(也就是fail指针的构造) 对于字典树,可以看看这个大佬: https://www.cnblogs.com/TheRo ...
- Deleaker – 内存泄漏猎人(RAD Studio 的附加组件)
程序员面临(并希望我们意识到)的常见问题之一是内存泄漏或任何其他类型的资源泄漏.例如,Windows限制了进程一次可以分配的GDI或USER32对象的数量.当事情走错路时,您可能希望拥有一些工具来帮助 ...
- Django-12-auth认证组件
1. 介绍 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能. Django作为一个完美主义者的终极框架,当然也会 ...