token的处理和统一异常处理 您所在的位置:网站首页 业务异常状态码怎么处理 token的处理和统一异常处理

token的处理和统一异常处理

2023-10-12 14:24| 来源: 网络整理| 查看: 265

统一token处理 3.1 问题分析 3.1.1 问题

token 为了测试方便增大存活时长,但是之后token能获去但总是不对,因为数据越界,变为-1,导致本来想增大存活时长,但却早早就使得token过期了

每一个控制方法中都需要解析token , 获取当前用户id , 代码重复度比较高

重复性的登录验证

繁琐的token获取及解析

3.1.2 解决方案

基于ThreadLocal + 拦截器的形式统一处理

 

 

 

拦截器(Interceptor)

是一种动态拦截方法调用的机制;

类似于Servlet 开发中的过滤器Filter,用于对处理器进行前置处理和后置处理。

 

 

 

ThreadLocal

线程内部的存储类,赋予了线程存储数据的能力。

线程内调用的方法都可以从ThreadLocal中获取同一个对象。

多个线程中ThreadLocal数据相互隔离

Threadlocal使用方法很简单

ThreadLocal threadLocal = new ThreadLocal(); threadLocal.set() //将数据绑定到当前线程 threadLocal.get() //从当前线程中获取数据 代码实现  定义拦截器

 

定义拦截器,在前置拦截方法preHandle中解析token并验证有效性,如果失效返回状态码401。如果有效,解析User对象,存入ThreadLocal中

package com.i.server.interceptor; /** * @author Administrator */ public class TokenInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //1、获取请求头 String token = request.getHeader("Authorization"); //2、使用工具类,判断token是否有效 boolean verifyToken = JwtUtils.verifyToken(token); //3、如果token失效,返回状态码401,拦截 if(!verifyToken) { response.setStatus(401); return false; } //4、如果token正常可用,放行 //解析token,获取id和手机号码, Claims claims = JwtUtils.getClaims(token); String mobile = (String) claims.get("mobile"); Integer id = (Integer) claims.get("id"); //构造User对象,存入Threadlocal User user = new User(); user.setId(Long.valueOf(id)); user.setMobile(mobile); UserHolder.set(user); return true; } //清空 解决ThreadLocal中数据越存越多导致内存溢出问题 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserHolder.remove(); } } 注册拦截器

拦截器需要注册到MVC容器中

/** * @author Administrator */ @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new TokenInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/user/login", "/user/loginVerification"); } } ThreadLocal工具类

定义ThreadLocal工具类,仅需要调用set方法即可将数据存入ThreadLocal中

package com.i.server.interceptor; import com.i.model.domain.User; /** * @author Administrator */ public class UserHolder { private static ThreadLocal tl = new ThreadLocal(); /** * 保存数据到线程 */ public static void set(User user) { tl.set(user); } /** * 获取线程中的用户信息 */ public static User get() { return tl.get(); } /** * 从当前线程,获取用户对象的id */ public static Long getUserId() { if (tl.get() == null) { return null; } return tl.get().getId(); } /** * 从当前线程,获取用户对象的手机号码 */ public static String getMobile() { if (tl.get() == null) { return null; } return tl.get().getMobile(); } /** * 移除线程中数据 */ public static void remove() { tl.remove(); } } 修改控制器方法

修改控制器方法, 所有需要用到userId都可以直接从线程中获取Long userId = UserHolder.getUserId();

@PostMapping(path = "/loginReginfo") public ResponseEntity loginReginfo(@RequestBody UserInfo userInfo) { //1. 校验token Long userId = UserHolder.getUserId(); //2. 保存用户信息 userInfo.setId(userId); userInfoService.save(userInfo); //3. 返回数据 return ResponseEntity.ok(null); }

 

 

统一异常处理

软件开发过程中,不可避免的是需要处理各种异常,常见的形式就是逐层向上抛出,web层进行处理。使用try {...} catch {...}很方便就能对异常做到业务处理

冗余代码多,影响代码可读性

异常处理和业务代码耦合

 SpringMVC提供了一套解决全局异常的处理方案,可以在代码无侵入的前提下完成异常处理。遵循逐层抛出,异常处理器统一处理的思路

(面向切面编程 aop)

 

 

项目中可能存在不可预知的各种异常,如:空指针,数组越界等。针对这类异常,可以直接在异常处理器中统一处理;

还有一类是可预知的错误,如图片不合法,验证码错误等等。这类错误也可以理解为业务异常,可以通过自定义异常类来处理;

业务异常对象

需求:自定义统一异常处理器,完成异常统一处理

 1定义异常处理类ExceptionAdvice

 2 编写方法,构造异常错误信息

 3 通过@ControllerAdvice和@ExceptionHandler配置

为了方便操作,将一些常见的业务错误封装到ErrorResult对象中

@Data @NoArgsConstructor @AllArgsConstructor @Builder public class ErrorResult { private String errCode = "999999"; private String errMessage; public static ErrorResult error() { return ErrorResult.builder().errCode("999999").errMessage("系统异常稍后再试").build(); } public static ErrorResult fail() { return ErrorResult.builder().errCode("000001").errMessage("发送验证码失败").build(); } public static ErrorResult loginError() { return ErrorResult.builder().errCode("000002").errMessage("验证码失效").build(); } public static ErrorResult faceError() { return ErrorResult.builder().errCode("000003").errMessage("图片非人像,请重新上传!").build(); } public static ErrorResult mobileError() { return ErrorResult.builder().errCode("000004").errMessage("手机号码已注册").build(); } public static ErrorResult contentError() { return ErrorResult.builder().errCode("000005").errMessage("动态内容为空").build(); } public static ErrorResult likeError() { return ErrorResult.builder().errCode("000006").errMessage("用户已点赞").build(); } public static ErrorResult disLikeError() { return ErrorResult.builder().errCode("000007").errMessage("用户未点赞").build(); } public static ErrorResult loveError() { return ErrorResult.builder().errCode("000008").errMessage("用户已喜欢").build(); } public static ErrorResult disloveError() { return ErrorResult.builder().errCode("000009").errMessage("用户未喜欢").build(); } } 业务异常类

自定义业务异常类,针对业务错误之间抛出业务异常即可

/** * 自定义异常类 */ @Data public class BusinessException extends RuntimeException { private ErrorResult errorResult; public BusinessException(ErrorResult errorResult) { super(errorResult.getErrMessage()); this.errorResult = errorResult; } } 异常处理器 /** * 自定义统一异常处理 * 1、通过注解,声明异常处理类 * 2、编写方法,在方法内部处理异常,构造响应数据 * 3、方法上编写注解,指定此方法可以处理的异常类型 */ @ControllerAdvice public class ExceptionAdvice { //处理业务异常 @ExceptionHandler(BusinessException.class) public ResponseEntity handlerException(BusinessException be) { be.printStackTrace(); ErrorResult errorResult = be.getErrorResult(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResult); } //处理不可预知的异常 @ExceptionHandler(Exception.class) public ResponseEntity handlerException1(Exception be) { be.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ErrorResult.error()); } }

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有