目录
🎈1.登陆拦截器的使用
🎊2.ThreadLocal的简单使用
🎃3.登录拦截器拦截和放行配置
1.登陆拦截器的使用
创建一个拦截器类,必须让其实现HandlerInterceptor接口
1.获取前端的token
2.判断token是否为空
3.若为空,返回json数据给前端
4.如不为空,校验解析token看是否与登陆者的一直,获取信息
5.将获取的信息,封装为UserDo对象
6.使用ThreadLocal传递信息
/**
* 登录拦截器
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
public static ThreadLocal<LoginUser> threadLocal=new ThreadLocal<>();
/**
* 登录校验
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取前端的token
String token = request.getHeader("token");
if (token == null) {
token = request.getParameter("token");
}
//判断token是否为空
if (StringUtils.isNotBlank(token)) {
//不为空,解密token
Claims claims = JwtUtil.checkToken(token);
if (claims == null) {
//未登录,返回json数据
CommonUtil.sendJsonMessage(response, CodeEnum.ACCOUNT_NO_LOGIN);
}
//解密登录对象的各种信息
Long loginUserId = Long.valueOf(claims.get("id").toString());
String loginUserHeadImage = String.valueOf(claims.get("head_image"));
String loginUserMail = String.valueOf(claims.get("mail"));
String loginUserName = String.valueOf(claims.get("name"));
//将获取的登录对象的各种信息封装为loginUser,方便使用
LoginUser loginUser = new LoginUser();
loginUser.setName(loginUserName);
loginUser.setMail(loginUserMail);
loginUser.setHeadImg(loginUserHeadImage);
loginUser.setId(loginUserId);
//使用threadLocal传递用户信息
threadLocal.set(loginUser);
//返回true,
return true;
}
CommonUtil.sendJsonMessage(response, CodeEnum.ACCOUNT_NO_LOGIN);
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
- 如果没有token,说明未登录,给前端返回json数据,调用指定的json转换方法
/**
* 返回json数据给前端
*
* @param response
* @param object
*/
public static void sendJsonMessage(HttpServletResponse response, Object object) {
//Json序列化
ObjectMapper objectMapper = new ObjectMapper();
//设置HTTP响应的Content-Type头部
response.setContentType("application/json; charset=utf-8");
//获取获取输出流
try (PrintWriter writer = response.getWriter()) {
writer.print(objectMapper.writeValueAsString(object));
response.flushBuffer();
log.info("返回json成功");
} catch (IOException e) {
e.printStackTrace();
log.warn("相应json数据异常:{}",e);
}
}
- 思考了一个问题: threadLocal的使用属于单例模式中的饿汉式吗????
答案:不是的
大佬的回答: 在LoginInterceptor
类中,threadLocal
被定义为一个静态变量,并且使用了饿汉式初始化,即在类加载的时候就完成了ThreadLocal
对象的创建。然而,这并不意味着它是单例模式的实现。单例模式关注的是确保一个类只有一个实例,而ThreadLocal
关注的是线程间的数据隔离。
2.ThreadLocal的简单使用
ThreadLocal
的主要目的是为每一个线程提供一个独立的变量副本,而不是确保整个应用程序只有一个实例。ThreadLocal
的设计是为了解决多线程环境下的数据隔离问题。当多个线程共享同一个对象时,如果不加控制,线程间的数据可能会互相干扰。使用ThreadLocal
可以让每个线程都拥有自己独立的数据副本,从而避免线程间的数据冲突。总结:同个线程共享数据
3.登录拦截器拦截和放行配置
- 创建拦截器的配置类,一定要实现WebMvcConfiguer接口;
- 重写addInterceptors()方法
- 设置指定的拦截器,并添加相应的拦截路径即可
@Slf4j
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
/**
* 创建loginInterceptor拦截器对象
* @return
*/
@Bean
public LoginInterceptor loginInterceptor(){
return new LoginInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//指定拦截器
registry.addInterceptor(loginInterceptor())
//需要拦截的路径
.addPathPatterns("/api/user/*/**","/api/address/*/**")
//排除不需要拦截的路径
.excludePathPatterns("/api/user/*/send_code","/api/user/*/captcha","/api/user/*/login","/api/user/*/register","/api/user/*/upload");
}
}