拦截器: 是在请求进入到Controller 的一层AOP处理,相当于在Controller之前、之中和之后可以定义一些我们自己的业务逻辑。
首先实现HandlerInterceptor 接口
SpringMVC中给我提供了一个接口叫做 HandlerInterceptor, 我们实现了这个接口之后,需要实现里面的几个方法。这几个方法就是用来定义我们拦截器的业务逻辑实现。我们来看下这接口中的内容:
java复制代码package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
这里面有三个方法:
preHandle: 在controller执行之前要执行的逻辑,这个方法返回boolean值,返回true, 则请求继续执行,返回false则不会向后执行。这个也是拦截器中最常用的方法,一般我们的项目中会校验每个请求的用户信息,根据用户传过来的token来验证其是否合法。如果不合法,直接返回false ,相当于请求会被拒绝。
postHandle: 此方法将在controller执行之后执行,但是视图还没有解析,可向ModelAndView中添加数据(前后端不分离的)
afterCompletion方法:该方法会在整个请求结束(请求结束,但是并未返回结果给客户端)之后执行, 可获取响应数据及异常信息
实现接口和方法里的业务逻辑后,这个拦截器还并没有生效,我们需要将这个拦截器注入到适配器中才能生效,适配器中其实主要就是执行一个添加拦截器的操作,并且为这个拦截器设置要拦截的路径(也可以设置不包含的路径)
我们的需求就是针对除了登录外的所有请求进行拦截,获取请求header中携带过来的token ,如果header中没有token则直接拦截,有token放行(我们只是举个例子,正常还要校验token的正确性)
首先我们要下个拦截器的类,实现HandlerInterceptor 接口
java复制代码public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 核心业务逻辑,判断是否登录等
String token = request.getHeader("token");
// 正常token是的登录后签发的,前端携带过来
return StringUtils.hasLength(token);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
//
System.out.println("controller 执行完了");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("我获取到了一个返回的结果:"+response);
System.out.println("请求结束了");
}
}
然后将这个拦截器进行注册,在config文件夹下创建一个配置类
java复制代码package com.lsqingfeng.springboot.config;
import com.lsqingfeng.springboot.interceptor.TokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @className: WebMvcConfig
* @description:webMvc配置
* @author: sh.Liu
* @date: 2022-01-13 09:51
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截
registry.addInterceptor(new TokenInterceptor())
// 对所有请求进行拦截
.addPathPatterns("/**")
// 排除 login请求
.excludePathPatterns("/login");
}
}
这个时候我们再重新启动项目,拦截器就生效了。我们访问试试。通过浏览器访问,肯定是没有token的。
发现是一个空白页面,这就是拦截器给拦打回来了。正常来讲这种方式不友好,如果不符合条件的最好不要直接返回false,我们可以抛出一个业务异常,然后在统一的异常拦截器中进行处理。后面再说。
我们在postman中传一个token的header试试。
加入token后正常返回了结果。那我们试试login是否可以被过滤掉。
java复制代码@GetMapping("/login")
public String login(){
return "success";
}
访问,在没有携带token参数的时候成功返回,就是因为我们的拦截器排除了login请求。
拦截器的写法在我们应用springBoot的时候还是经常会使用到的,所以大家一定要掌握。
另: 配套项目代码已托管中gitCode: gitcode.net/lsqingfeng/…