自定義注解 一般功能無非就是通過其實現(xiàn)一個統(tǒng)一的攔截功能,然后實現(xiàn)批量的一個統(tǒng)一操作;
例如: 日志打印; 權(quán)限校驗;參數(shù)校驗;業(yè)務校驗......................
那么大多數(shù)我們只需要通過獲取添加自定義注解方法上的參數(shù)共同部分,就能實現(xiàn)以上功能,而且一般不需要在自定義注解中增加入?yún)?br>
類似功能可以參考如下幾篇文章;其實寫的不錯,但是也對我產(chǎn)生了誤導;
https://blog.csdn.net/w253202712/article/details/83506962
http://www.javashuo.com/article/p-opimlduj-gx.html
https://www.freesion.com/article/5610369762/
我這里要實現(xiàn)的是 動態(tài)入?yún)?而文章中的示例都是相當于是傳入的寫死的字符串,也就是在使用自定義注解的時候 ,寫入的是字符串,并非一個傳入?yún)?shù)值

我想實現(xiàn)的如下:
@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 并非一個固定字符串,而是一個路徑參數(shù),每次接口參數(shù)變化,我都想將這個參數(shù)傳入自定義的注解中用以校驗;(那么這個時候有杠精說了, 我可以直接去通過 獲取方法上的參數(shù)獲取路徑參數(shù) space,是的也可以) 我這里想實現(xiàn)的更優(yōu)雅一丟丟,其次當方法上的參數(shù)順序,名稱發(fā)生變化,獲取改方法上的參數(shù)也會增加獲取難度,所以此種方式更簡單一些;
開干!!!!!!!!!!
如果是單個參數(shù),@DataAuth(spaceName = "#space")
如果是對象參數(shù),@DataAuth(spaceName = "#graphShowAttribute.space")
自定義注解如下:
/**
* @ClassName: DataAuth
* 數(shù)據(jù)權(quán)限校驗切面日志
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataAuth {
String spaceName();
}
注解切面實現(xiàn):
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
* 數(shù)據(jù)權(quán)限切面實現(xiàn)
*/
@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("入?yún)?{}", dataAuth.spaceName());
String value= generateKeyBySpEL(dataAuth.spaceName(), joinPoint);
log.info("解析入?yún)?{}", value);
if (!StpUtil.getRoleList().contains(value)) {
throw new GraphExecuteException("無數(shù)據(jù)權(quán)限");
}
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 方法就是在解析該參數(shù),從而獲取到它的值,這樣就能進行校驗了;
如果是一個寫死的普通字符串,那么在
log.info("入?yún)?{}", dataAuth.spaceName());
就已經(jīng)獲取到了;
搞了半天,終于搞定了!!!