Spring SourceCode SpringBoot Java Code

Spring使用注解注入token的值

Posted on 2021-05-02,4 min read
  • 在实际开发中,我们可能会需要使用到注解来给我们的方法注入一些参数值,比如从token中获取某些参数然后注入到controller中的方法中。但是由于SpringAOP无法支持对参数上的注解进行拦截所以我们需要使用其他的方法来实现。
  • Spring为我们提供了一个接口:AbstractNamedValueMethodArgumentResolver,这个接口是专门用于处理当前情况的,Spring中的很多常用注解也是通过继承这个类实现的。如:@CookieValue@PathVariable等。
  • 本文主要介绍如何通过继承这个类来实现相应的效果。

实现

代码

  • 定义一个注解,用于标识要获取的属性。
package cn.gloduck.gmall.token.annotation;

import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;


/**
 * 从token中获取属性
 *
 * @author Gloduck
 */
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface TokenAttribute {

    /**
     * 需要获取的属性值
     *
     * @return
     */
    String name();

    /**
     * token的分组
     *
     * @return
     */
    String group();

    /**
     * 当前的参数是否必须
     * @return
     */
    boolean required() default true;

}

  • 定义一个异常,用于抛出
package cn.gloduck.gmall.token.exception;

/**
 * 从token中获取属性失败抛出的异常
 * @author Gloduck
 */
public class TokenAttributeException extends RuntimeException {
    public TokenAttributeException(String message) {
        super(message);
    }
}
  • AbstractNamedValueMethodArgumentResolver的具体实现,具体获取逻辑在resolveName
package cn.gloduck.gmall.token;

import cn.gloduck.gmall.constant.TokenConstant;
import cn.gloduck.gmall.token.annotation.TokenAttribute;
import cn.gloduck.gmall.service.TokenService;
import cn.gloduck.gmall.token.exception.TokenAttributeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver;

import javax.servlet.ServletException;
import java.util.Map;


/**
 * token扩展,使得可以直接通过@TokenAttribute注解获取token中的值
 * @author Gloduck
 */
@Slf4j
public class TokenAttributeMethodArgumentResolver  extends AbstractNamedValueMethodArgumentResolver {
    public TokenAttributeMethodArgumentResolver(TokenService tokenService) {
        log.info("注入:{}到:{}",tokenService.getClass().getName(), this.getClass().getName());
        this.tokenService = tokenService;
    }

    private TokenService tokenService;

    /**
     * 当前处理器支持@TokenAttribute注解
     * @param methodParameter
     * @return
     */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotation(TokenAttribute.class);
    }


    /**
     * 封装NamedValueInfo,如果获取不到的话会从defaultValue中获取,所以我们这里设置defaultValue为null
     * @param methodParameter
     * @return
     */
    @Override
    protected NamedValueInfo createNamedValueInfo(MethodParameter methodParameter) {
        TokenAttribute annotation = methodParameter.getParameterAnnotation(TokenAttribute.class);
        Assert.state(annotation != null, "No RequestAttribute annotation");
        return new NamedValueInfo(annotation.name(), annotation.required(), null);
    }

    /**
     * 具体的处理逻辑
     * @param s
     * @param methodParameter
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    protected Object resolveName(String s, MethodParameter methodParameter, NativeWebRequest request) throws Exception {
        String token = request.getHeader(TokenConstant.TOKEN_HEADER);
        if(token == null){
            // 获取token失败
            return null;
        }
        TokenAttribute tokenAttribute = methodParameter.getParameterAnnotation(TokenAttribute.class);
        String group = tokenAttribute.group();
        String name = tokenAttribute.name();
        Map<String, String> map = tokenService.verifyAndGetPayloadMap(group, token);
        if(map == null){
            // token校验失败
            return null;
        }
        String value = map.get(name);
        return value;
    }

    /**
     * 当获取不到时候的处理
     * @param name
     * @param parameter
     * @throws ServletException
     */
    @Override
    protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException {
        throw new TokenAttributeException(String.format("token中获取参数:%s失败",name));
    }

}

配置

  • 自定义的AbstractNamedValueMethodArgumentResolver需要注册,所以我们需要重写WebMvcConfigurationSupport中的addArgumentResolvers方法

  • 
    /**
     * @author Gloduck
     */
    @Configuration
    public class GlobalConfiguration extends WebMvcConfigurationSupport {
        @Autowired
        private TokenService tokenService;
        @Override
        protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
            // 使得能直接通过注解从token中获取参数
            argumentResolvers.add(new TokenAttributeMethodArgumentResolver(tokenService));
        }
    }
    
    

下一篇: Java中的观察者模式和观察订阅模式→

loading...