• 实战篇04:获取用户详细信息


    实战篇04:获取用户详细信息

    一、接口信息

    1.1 基本信息

    请求路径:/user/userInfo

    请求方式:GET

    接口描述:该接口用于获取当前已登录用户的详细信息

    1.2 请求参数

    1.3 响应数据

    响应数据类型:application/json

    响应参数说明:

    名称类型是否必须默认值备注其他信息
    codenumber必须响应码, 0-成功,1-失败
    messagestring非必须提示信息
    dataobject必须返回的数据
    |-idnumber非必须主键ID
    |-usernamesrting非必须用户名
    |-nicknamestring非必须昵称
    |-emailstring非必须邮箱
    |-userPicstring非必须头像地址
    |-createTimestring非必须创建时间
    |-updateTimestring非必须更新时间

    响应数据样例:

    {
        "code": 0,
        "message": "操作成功",
        "data": {
            "id": 5,
            "username": "wangba",
            "nickname": "",
            "email": "",
            "userPic": "",
            "createTime": "2023-09-02 22:21:31",
            "updateTime": "2023-09-02 22:21:31"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    二、业务流程

    1. 在Controller层通过JWT token获取用户名,以此来获取相应的用户数据
    2. service与mapper复用之前的,为controller提供服务

    在这里插入图片描述

    三、编写Controller

    1. 在UserController类中添加用户信息功能
    @GetMapping("/userInfo")
    public Result<User> userInfo(@RequestHeader(name = "Authorization") String token){
        // 根据用户名查询用户
        Map<String, Object> map = JwtUtil.parseToken(token);
        System.out.println(map);
        String username = (String) map.get("username");
        User user = userService.findByUserName(username);
        return Result.success(user);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 此时,返回user对象会将密码进行返回,需要在User类中对password字段添加注解:@JsonIgnore
    package com.example.bigevent.pojo;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import lombok.Data;
    
    import java.time.LocalDateTime;
    
    @Data
    public class User {
        private Integer id;//主键ID
        private String username;//用户名
        @JsonIgnore // 转换成jason时忽略此字段
        private String password;//密码
        private String nickname;//昵称
        private String email;//邮箱
        private String userPic;//用户头像地址
        private LocalDateTime createTime;//创建时间
        private LocalDateTime updateTime;//更新时间
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    1. 由于User类中时间:createTime与数据库中字段:create_time,不一致。在application.yml中开启驼峰转换即可显示信息
    mybatis:
      configuration:
        map-underscore-to-camel-case: true #开启驼峰命名和下划线命名的自动转换
    
    • 1
    • 2
    • 3

    四、改进Controller

    4.1、改进原因

    由于在拦截器中解析过token,因此在Controller层不需要重复解析操作,为此需要改进Controller

    4.2、ThreadLocal介绍

    4.2.1、优势

    可以存取数据:set()/get();且该方法线程安全

    在这里插入图片描述

    4.2.2、使用测试类对ThreadLocal进行测试

    @Test
    public void testThreadLocalSetAndGet(){
        // 提供一个ThreadLocal对象
        ThreadLocal tl = new ThreadLocal();
        // 开启两个线程
    
        new Thread(()->{
            tl.set("萧炎");
            System.out.println(Thread.currentThread().getName()+": "+tl.get());
            System.out.println(Thread.currentThread().getName()+": "+tl.get());
        },"蓝色").start();
    
        new Thread(()->{
            tl.set("药尘");
            System.out.println(Thread.currentThread().getName()+": "+tl.get());
            System.out.println(Thread.currentThread().getName()+": "+tl.get());
        },"绿色").start();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4.2.3、运行逻辑

    每一个用户访问服务器时,使用同一个线程进行Controller,Service,Mapper加载访问,因此可以使用ThreadLocal进行线程隔离方式存储数据。

    在这里插入图片描述

    4.3、使用ThreadLocal进行优化

    4.3.1、编写ThreadLocal工具类:ThreadLocalUtil

    package com.example.bigevent.utils;
    
    @SuppressWarnings("all")
    public class ThreadLocalUtil {
        //提供ThreadLocal对象,
        private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
    
        //根据键获取值
        public static <T> T get(){
            return (T) THREAD_LOCAL.get();
        }
    
        //存储键值对
        public static void set(Object value){
            THREAD_LOCAL.set(value);
        }
    
    
        //清除ThreadLocal 防止内存泄漏
        public static void remove(){
            THREAD_LOCAL.remove();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4.3.2、在拦截器中存放Jwt的token数据

    @Component
    public class LoginInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 令牌验证
            String token = request.getHeader("Authorization");
            try {
                Map<String, Object> claims = JwtUtil.parseToken(token);
                // 把数据放进ThreadLocal中
                ThreadLocalUtil.set(claims);
                // 拦截器放行
                return true;
            }catch (Exception e){
                response.setStatus(401);
                return false;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4.3.3、在Controlle层获取token数据

    @GetMapping("/userInfo")
    public Result<User> userInfo(/*@RequestHeader(name = "Authorization") String token*/){
        // 根据用户名查询用户
    //        Map map = JwtUtil.parseToken(token);
    //        System.out.println(map);
    //        String username = (String) map.get("username");
        Map<String,Object> map = ThreadLocalUtil.get();
        String username = (String) map.get("username");
        User user = userService.findByUserName(username);
        return Result.success(user);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4.3.4、新增结束拦截器,用于释放ThreadLocal

    @Component
    public class LoginInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 令牌验证
            String token = request.getHeader("Authorization");
            try {
                Map<String, Object> claims = JwtUtil.parseToken(token);
                // 把数据放进ThreadLocal中
                ThreadLocalUtil.set(claims);
                // 拦截器放行
                return true;
            }catch (Exception e){
                response.setStatus(401);
                return false;
            }
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            // 清空ThreadLocal中的数据
            ThreadLocalUtil.remove();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    vue3代码编写
    JavaScript——Document Object Model
    MySQL之MHA
    Linux简单安装ffmpeg 实现用PHP压缩音频
    【洛谷 P5717】【深基3.习8】三角形分类 题解(数学+分支)
    【深度学习】torch.squeeze()移除维度函数 | torch.unsqueeze()增加某一维度函数 | pytorch
    STM32物联网项目-HMI串口屏
    进程与线程
    [Spring Cloud] nacos安装与使用
    C# 实战--listBox1使用
  • 原文地址:https://blog.csdn.net/qq_37589805/article/details/137433812