目的:项目中需要拦截器的实现,让没有登陆的用户无法通过url来实现页面的渲染。
实现:
一、继承HandlerInterceptorAdapter
public class LoginInterceptor extends HandlerInterceptorAdapter
二、重写preHandler和afterCompletion
preHandler:前置方法,可以拦截在controller之前,return false被拦截,return true被放行
afterCompletion:完成方法,当视图渲染完成之后执行
/**
* 前置方法:在handler方法执行之前执行
* false-被拦截
* true-放行
* @param request
* @param response
* @param handler
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取token信息
String token = CookieUtils.getCookieValue(request, this.jwtProperties.getCookieName());
// 判断token是否为空
if (StringUtils.isBlank(token)) {
// 没有登录,跳转到登录页
response.sendRedirect("登陆页面的url(从上个页面进入登陆页面的url)");
return false;
}
// 解析jwt
UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getPublicKey());
if (userInfo == null) {
response.sendRedirect("登陆页面的url(从上个页面进入登陆页面的url)");
return false;
}
THREAD_LOCAL.set(userInfo);
return true;
}
/**
* 完成方法:在视图渲染完成之后执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 必须要释放资源,使用的是tomcat线程池,业务逻辑处理完成之后,线程并没有结束,还回到线程池中了
THREAD_LOCAL.remove();
}
三、使用ThreadLocal共享用户信息数据UserInfo
设置到ThreadLocal中在后续的业务逻辑中就可以使用UserInfo数据
private static final ThreadLocal<UserInfo> THREAD_LOCAL = new ThreadLocal<>();
THREAD_LOCAL.set(userInfo);
完整的拦截器代码:
@EnableConfigurationProperties(JwtProperties.class)
@Component
public class LoginInterceptor extends HandlerInterceptorAdapter {
private static final ThreadLocal<UserInfo> THREAD_LOCAL = new ThreadLocal<>();
public LoginInterceptor(JwtProperties jwtProperties) {
this.jwtProperties = jwtProperties;
}
@Autowired
private JwtProperties jwtProperties;
/**
* 前置方法:在handler方法执行之前执行
* false-被拦截
* true-放行
* @param request
* @param response
* @param handler
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取token信息
String token = CookieUtils.getCookieValue(request, this.jwtProperties.getCookieName());
// 判断token是否为空
if (StringUtils.isBlank(token)) {
// 没有登录,跳转到登录页
response.sendRedirect("登陆页面的url(从上个页面进入登陆页面的url)");
return false;
}
// 解析jwt
UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getPublicKey());
if (userInfo == null) {
response.sendRedirect("登陆页面的url(从上个页面进入登陆页面的url)");
return false;
}
THREAD_LOCAL.set(userInfo);
return true;
}
/**
* 完成方法:在视图渲染完成之后执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 必须要释放资源,使用的是tomcat线程池,业务逻辑处理完成之后,线程并没有结束,还回到线程池中了
THREAD_LOCAL.remove();
}
/**
* 获取线程变量中的参数
* @return
*/
public static UserInfo get() {
return THREAD_LOCAL.get();
}
}
四、启动拦截器
两个条件:1、实现WebMvcConfigurer接口 2、添加@Configuration注解
重写addInterceptors方法:
@Override
public void addInterceptors(InterceptorRegistry registry)
五、添加拦截器和拦截路径
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor()).addPathPatterns("/**");
}
其中的addPathPatterns("/**")是指拦截所有的路径
完整启动拦截器代码:
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class ProjectConfig implements WebMvcConfigurer {
@Autowired
private JwtProperties jwtProperties;
@Bean
public LoginInterceptor loginInterceptor() {
return new LoginInterceptor(jwtProperties);
}
/**
* 注册拦截器到拦截器注册器中,使拦截器生效
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor()).addPathPatterns("/**");
}
}