目的:項目中需要攔截器的實現,讓沒有登陸的用戶無法通過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("/**");
}
}