交友项目【统一token处理】拦截器处理
目录
1:统一token处理
1.1:目的
1.2:实现
1.2.1:SpringMVC拦截器
1.2.2:使用ThreadLocal线程变量创建存储数据的类
1:统一token处理
1.1:目的
在前台请求和后端方法接收的这个模块,前台每次请求都需要去在controller视图层面进行获取请求头中的token信息,来判断是否携带了token。这一次每一个方法中都需要去书写相同的代码,来获取,势必会造成代码的冗余。
在这个交友项目中采用了拦截器的方式和线程中ThreadLocal的方式进行处理token获取和存放
1.2:实现
1.2.1:SpringMVC拦截器
工作流程图:
当然拦截器在拦截请求的等级中不是最高的,像一些过滤器等等。看图更方便
此项目中使用的是拦截器进行操作。
拦截器就是在请求到达Controller之前,将请求进行拦截下来,进行一定业务上的操作,将拦截器配置到项目的接收请求模块,在每次请求到达Controller层之前进行拦截请求,处理token即可。
拦截器代码实现:
package com.czxy.tanhua.interceptor;import com.czxy.tanhua.commons.utils.JwtUtils;
import com.czxy.tanhua.entity.User;
import io.jsonwebtoken.Claims;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class TokenInterceptor extends HandlerInterceptorAdapter {/*** 处理前* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1 获得tokenString token = request.getHeader("Authorization");//2 校验tokenboolean verifyToken = JwtUtils.verifyToken(token);if(!verifyToken) {response.setStatus(401);return false;}//3 获得token中的数据,封装User中Claims claims = JwtUtils.getClaims(token);Integer id = (Integer)claims.get("id");String mobile = (String) claims.get("mobile");User user = new User();user.setId(Long.valueOf(id));user.setMobile(mobile);//4 将user通过工具类,保存threadLocal中UserHolder.set(user);return true;}/*** 完成后* @param request* @param response* @param handler* @param ex* @throws Exception*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//移除UserHolder.remove();}
}
首先编写一个拦截类去继承HandlerInterceptorAdapter 类,HandlerInterceptorAdapter 类提供了三个方法:
这三个方法:一个是预处理,后处理,完成后,这里使用到了,预处理和完成后两种方法,进行重写这两个方法即可,我在预处理方法中处理了每次请求中的token,将其存放到UserHolder类中,这个类中用到了ThreadLocal这个线程变量,后续介绍,在完成后方法中调用线程回收方法进行释放了线程变量。完成一次的请求的接收和响应。
1.2.2:使用ThreadLocal线程变量创建存储数据的类
ThreadLocal是一个线程变量,在这个变量中填充的内容属于当前线程,什么意思呢?就是一个线程中用到了ThreadLocal这个线程变量的话对于其他线程是隔离的,独有的。所有呢因为是线程独有的就不存在多线程之间存在共享的问题。
ThreadLocal变量是被private static修饰的,当一个线程结束时,它所使用的所有ThreadLocal中的实例内容就会被回收。
总的来说,ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景
UserHolder类实现:将解析出来的token信息进行存放到该类中
package com.czxy.tanhua.interceptor;import com.czxy.tanhua.entity.User;
public class UserHolder {// 创建一个ThreadLocal类private static ThreadLocal<User> threadLocal = new ThreadLocal<>();/*** 保存用户信息* @param user*/public static void set(User user) {threadLocal.set(user);}/*** 获得线程中用户信息* @return*/public static User get() {return threadLocal.get();}/*** 获得用户id* @return*/public static Long getUserId() {User user = get();if(user == null) {return null;}return user.getId();}/*** 从当前线程,获取用户对象的手机号码*/public static String getMobile() {if (threadLocal.get() == null) {return null;}return threadLocal.get().getMobile();}/*** 移除线程中数据*/public static void remove() {threadLocal.remove();}
}
1.2.3:配置类将编写的拦截器进行注册
WebConfig类:
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**") //拦截所有路径.excludePathPatterns("/user/login", "/user/loginVerification"); //放行指定路径}
}