微服务获取登录用户Id与单体服务下获取用户Id对比(黑马头条Day03)

前置声明

        当前前后端分离开发项目中,后端某个请求向具体某个数据库中的多个表插入数据时,经常需要使用到当前登录用户的Id(唯一标识)。在当前用户线程下以实现变量共享,同时为了避免不同用户线程之间操作变量的影响,往往选择ThreadLocal本地线程变量实现线程内变量的共享读取,同时避免不同线程间操作的影响。

         产生第一个问题?我们如何获取用户的线程Id并将其存入到本地线程变量ThreadLocal中?

        http连接是无状态的,当前请求不会共享上一次请求的数据,所以需要结果Cookie、Session或Token一起使用,同时Token结合JWT令牌尝尝用于用户的登录校验,只有通过验证的连接才可以执行后续请求,没有通过登录验证的连接直接拒绝本次请求,提醒用户进行登录授权在用户首次登陆时服务端会利用JWT令牌技术生成Token,并将其一起返回给用户,随后用户访问服务端时携带第一次生成的Token,服务端可以实现用户登陆校验。在生成Token的同时可以在payLoad中加入用户Id信息,实现每次连接服务端解析Token获取当前登陆用户Id的目的。

 单体服务(苍穹外卖)如何获取用户Id

实现原理

        苍穹外卖作为一个单体项目,整个项目内只有一个启动类,所有可以认为一个连接就是一个线程,项目结构如下:

        在单体项目中获取用户Id并将其存入ThreadLocal变量中可以在项目拦截器中的以实现,具体流程如下:

        在生成JWT Token的过程中返给UserId,在拦截请求验证过程中解析Token获取用户Id。

实现步骤

  • 创建ThreadLocal类,主要功能包括设置UerId,获取UserId,清除UserId。
public class BaseContext {public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();/*** 设置UserId值* @param id*/public static void setCurrentId(Long id) {threadLocal.set(id);}/*** 获取UserId值* @return*/public static Long getCurrentId() {return threadLocal.get();}/*** 请求局部变量ThreadLocal中的UserId,防止内存溢出*/public static void removeCurrentId() {threadLocal.remove();}
}
  • 在拦截器中解析Token获取用户Id,并将其存入上面创建的BaseContext类中。 
    /*** 校验jwt** @param request* @param response* @param handler* @return* @throws Exception*/public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//判断当前拦截到的是Controller的方法还是其他资源if (!(handler instanceof HandlerMethod)) {//当前拦截到的不是动态方法,直接放行return true;}//1、从请求头中获取令牌String token = request.getHeader(jwtProperties.getUserTokenName());//2、校验令牌try {log.info("jwt校验:{}", token);Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());log.info("当前员工id:{}", userId);// 将当前登陆ID放入ThreadLocal中BaseContext.setCurrentId(userId);//3、通过,放行return true;} catch (Exception ex) {//4、不通过,响应401状态码response.setStatus(401);return false;}}
  • 上述代码块中主要使用的如下:直接调用静态方法setCurrentIdUserId添加到创建的ThreadLocal中。

 

  • 此后直接从BaseContext中使用getCurrentId(...)获取当前登陆用户的Id。 

微服务(黑马头条)如何获取用户Id

实现原理

        相信做过黑马头条这个项目的同伴都不会陌生微服务这个概念,在黑马头条这个微服务项目中涉及到多个微服务,如:网关微服务、文章微服务、用户微服务......。各个微服务均有属于各自的启动类,各个微服务通过阿里开源nacos实现服务注册与分发,在这个项目中自媒体网关微服务自媒体微服务通过nacos将其关联起来,自媒体相关请求到达时首先通过Nginx方向代理将其分配到自媒体网关微服务接口,对其进行登陆校验(Token解析相关工作),通过验证的请求,nacos会将其分发到自媒体微服务接口,实现后续操作。 两个微服务各自有各自的启动类,二者之间并不直接联系,对应不同的线程。如何使用TheradLocal实现共享变量的线程内部使用。

        首先在自媒体网关微服务中对Token进行解析,并将其存入Header中,随后路由(重置请求)将其发送到自媒体微服务中,后续逻辑同单体服务。

实现步骤

  • 构建ThreadLocal类。
public class WmThreadLocalUtil {private static ThreadLocal<WmUser> WM_USER_THREAD_LOCAL = new ThreadLocal<>();/*** 设置用户信息* @param wmUser*/public static void setUser(WmUser wmUser){WM_USER_THREAD_LOCAL.set(wmUser);}/*** 获取用户信息* @return*/public static WmUser getUser(){return WM_USER_THREAD_LOCAL.get();}/*** 清理用户信息*/public static void clear(){WM_USER_THREAD_LOCAL.remove();}
}
  • 自媒体网关微服务中对登陆进行校验并获取用户信息。 

  • 自媒体微服务中配置拦截器对header进行拦截并进行存储。
