文章目录
目前有一个需求,是在现有项目中集成一个简单的登录功能,想到了使用过滤器和拦截器实现,这篇文章介绍如何使用spring的拦截器。
1 拦截器(Interceptor)定义
拦截器是在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。是基于JAVA的反射机制。
1.1 拦截器(Interceptor)执行顺序
- 请求到达 DispatcherServlet
- DispatcherServlet 发送至 Interceptor ,执行 preHandle
- 请求达到 Controller
- 请求结束后,postHandle 执行
1.2 拦截器(Interceptor)和过滤器(Filter)的执行顺序
过滤前->拦截前->Action处理->拦截后->过滤后

1.3 方法介绍
1)预处理preHandle()方法
用户发送请求时,先执行preHandle()方法。会先按照顺序执行所有拦截器的preHandle方法,一直遇到return false为止,比如第二个preHandle方法是return false,则第三个以及以后所有拦截器都不会执行。若都是return true,则执行用户请求的url方法。
2)后处理postHandle()方法
调用了Service并返回ModelAndView,但未进行页面渲染,可以在这里继续修改ModelAndView或者返回值
3)返回处理afterCompletion()方法
已经渲染了页面,在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
注:一般使用preHandle这个拦截器进行预处理,对url进行请求拦截
2 拦截器编写(实现HandlerInterceptor接口)
需要继承HandlerInterceptorAdapter类
注意,在更高版本中HandlerInterceptorAdapter已经弃用,推荐实现HandlerInterceptor接口
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("进入到拦截器中:preHandle() 方法");
System.out.println(request.getServletPath());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("进入到拦截器中:postHandle() 方法中");
System.out.println(request.getRequestURI());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("进入到拦截器中:afterCompletion() 方法中");
System.out.println(request.getServletPath());
}
}
3 拦截器注册(实现WebMvcConfigurer接口)
需要继承WebMvcConfigurerAdapter类,注意,在更高版本中WebMvcConfigurerAdapter已经弃用,推荐实现WebMvcConfigurer接口;
需要重写addInterceptors(InterceptorRegistry registry)方法,这里是对根目录"/"进行拦截,可以指定拦截url请求目录
也可以通过继承WebMvcConfigurationSupport类来实现,但是只能继承一次,而且会导致其他不注册在此类中的拦截器失效,不建议使用。
@Configuration
public class InterceptorAdapterConfig implements WebMvcConfigurer {
private final LoginInterceptor loginInterceptor;
public InterceptorAdapterConfig(LoginInterceptor loginInterceptor) {
this.loginInterceptor = loginInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry)
{
//注册自己的拦截器并设置拦截的请求路径
registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
}
}
4 对指定方法进行拦截
这里的注册监听器,自定义监听器写法和前面一致。
如果对url目录下所有的请求进行了监听,但需要对某些请求方法不进行拦截或单独拦截,可以采用自定义注解方式,对方法加上自定义注解,拦截器进行扫描,对出现过自定义注解的方法进行单独处理
3.1 编写一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedLogin {
boolean LoginSuccess() default true;
}
3.2 修改拦截器
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("进入到拦截器中:preHandle() 方法");
HandlerMethod handlerMethod = (HandlerMethod) handler;
NeedLogin loginVerify = handlerMethod.getMethodAnnotation(NeedLogin.class);
if (loginVerify == null) {
log.info("不需要对该路径 进行拦截");
return true;
}else {
log.info("对该路径 进行拦截");
log.info("业务操作...");
return true;
}
}
/**
* 拦截后自定义响应
*/
public void sendResponse(HttpServletResponse httpServletResponse, Object object) throws IOException {
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
ServletOutputStream out = httpServletResponse.getOutputStream();
out.write(objectMapper.writeValueAsString(object).getBytes(StandardCharsets.UTF_8));
out.flush();
out.close();
}
3.3 编写controller测试
@GetMapping("/test")
@NeedLogin
public String test() {
System.out.println(LocalDateTime.now());
return LocalDateTime.now().toString();
}
@GetMapping("/test2")
public String test2() {
System.out.println(LocalDateTime.now());
return LocalDateTime.now().toString();
}
5 拦截器中获取类注解和方法注解
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//必须强转为HandlerMethod
HandlerMethod handlerMethod = (HandlerMethod) handler;
//获取类上的注解
IgnoreAuth clazzAnnotation = handlerMethod.getBeanType().getAnnotation(IgnoreAuth.class);
//判断类上是否有打该注解
boolean clazzAnnotationPresent = handlerMethod.getBeanType().isAnnotationPresent(IgnoreAuth.class);
//获取方法上的注解 方式1
IgnoreAuth methodAnnotation_1 = handlerMethod.getMethodAnnotation(IgnoreAuth.class);
//获取方法上的注解 方式2
IgnoreAuth methodAnnotation_2 = handlerMethod.getMethod().getAnnotation(IgnoreAuth.class);
//判断方法上是否有打该注解
boolean methodsAnnotationPresent = handlerMethod.getMethod().isAnnotationPresent(IgnoreAuth.class);
}

本文介绍了如何在Spring MVC中使用拦截器实现简单的登录功能。拦截器基于Java反射机制,在面向切面编程中应用,分为preHandle、postHandle和afterCompletion三个阶段。preHandle在请求到达Controller之前执行,postHandle在Controller处理后但页面渲染前执行,afterCompletion在页面渲染后执行。文章详细讲解了拦截器的定义、执行顺序、与过滤器的区别,以及如何编写和注册拦截器,并通过自定义注解实现对特定方法的拦截。最后,展示了如何在拦截器中获取类和方法的注解。
701





