SpringMVC提供了一个拦截器接口供我们调用:HandlerInterceptor
,这个接口有三个待实现的方法:
- preHandle方法
进入 Handler方法之前执行
用于身份认证、身份授权
比如身份认证,如果认证不通过表示当前用户没有登陆,需要此方法拦截不再向下执行
return false表示拦截,不向下执行
return true表示放行
- postHandle方法
进入Handler方法之后,返回modelAndView之前执行
应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
- afterCompletion方法
执行Handler完成执行此方法
应用场景:统一异常处理,统一日志处理
这里给个拦截器的原理图
下面我们来试试自己的拦截器.
自己定义一个拦截器LogInterceptor
,实现HandlerInterceptor
package com.zgd.demo.spring.intercept;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Map;
/**
* @author zzzgd
* @data 2019年3月8日14:54:00
*/
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
private static final ThreadLocal<Long> START_TTIME_THREAD_LOCAL = new NamedThreadLocal<Long>("ThreadLocal StartTime");
/**
* 拦截的方法执行之前调用
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
//1、开始时间
long beginTime = System.currentTimeMillis();
//线程绑定变量(该数据只有当前请求的线程可见)
START_TTIME_THREAD_LOCAL.set(beginTime);
return true;
}
/**
* 拦截的方法执行过程中,返回model and view之前调用
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
if (modelAndView != null) {
log.info("ViewName: " + modelAndView.getViewName());
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// 打印JVM信息。
//1. 得到线程绑定的局部变量(开始时间)
long beginTime = START_TTIME_THREAD_LOCAL.get();
//2、结束时间
long endTime = System.currentTimeMillis();
Map<String, String[]> pm = request.getParameterMap();
log.info("耗时:{}ms\tURI:{}\t请求参数:{}\t最大内存:{}m\t已分配内存:{}m\t已分配内存中的剩余空间:{}m\t最大可用内存:{}m",
(endTime - beginTime), request.getRequestURI(), JSON.toJSON(pm), Runtime.getRuntime().maxMemory() / 1024 / 1024, Runtime.getRuntime().totalMemory() / 1024 / 1024, Runtime.getRuntime().freeMemory() / 1024 / 1024,
(Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory() + Runtime.getRuntime().freeMemory()) / 1024 / 1024);
}
}
1. springmvc情况
然后在SpringMVC配置文件进行配置:
<!--配置拦截器, 多个拦截器,顺序执行 -->
<mvc:interceptors>
<!-- 系统日志拦截器 -->
<mvc:interceptor>
<!--拦截的路径-->
<mvc:mapping path="/**" />
<!--排除的匹配路径-->
<mvc:exclude-mapping path="/wxPay/*" />
<!--自己定义的拦截器-->
<bean class="com.zgd.demo.spring.intercept.LogInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
2.springboot情况
如果是springboot,要在配置类中配置,实现WebMvcConfigurer
,重写addInterceptors方法
addPathPatterns -------- 添加路径匹配,匹配这个路径的都会被拦截到
excludePathPatterns -------- 排除路径匹配
package com.zgd.demo.spring.config;
import com.zgd.demo.spring.intercept.LogInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class WebAppConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册自定义拦截器,添加拦截路径和排除拦截路径
registry.addInterceptor(new LogInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/skip/**");
}
}
这样就大功告成了