目录
🎈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*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取前端的tokenString token = request.getHeader("token");if (token == null) {token = request.getParameter("token");}//判断token是否为空if (StringUtils.isNotBlank(token)) {//不为空,解密tokenClaims 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;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic 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*/@Beanpublic LoginInterceptor loginInterceptor(){return new LoginInterceptor();}@Overridepublic 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");}
}