# 1. 使用自定义参数注解获取 token 中User数据

## 使用背景

在springboot项目开发中需要从token中获取用户信息时通常的方式要经历几个步骤

1. 拦截器中截获token
2. TokenUtil工具类解析token中的用户信息
3. 把解析结果存入到成员变量中
4. controller中通过TokenUtil工具类提供的静态方法获取用户信息

下面是过程示例代码

```java
/*--------1.拦截器中获取---------*/
String token =request.getHeader("token")

/*--------2.解析---------*/
//如果没过期且有效
if(!TokenUtil.isExpire(token)){
    //解析token把结果存入成员变量
    TokenUtil.decode(token);
}

/*--------3.controller中获取---------*/
User currentUser=TokenUtil.getUser();
```

看上去也没什么复杂指处,但是如果在每个Controller中都加上一句 `User currentUser=TokenUtil.getUser();`感觉有些多余(潜意识知道肯定有更简洁的方法能减少这里所写代码)

下面介绍一种使用自定义参数注解的方法简化获取结果

## 最后预期达到的效果

```java
@{RequestMethod}Mapping(value="path")
public Object methodName(@CurrentUser User user){
    //...code
}
```

## 正文开始

### 1. 拦截器中的代码(GlobalInterceptor.java)

```java
public class GlobalInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token=request.getHeader("token");
        //判断路径需要拦截
        //....code

        //如果token有效
        if(!TokenUtil.isExpire(token)){
            User user = TokenUtil.getUser(token);
            //我们将解析的用户结果先放入session中
            request.getSession().setAttribut("currentUser",user);
        }

        return true;
    }
}
```

### 2. 注解类 (CurrentUser.java)

```java
@Target({ElementType.PARAMETER})//Annotation所修饰的对象范围:方法参数
@Retention(RetentionPolicy.RUNTIME)//Annotation被保留时间:运行时保留(有效)
@Documented//标记注解:java工具文档化
public @interface CurrentUser {

}
```

### 3. CurrentUser注解实现类(CurrentUserHandlerMethodArgReslover.java)

```java
public class CurrentUserHandlerMethodArgReslover implements HandlerMethodArgumentResolver {

    /**
    * 判断是否支持使用@CurrentUser注解的参数
    */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        //如果该参数注解有@CurrentUser且参数类型是User
        return methodParameter.getParameterAnnotation(CurrentUser.class) != null &&methodParameter.getParameterType() == User.class;
    }

    /**
    * 注入参数值
    */
    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        //取得HttpServletRequest
        HttpServletRequest request= (HttpServletRequest) nativeWebRequest.getNativeRequest();
        //取出session中的User
        return (User)request.getSession().getAttribute("currentUser");
    }
}
```

### 4. 在SpringBoot启动类中注册 注解的实现类与拦截器(ServerApplication.java)

```java
@SpringBootApplication
public class ServerApplication extends WebMvcConfigurationSupport {

    /**
     * 启动入口
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class,args);
    }

    @Override
    protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers){
        //注册@CurrentUser注解的实现类
        argumentResolvers.add(new CurrentUserHandlerMethodArgReslover());
    }

    /**
    * 注册拦截器
    * @param registry
    */
    @Override
    protected void addInterceptors(InterceptorRegistry registry {
        //注册拦截器
        registry.addInterceptor(new GlobalInterceptor().addPathPatterns("/*/api/**");
        registry.addInterceptor(new TestInterceptor().addPathPatterns("/*/api/test/**");
        super.addInterceptors(registry);
    }
}
```

### 5. 在Controller中使用

```java
@GetMapping(value="/demo/api/testget")
public Object getTest(@CurrentUser User currentUser){
    System.out.println(currentUser);
    return currentUser;
}
```

到此就实现了预期的结果,回头看发现虽然多写了不少代码,但是在用的时候还是更加简洁明了,美丽大方(给自己比个❤)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sugar-at.gitbook.io/blog-article/springboot/p1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
