这里记录回顾一些知识,不然就快忘记啦。
- 环境:SpringBoot 2.0.4.RELEASE
- 需求:很多Controller方法,刚进来要先获取当前登录用户的信息,以便做后续的用户相关操作。
- 准备工作:前端每次请求都传token,后端封装一方法tokenUtils.getUserByToken(token),根据token解析得到currentUserInfo。
这是一个常见的业务需求,为实现这个需求,有以下几种解决方案:
一、最原始直接
即,每个Controller开始,先调用tokenUtils.getUserByToken(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. 自定义权限拦截器AuthenticationInterceptor拦截所有request请求,并将token解析为currentUser,最终放到request中;
2. 自定义参数注解@CurrentUser,添加至controller的方法参数user之上;
3. 自定义方法参数解析器CurrentUserMethodArgumentResolver,取出request中的user,并赋值给添加了@CurrentUser注解的参数user。
使用方式
要使用 HandlerMethodArgumentResolver
,需要遵循以下步骤:
- 创建一个自定义的
HandlerMethodArgumentResolver
实现类。 - 在该类中实现
supportsParameter()
方法和resolveArgument()
方法。 - 在 Spring Boot 应用程序中注册该类。
创建自定义的 HandlerMethodArgumentResolver 实现类
为了将 HTTP 请求参数转换为 Java 对象,我们需要创建一个自定义的 HandlerMethodArgumentResolver
实现类。在这个类中,我们需要实现 supportsParameter()
方法和 resolveArgument()
方法。
supportsParameter() 方法
在 supportsParameter()
方法中,我们需要检查方法参数是否与我们要转换的 Java 类型相同。如果是,返回 true
,否则返回 false
。
resolveArgument() 方法
在 resolveArgument()
方法中,我们需要将 HTTP 请求参数转换为 Java 对象。为此,我们可以使用 NativeWebRequest
对象来获取请求参数,然后将其转换为 Java 对象。
注册自定义的 HandlerMethodArgumentResolver 实现类
要在 Spring Boot 应用程序中使用自定义的 HandlerMethodArgumentResolver
实现类,我们需要将其注册到应用程序上下文中。为此,我们可以创建一个 @Configuration
类,并实现 WebMvcConfigurer
接口。在这个类中,我们需要重写 addArgumentResolvers()
方法,并将自定义的 HandlerMethodArgumentResolver
实现类添加到参数解析器列表中。
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new CustomHandlerMethodArgumentResolver());
}
}
3.1 自定义权限拦截器
自定义权限拦截器AuthenticationInterceptor,需实现HandlerInterceptor。在preHandle中调用tokenUtils.getUserByToken(token),获取到当前用户,最后塞进request中,如下:
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import edp.core.utils.TokenUtils; import edp.davinci.core.common.Constants; import edp.davinci.model.User; public class AuthenticationInterceptor implements HandlerIntercept