@Slf4j
@Component
public class WmTokenInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String userId = request.getHeader("userId");if(userId != null){log.info("将用户信息存入到ThreadLocal中:{}", userId);WmUser wmUser = new WmUser();wmUser.setId(Integer.valueOf(userId));WmThreadLocalUtil.setUser(wmUser);}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);log.info("清理ThreadLocal中的用户信息");WmThreadLocalUtil.clear();}}

        在上面代码中重写postHandle(...)方法对ThreadLocal中的变量进行及时清除。防止内存溢出。

参考

        苍穹外卖

        黑马头条

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/518268.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

期货开户如何查询最新的手续费明细?

一、如何查询最新的手续费明细和保证金明细&#xff1f; 1、手机或者电脑交易软件下单窗口&#xff0c;点击品种合约&#xff0c;一般会显示1手需要的保证金比例&#xff0c;比如手机博弈大师/同花顺期货通等。 2、电脑交易软件下单窗口&#xff0c;点合约&#xff0c;里面会…

在idea中如何开启项目的热部署

热部署&#xff1a;就是当我们IDEA的项目在运行期间&#xff0c;我们修改代码以后&#xff0c;不需要我们自己重启项目&#xff0c;IDEA就会自动的重启项目 在idea中开启项目热部署的步骤 第一步&#xff1a;引入热部署的依赖 <dependency><groupId>org.springfr…

重磅!云智慧推出轻量智能化服务管理平台轻帆云

近日&#xff0c;云智慧推出智能服务管理平台轻帆云&#xff0c;通过构建服务体系、规范服务流程、保障服务质量、提升服务效能&#xff0c;为企业提供安全可靠的一站式服务管理解决方案。SaaS轻量化部署方式&#xff0c;仅需通过简单操作&#xff0c;即可轻松完成搭建&#xf…

物体检测-系列教程22:YOLOV5 源码解析12 (BottleneckCSP层、Conv模块、Bottleneck模块)

&#x1f60e;&#x1f60e;&#x1f60e;物体检测-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 点我下载源码 16、BottleneckCSP层 16.1 BottleneckCSP类 位置&#xff1a;yolov5/models/common.py/…

数据结构:顺序表的奥秘

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生&#x1f43b;‍❄个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE&#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&a…

Golang搭建grpc环境

简介 OS : Windows 11 Golang 版本: go1.22.0 grpc : 1.2 protobuffer: 1.28代理 没有代理国内环境下载不了库七牛CDN &#xff08;试过可用&#xff09; go env -w GOPROXYhttps://goproxy.cn,direct阿里云代理(运行grpc时下载包出现报错 ): go env -w GOPROXYhttps://mirr…

el-table 表格多选, 批量删除功能

一、基础的多选el-table ElementUI 提供了多选行table&#xff0c;同时若依框架也提供了成熟的多选表格。 1.table基础结构 需要绑定selection-change方法 <el-tablev-loading"loading"stripe:data"productList"selection-change"handleSelect…

Vue+Vue CLI学习

1、Vue基础 1.1、Vue简介 &#xff08;1&#xff09;Javascript框架 &#xff08;2&#xff09;简化Dom操作 &#xff08;3&#xff09;响应式数据驱动 vue基础&#xff1b;vue-cli;vue-router;vuex;element-ui;vue3 vue文件包括html、css、js 1.2、第一个Vue程序 Vue …

如何进行渗透测试以提高软件安全性

对于各种规模的企业和组织来说&#xff0c;软件安全是一个至关重要的问题。随着网络攻击越来越复杂&#xff0c;软件中的漏洞越来越多&#xff0c;确保你的软件安全比以往任何时候都更重要。提高软件安全性的一个有效方法是渗透测试&#xff08;penetration testing&#xff09…

【python基础学习10课_面向对象、封装、继承、多态】

一、类与对象 1、类的定义 在类的里面&#xff0c;称之为方法。 在类的外面&#xff0c;称之为函数。类&#xff1a;人类&#xff0c;一个族群&#xff0c;是一个群体类的语法规则&#xff1a;class 自定义的类名():属性 -- 变量方法 -- 函数类&#xff0c;首字母大写&#x…

如何在有/没有备份的情况下恢复华为上已删除的视频?6 个推荐选项

“我不小心删除了华为手机上的一堆视频。我怎样才能把它们找回来&#xff1f;我在谷歌上也找不到它们”。——来自知乎 在我们日常生活的喧嚣中&#xff0c;意外时有发生。无论是由于华为手机上的无意删除、恢复出厂设置、病毒感染、数据损坏还是系统故障&#xff0c;这些视频…

基于单片机的机动车智能远光灯系统设计

目 录 摘 要 I Abstract II 引 言 1 1 主要研究内容及总体设计方案 3 1.1 主要研究内容 3 1.2 系统总体方案选择 3 1.3 系统功能的确定 4 2 硬件电路的设计 5 2.1 单片机控制模块设计 5 2.2 液晶显示模块电路设计 7 2.3 远近灯光电路设计 9 2.4 按键电路设计 9 2.5 超声波电路…