实战篇04:获取用户详细信息
一、接口信息
1.1 基本信息
请求路径:/user/userInfo
请求方式:GET
接口描述:该接口用于获取当前已登录用户的详细信息
1.2 请求参数
无
1.3 响应数据
响应数据类型:application/json
响应参数说明:
名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
---|---|---|---|---|---|
code | number | 必须 | 响应码, 0-成功,1-失败 | ||
message | string | 非必须 | 提示信息 | ||
data | object | 必须 | 返回的数据 | ||
|-id | number | 非必须 | 主键ID | ||
|-username | srting | 非必须 | 用户名 | ||
|-nickname | string | 非必须 | 昵称 | ||
string | 非必须 | 邮箱 | |||
|-userPic | string | 非必须 | 头像地址 | ||
|-createTime | string | 非必须 | 创建时间 | ||
|-updateTime | string | 非必须 | 更新时间 |
响应数据样例:
{"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"}
}
二、业务流程
- 在Controller层通过JWT token获取用户名,以此来获取相应的用户数据
- service与mapper复用之前的,为controller提供服务
三、编写Controller
- 在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);
}
- 此时,返回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;//主键IDprivate String username;//用户名@JsonIgnore // 转换成jason时忽略此字段private String password;//密码private String nickname;//昵称private String email;//邮箱private String userPic;//用户头像地址private LocalDateTime createTime;//创建时间private LocalDateTime updateTime;//更新时间
}
- 由于User类中时间:createTime与数据库中字段:create_time,不一致。在application.yml中开启驼峰转换即可显示信息
mybatis:configuration:map-underscore-to-camel-case: true #开启驼峰命名和下划线命名的自动转换
四、改进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();
}
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();}
}
4.3.2、在拦截器中存放Jwt的token数据
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic 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;}}
}
4.3.3、在Controlle层获取token数据
@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");Map<String,Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");User user = userService.findByUserName(username);return Result.success(user);
}
4.3.4、新增结束拦截器,用于释放ThreadLocal
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic 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;}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 清空ThreadLocal中的数据ThreadLocalUtil.remove();}
}