场景:当我们需要获取参数内容并且把获取到的内容复制给注解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返回
评论区