拦截器HandlerInterceptor+方法参数解析器HandlerMethodArgumentResolver用于统一获取当前登录用户信息
文章目录
- 前言
- 一、拦截器+方法参数解析器 是什么?
- 二、具体实现步骤
- 1.自定义权限拦截器LoginInterceptor拦截所有request请求,并将token解析为currentUser,最终放到request中。
- 2.自定义参数注解@User,添加至controller的方法参数currentUser之上。
- 3.自定义方法参数解析器CurrentUserHandlerMethodArgReslover,取出request中的currentUser,并赋值给添加了@User注解的参数currentUser。
- 4.配置MVC
- 三、总结
前言
需求:很多Controller方法,刚进来要先获取当前登录用户的信息,以便做后续的用户相关操作。
准备工作:前端每次请求都传token,后端封装一方法redisUtil.get(token),根据token解析得到currentUser。
这是一个常见的业务需求,为实现这个需求有以下三种解决方案:
一、最原始直接的方式:即在每个Controller开始,先调用redisUtil.get(token),获取用户的信息,不够优雅。
二、AOP:AOP可以解决很多切面类问题,思路同Spring AOP来自定义注解实现审计或日志记录(完整代码),将currentUser放到request里;比起拦截器稍重。
三、拦截器+方法参数解析器:使用mvc拦截器HandlerInterceptor+方法参数解析器HandlerMethodArgumentResolver最合适。
本篇博客讲解第三种的具体实现步骤~
一、拦截器+方法参数解析器 是什么?
SpringMVC提供了mvc拦截器HandlerInterceptor,包含以下3个方法:
①:preHandle
②:postHandle
③:afterCompletion
HandlerInterceptor经常被用来解决拦截事件,如用户鉴权等。
另外,Spring也向我们提供了多种解析器Resolver,如用来统一处理异常HandlerExceptionResolver,以及今天的主角HandlerMethodArgumentResolver。HandlerMethodArgumentResolver是用来处理方法参数的解析器,包含以下2个方法:
①:supportsParameter(满足某种要求,返回true,方可进入resolveArgument做参数处理)
②:resolveArgument
二、具体实现步骤
1.自定义权限拦截器LoginInterceptor拦截所有request请求,并将token解析为currentUser,最终放到request中。
自定义权限拦截器LoginInterceptor,需实现HandlerInterceptor。在preHandle中调用redisUtil.get(token),获取到当前用户,最后塞进request中,如下:
public class LoginInterceptor implements HandlerInterceptor {//@Autowired//private ShoConfigService shoConfigService;@Autowiredprivate RedisUtil redisUtil;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {System.out.println(request.getRequestURL());String tokenHeader = request.getHeader("token");if (StringUtils.isBlank(tokenHeader)) {throw new AppException("openid为空", ResultCode.PERMISSION_NO_ACCESS.getCode());}CurrentUser currentUser = (CurrentUser) redisUtil.get(tokenHeader);if (currentUser == null) {throw new AppException("openid为空", ResultCode.PERMISSION_NO_ACCESS.getCode());}request.getSession().setAttribute("currentUser", currentUser);
// 调用接口的时候查询系统维护的状态/*JsonResult result = shoConfigService.selStatue();if (result.getData().equals(0)) {throw new AppException("系统维护中", ResultCode.SYSTEM_MAINTENANCE.getCode());}*/return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
2.自定义参数注解@User,添加至controller的方法参数currentUser之上。
自定义方法参数上使用的注解@User,代表被它注解过的参数的值都需要由方法参数解析器CurrentUserHandlerMethodArgReslover来“注入”,如下:
package com.boduo.config.aop;import java.lang.annotation.*;/*** @Description:@User自定义注解* @Author nanyi* @Date 2021/4/16 20:03**/
@Target({ElementType.PARAMETER})//Annotation所修饰的对象范围:方法参数
@Retention(RetentionPolicy.RUNTIME)//Annotation被保留时间:运行时保留(有效)
@Documented//标记注解:java工具文档化
public @interface User {}
给各Controller类中方法的参数添加此注解,案例如下:
/*** @Description:对应品牌的通知* @Author nanyi* @Date 2021/4/16 10:28**/
@RestController
@RequestMapping("/api/shop/notify")
@Api(tags = "首页")
@ApiSort(1)
public class NotifyController {@AutowiredNotifyService notifyService;/*** @Description:未查看通知列表*/@GetMapping("/list")@ApiOperation("通知列表")@ApiOperationSupport(order = 11)public JsonResult<NotifyDTO> noticesAll(@ApiIgnore @User CurrentUser currentUser) {if (currentUser.getIsVisitory()) {// 如果是游客,根据Openid和品牌id进行查询return notifyService.selNotifyByBrandId(currentUser.getUsername(), currentUser.getBrand().getBrandId());}
// 如果是VIP,根据AI系统里面的用户编号和品牌id进行查询return notifyService.selNotifyByBrandId(currentUser.getUsername(), currentUser.getBrand().getBrandId());}}
3.自定义方法参数解析器CurrentUserHandlerMethodArgReslover,取出request中的currentUser,并赋值给添加了@User注解的参数currentUser。
自定义方法参数解析器CurrentUserHandlerMethodArgReslover,需实现HandlerMethodArgumentResolver。
package com.boduo.config.aop;import com.boduo.entity.CurrentUser;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;import javax.servlet.http.HttpServletRequest;/*** @Description:@User 注解解析器* @Author nanyi* @Date 2021/4/16 10:28**/
public class CurrentUserHandlerMethodArgReslover implements HandlerMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter methodParameter) {//如果该参数注解有@User且参数类型是Userreturn methodParameter.getParameterAnnotation(User.class) != null;}@Overridepublic Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {//取得HttpServletRequestHttpServletRequest request= (HttpServletRequest) nativeWebRequest.getNativeRequest();//取出session中的Userreturn (CurrentUser)request.getSession().getAttribute("currentUser");}
}
拦截器定义好以后,在SpringMVC项目中,需要去SpringMVC的配置文件springmvc.xml添加该拦截器;但是在SpringBoot中,省去了很多配置文件,取而代之的是被注解@Configuration标识的配置类,SpringMVC配置文件对应的配置类需继承WebMvcConfigurer。同理,解析器定义好以后,也需被添加到SpringMVC的配置文件或配置类中。最后,额外的一步,配置mvc。
4.配置MVC
package com.boduo.config.aop;import com.boduo.config.properties.MyProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;/*** @Description:@User 注解解析器* @Author nanyi* @Date 2021/4/16 10:40**/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@AutowiredMyProperties myProperties;@Beanpublic LoginInterceptor LoginInterceptor() {return new LoginInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {/***此处拦截路径(/**)* 注意两个**。一个*号只拦截一级路径下,两个*号拦截所有* 将LoginInterceptor()给添加进来*/registry.addInterceptor(LoginInterceptor()).addPathPatterns("/**").excludePathPatterns(myProperties.getIgnoreUrls());}@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {//注册@User注解的实现类argumentResolvers.add(new CurrentUserHandlerMethodArgReslover());}public void addResourceHandlers(ResourceHandlerRegistry registry) {//将templates目录下的CSS、JS文件映射为静态资源,防止Spring把这些资源识别成thymeleaf模版registry.addResourceHandler("/static/**.js").addResourceLocations("classpath:/static/");
}
三、总结
成为一个小胖子,没事摸摸小肚子~
拦截器HandlerInterceptor+方法参数解析器HandlerMethodArgumentResolver用于统一获取当前登录用户信息相关推荐
- (十六)ATP应用测试平台——java应用中的过滤器Filter、拦截器Interceptor、参数解析器Resolver、Aop切面,你会了吗?
前言 过滤器Filter.拦截器Interceptor.参数解析器Resolver.Aop切面是我们应用开发中经常使用到的技术,到底该如何使用这些web附属功能, 本小节我们就分别介绍一下其各自的用法 ...
- Linux下用于查看系统当前登录用户信息的4种方法
作为系统管理员,你可能经常会(在某个时候)需要查看系统中有哪些用户正在活动.有些时候,你甚至需要知道他(她)们正在做什么.本文为我们总结了4种查看系统用户信息(通过编号(ID))的方法. 1. 使用w ...
- Linux查看系统中用户信息,Linux下用于查看系统当前登录用户信息的4种方法
作为系统管理员,你可能经常会(在某个时候)需要查看系统中有哪些用户正在活动.有些时候,你甚至需要知道他(她)们正在做什么.本文为我们总结了4种查看系统用户信息(通过编号(ID))的方法. 1. 使用w ...
- CentOS下用于查看系统当前登录用户信息的4种方法
1. 使用w命令查看登录用户正在使用的进程信息 w命令用于显示已经登录系统的用户的名称,以及他们正在做的事.该命令所使用的信息来源于/var/run/utmp文件.w命令输出的信息包括: 用户名称 用 ...
- wordpress获取当前登录用户信息的方法
1). get_currentuserinfo(); 此函数将当前登录用户信息赋给全局变量$current_user以及一些单独的用户信息全局变量例如$display_name, $user_emai ...
- Spring MVC自定义类型转换器Converter、参数解析器HandlerMethodArgumentResolver
文章目录 一.前言 二.类型转换器Converter 1.自定义类型转换器 三.参数解析器 1.自定义分页参数解析器 2.自定义注解参数解析器 一.前言 Spring MVC源码分析相关文章已出: S ...
- SpringMVC 参数解析器
一.问题 springMVC对于下面这种接口,参数是怎么解析的: @GetMapping("/hello/{id}") public void hello3(@PathVariab ...
- Spring参数解析器
文章目录 请求映射处理适配器:RequestMappingHandlerAdapter 参数解析器:HandlerMethodArgumentResolver 参数处理相关注解 1.@PathVari ...
- springmvc自定义参数解析器/类型转换器
概述 有些时候我们需要对GET请求的入参做自定义的处理,比较常见的就是字符串反序列化时间类型了,常用的像@DateTimeFormat注解,但是这需要在每个入参的属性上都加上这个注解,比较费手,那么我 ...
最新文章
- xgboost lightgbm catboost 多分类 多标签
- Linux下的kill函数的用法
- 各个级别镜像之间的跳转模型
- input file 上传文件格式限制
- line和spline_探索适用于Apache Spark的Spline Data Tracker和可视化工具(第1部分)
- Cannot merge new index 66395 into a non-jumbo instruction!,uses or overrides a deprecated API.
- 为什么相关性不等于因果性?终于有人讲明白了
- 12C 新特性 | 标量子查询自动转换
- 彪悍语录系列(摘于网络)
- javascript 未来新方法的介绍
- LL1分析构造法_行测技巧:比较构造法两步轻松解决方程题
- Android开发遇到的问题
- OSEK Os的任务调度
- Android Studio 怎么连接MUMU模拟器并永久使用
- 【小程序源码】经典语录大全多种分类语录
- EXCEL如何真正彻底去掉小数点后的数字
- 小游戏制作QQ宠物系列1 ---- 吹泡泡
- python计算给定的日期的星期_Python计算给定日期的周内的某一天
- Python爬取《创造营2020》小姐姐数据用腾讯云人脸识别做颜值评分
- 了解爬虫的工作流程及相关概念
热门文章
- win7安装python计算机丢失api-ms-win_无法启动此程序因为计算机中丢失api-ms-win
- 因式分解英语计算机,网易正式发布有道超级计算器 免费无广告离线高级运算...
- Visio无法复制文本框,内部错误1021
- 嘉弘恒信:拼多多新手期红包要怎么使用
- c语言中数组的变量j是什么,C语言中x[i][j]的意思是?
- IDEA中报错“Cannot resolve symple”解决办法
- java jit aot_对比JIT和AOT,各自有什么优点与缺点?
- swing的JTextField的介绍及其使用方法
- SAP创建客户主数据事务码和透明表
- 安装一个好用的Ubuntu桌面