要实现的是 动态入参,也就是在使用自定义注解的时候 ,写入的是字符串,并非一个传入参数值
1、方法是自定义注解传参
@DataAuth(spaceName = "#space")
@PostMapping("/list")
@ApiOperation("卡片展示列表(图谱详情)")
public R<List<DetailSpace>> detailSpace(@RequestBody GraphShowAttribute graphShowAttribute, @PathVariable String space) {
return R.data(spaceService.detailSpace(graphShowAttribute));
}
@DataAuth(spaceName = "#space")
这里的spaceName 并非一个固定字符串,而是一个路径参数,每次接口参数变化,我都想将这个参数传入自定义的注解中用以校验;
如果是单个参数,@DataAuth(spaceName = "#space")
如果是对象参数,@DataAuth(spaceName = "#graphShowAttribute.space")
自定义注解如下:
/**
* @ClassName: DataAuth
* 数据权限校验切面日志
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataAuth {
String spaceName();
}
注解切面实现:
使用 SpelExpressionParser 和DefaultParameterNameDiscoverer 来动态获取参数
import cn.dev33.satoken.stp.StpUtil;
import com.hotemasoft.knowledge.manage.exception.GraphExecuteException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @ClassName: DataAuthAspect
* 数据权限切面实现
*/
@Aspect
@Component
@Slf4j
public class DataAuthAspect implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Pointcut("@annotation(com.hotemasoft.knowledge.manage.config.DataAuth)")
public void dataAuthMethod() {
}
@SneakyThrows
@Around(value = "dataAuthMethod()")
public Object around(ProceedingJoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
log.info("拦截的方法:{}", method);
DataAuth dataAuth = method.getAnnotation(DataAuth.class);
log.info("入参:{}", dataAuth.spaceName());
String value= generateKeyBySpEL(dataAuth.spaceName(), joinPoint);
log.info("解析入参:{}", value);
if (!StpUtil.getRoleList().contains(value)) {
throw new GraphExecuteException("无数据权限");
}
return joinPoint.proceed();
}
private SpelExpressionParser parserSpel = new SpelExpressionParser();
private DefaultParameterNameDiscoverer parameterNameDiscoverer= new DefaultParameterNameDiscoverer();
public String generateKeyBySpEL(String key, ProceedingJoinPoint pjp) {
Expression expression = parserSpel .parseExpression(key);
EvaluationContext context = new StandardEvaluationContext();
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Object[] args = pjp.getArgs();
String[] paramNames = parameterNameDiscoverer.getParameterNames(methodSignature.getMethod());
for(int i = 0 ; i < args.length ; i++) {
context.setVariable(paramNames[i], args[i]);
}
return expression.getValue(context).toString();
}
}