侧边栏壁纸
博主头像
ZHD的小窝博主等级

行动起来,活在当下

  • 累计撰写 79 篇文章
  • 累计创建 53 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

Springboot通过接口注解获取参数内容

江南的风
2024-11-14 / 0 评论 / 0 点赞 / 20 阅读 / 4727 字 / 正在检测是否收录...

场景:当我们需要获取参数内容并且把获取到的内容复制给注解value,比如我们通过参数ID进行鉴权时,

/**
 * 查询数据
 *
 * @param req 参数
 * @return 返回结果
 */
@RequiredPermission(pid = "{#req.id}")
@PostMapping("/data")
public GlobalResponse getData(@RequestBody BaseParamReq req) {
  // Bussiness
}

@Data
public class BaseParamReq implements Serializable {
    private Integer id;
    private Map<String, Object> param;
}

我们想通过SpEL表达式获取参数内容并且赋值给注解的pid,我们应该怎么处理?

我们可以写一个AOP进行接口拦截,通过自定义ExpressionEvaluator进行表达式获取值

@Component
@Slf4j
@Aspect
public class PermissionAspect {

    @Resource
    private ISupplierApiService supplierApiService;

    private ExpressionEvaluator<String> evaluator = new ExpressionEvaluator<>();

    /**
     * 配置织入点
     */
    @Pointcut("@annotation(RequiredPermission)")
    public void permissionPointCut() {
    }

    /**
     * 执行方法前执行
     */
    @Before(value = "permissionPointCut()")
    public void beforeMethodExecution(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method == null) {
            return;
        }
        RequiredPermission annotation = method.getAnnotation(RequiredPermission.class);
        EvaluationContext evaluationContext = evaluator.createEvaluationContext(joinPoint.getTarget(), joinPoint.getTarget().getClass(), ((MethodSignature) joinPoint.getSignature()).getMethod(), joinPoint.getArgs());
        AnnotatedElementKey methodKey = new AnnotatedElementKey(((MethodSignature) joinPoint.getSignature()).getMethod(), joinPoint.getTarget().getClass());
        String pid = evaluator.condition(annotation.pid(), methodKey, evaluationContext, String.class);
        if (StringUtils.isBlank(pid)) {
            return;
        }
        // 通过pid镜像权限校验...
        
    }
}

ExpressionEvaluator


public class ExpressionEvaluator<T> extends CachedExpressionEvaluator {
    private final ParameterNameDiscoverer paramNameDiscoverer = new DefaultParameterNameDiscoverer();
    private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<>(64);
    private final Map<AnnotatedElementKey, Method> targetMethodCache = new ConcurrentHashMap<>(64);

    public EvaluationContext createEvaluationContext(Object object, Class<?> targetClass, Method method,
        Object[] args) {
        Method targetMethod = getTargetMethod(targetClass, method);
        ExpressionRootObject root = new ExpressionRootObject(object, args);
        return new MethodBasedEvaluationContext(root, targetMethod, args, this.paramNameDiscoverer);
    }

    public T condition(String conditionExpression, AnnotatedElementKey elementKey, EvaluationContext evalContext,
        Class<T> clazz) {
        return getExpression(this.conditionCache, elementKey, conditionExpression).getValue(evalContext, clazz);
    }

    private Method getTargetMethod(Class<?> targetClass, Method method) {
        AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass);
        Method targetMethod = this.targetMethodCache.get(methodKey);
        if (targetMethod == null) {
            targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
            if (targetMethod == null) {
                targetMethod = method;
            }
            this.targetMethodCache.put(methodKey, targetMethod);
        }
        return targetMethod;
    }
}

核心就是这个方法

public EvaluationContext createEvaluationContext(Object object, Class<?> targetClass, Method method,
        Object[] args) {
        Method targetMethod = getTargetMethod(targetClass, method);
        ExpressionRootObject root = new ExpressionRootObject(object, args);
        return new MethodBasedEvaluationContext(root, targetMethod, args, this.paramNameDiscoverer);
    }

我们通过这个方法把参数args赋值给EvaluationContext返回

0

评论区