自定义注解 一般功能无非就是通过其实现一个统一的拦截功能,然后实现批量的一个统一操作;
例如: 日志打印; 权限校验;参数校验;业务校验......................
那么大多数我们只需要通过获取添加自定义注解方法上的参数共同部分,就能实现以上功能,而且一般不需要在自定义注解中增加入参
类似功能可以参考如下几篇文章;其实写的不错,但是也对我产生了误导;
https://blog.csdn.net/w253202712/article/details/83506962
http://www.javashuo.com/article/p-opimlduj-gx.html
https://www.freesion.com/article/5610369762/
我这里要实现的是 动态入参,而文章中的示例都是相当于是传入的写死的字符串,也就是在使用自定义注解的时候 ,写入的是字符串,并非一个传入参数值
我想实现的如下:
@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 并非一个固定字符串,而是一个路径参数,每次接口参数变化,我都想将这个参数传入自定义的注解中用以校验;(那么这个时候有杠精说了, 我可以直接去通过 获取方法上的参数获取路径参数 space,是的也可以) 我这里想实现的更优雅一丢丢,其次当方法上的参数顺序,名称发生变化,获取改方法上的参数也会增加获取难度,所以此种方式更简单一些;
开干!!!!!!!!!!
如果是单个参数,@DataAuth(spaceName = "#space")
如果是对象参数,@DataAuth(spaceName = "#graphShowAttribute.space")
自定义注解如下:
/**
* @ClassName: DataAuth
* 数据权限校验切面日志
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataAuth {
String spaceName();
}
注解切面实现:
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();
}
}
其中 带# 的这种写法叫做spel表达式 @DataAuth(spaceName = "#space"),并非如此写就是好使的,这个是需要我们自己解析的,上述中 generateKeyBySpEL 方法就是在解析该参数,从而获取到它的值,这样就能进行校验了;
如果是一个写死的普通字符串,那么在
log.info("入参:{}", dataAuth.spaceName());
就已经获取到了;
搞了半天,终于搞定了!!!