应用场景
1、登录验证
以后台管理系统为例,大部分接口都应该要求做登录验证。如果每个方法里都加上登录状态检查,那未免太麻烦了,而且也不利于维护。应当把登录验证这个动作封装起来,以便复用。
2、数据统计 / 监控
比如使用 redis 统计指定页面的访问量等
如何使用拦截器?
控制器
先写一个测试的方法:
package com.example.boot.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@Slf4j
public class TestController {
@RequestMapping("/test/index")
public Map index() {
Map<String, Object> map = new HashMap<>();
map.put("code", 1);
map.put("msg", "ok");
map.put("data", null);
return map;
}
}
ok,能正常访问测试接口了。
1、编写拦截器类
实现 HandlerInterceptor 接口,并使用 @Component 注解自动注入到容器中。
LoginInterceptor
package com.example.boot.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Enumeration;
import java.util.Map;
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("LoginInterceptor -> preHandle 执行了");
// HttpSession session = request.getSession();
// Map<String, String[]> parameterMap = request.getParameterMap();
// Enumeration<String> parameterNames = request.getParameterNames();
// url
String scheme = request.getScheme();
String serverName = request.getServerName();
int serverPort = request.getServerPort();
String requestURI = request.getRequestURI();
StringBuffer requestURL = request.getRequestURL();
log.info("LoginInterceptor -> preHandle -> scheme: {}", scheme);
log.info("LoginInterceptor -> preHandle -> serverName: {}", serverName);
log.info("LoginInterceptor -> preHandle -> serverPort: {}", serverPort);
log.info("LoginInterceptor -> preHandle -> requestURI: {}", requestURI);
log.info("LoginInterceptor -> preHandle -> requestURL: {}", requestURL);
// header
String userAgentHeader = request.getHeader("User-Agent");
log.info("LoginInterceptor -> preHandle -> userAgentHeader: {}", userAgentHeader);
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
//通过请求头的名称获取请求头的值
String value = request.getHeader(name);
log.info("LoginInterceptor -> preHandle -> userAgentHeaders: {} -> {}", name, value);
}
// cookie
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
log.info("LoginInterceptor -> preHandle -> cookies: {} -> {}", cookie.getName(), cookie.getValue());
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("LoginInterceptor -> postHandle 执行了");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("LoginInterceptor -> afterCompletion 执行了");
}
}
2、将拦截器注册到容器中,指定拦截规则
新建一个配置类,使用 @Autowired 注解将拦截器自动装配到配置类中。
实现 WebMvcConfigurer 接口的 addInterceptors 方法。
MyWebMvcConfig
package com.example.boot.config;
import com.example.boot.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
@Autowired
LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(
"/css/**",
"/js/**",
"/images/**"
);
}
}
拦截所有请求
addPathPatterns -> /**
放行下列请求
excludePathPatterns -> “”,””
3、测试效果
应该注意哪些东西?
1、公共规则抽取
如果拦截器数量较多,应当把公共规则抽象出来。
public void addInterceptors(InterceptorRegistry registry) {
// 公共拦截规则
String[] PublicAddPathPatterns = {
"/**"
};
// 公共放行路径规则
String[] PublicExcludePathPatterns = {
"/static/**",
"/css/**",
"/js/**",
"/images/**"
};
registry.addInterceptor(loginInterceptor)
.addPathPatterns(PublicAddPathPatterns)
.excludePathPatterns(PublicExcludePathPatterns);
registry.addInterceptor(login2Interceptor)
.addPathPatterns(PublicAddPathPatterns)
.excludePathPatterns(PublicExcludePathPatterns);
}
2、不要使用 new 的方式手动创建拦截器实例
如果拦截器内使用了 @Autowired 注解自动装配,那么 new 出来的拦截器中,@Autowired 注解将会失效。
推荐在配置类中,使用 @Autowired 注解自动装配拦截器,而不是 new 的方式。
Reference
1、Springboot过滤器和拦截器详解及使用场景:https://zhuanlan.zhihu.com/p/340397290